/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2018 Alexander Barton (alex@barton.de) and Contributors.
*
* 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
* Login and logout
*/
-#include "imp.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
+#include <time.h>
#include "conn-func.h"
-#include "class.h"
#include "conf.h"
#include "channel.h"
#include "log.h"
#include "messages.h"
#include "parse.h"
#include "irc.h"
-#include "irc-info.h"
#include "irc-macros.h"
#include "irc-write.h"
-#include "exp.h"
#include "irc-login.h"
-static void Kill_Nick PARAMS((char *Nick, char *Reason));
static void Change_Nick PARAMS((CLIENT * Origin, CLIENT * Target, char *NewNick,
bool InformClient));
/* Return an error if this is not a local client */
if (Client_Conn(Client) <= NONE)
- return IRC_WriteStrClient(Client, ERR_UNKNOWNCOMMAND_MSG,
+ return IRC_WriteErrClient(Client, ERR_UNKNOWNCOMMAND_MSG,
Client_ID(Client), Req->command);
if (Client_Type(Client) == CLIENT_UNKNOWN && Req->argc == 1) {
} else if (Client_Type(Client) == CLIENT_UNKNOWN ||
Client_Type(Client) == CLIENT_UNKNOWNSERVER) {
/* Unregistered connection, but wrong number of arguments: */
- IRC_SetPenalty(Client, 2);
- return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+ return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
Client_ID(Client), Req->command);
} else {
/* Registered connection, PASS command is not allowed! */
- IRC_SetPenalty(Client, 2);
- return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
+ return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
Client_ID(Client));
}
/* Protocol version */
if (Req->argc >= 2 && strlen(Req->argv[1]) >= 4) {
- int c2, c4;
+ char c2, c4;
c2 = Req->argv[1][2];
c4 = Req->argv[1][4];
IRC_NICK( CLIENT *Client, REQUEST *Req )
{
CLIENT *intr_c, *target, *c;
+ CHANNEL *chan;
char *nick, *user, *hostname, *modes, *info;
int token, hops;
/* Search "target" client */
if (Client_Type(Client) == CLIENT_SERVER) {
+ _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
target = Client_Search(Req->prefix);
if (!target)
- return IRC_WriteStrClient( Client,
- ERR_NOSUCHNICK_MSG,
- Client_ID( Client ),
- Req->argv[0] );
+ return IRC_WriteErrClient(Client,
+ ERR_NOSUCHNICK_MSG,
+ Client_ID(Client),
+ Req->argv[0]);
} else {
/* Is this a restricted client? */
- if (Client_HasMode(Client, 'r')) {
- IRC_SetPenalty(Client, 2);
- return IRC_WriteStrClient( Client,
- ERR_RESTRICTED_MSG,
- Client_ID( Client ));
- }
+ if (Client_HasMode(Client, 'r'))
+ return IRC_WriteErrClient(Client,
+ ERR_RESTRICTED_MSG,
+ Client_ID(Client));
target = Client;
}
#ifndef STRICT_RFC
if (Conf_AuthPing) {
+#ifdef HAVE_ARC4RANDOM
+ Conn_SetAuthPing(Client_Conn(Client), arc4random());
+#else
Conn_SetAuthPing(Client_Conn(Client), rand());
- IRC_WriteStrClient(Client, "PING :%ld",
+#endif
+ Conn_WriteStr(Client_Conn(Client), "PING :%ld",
Conn_GetAuthPing(Client_Conn(Client)));
LogDebug("Connection %d: sent AUTH PING %ld ...",
Client_Conn(Client),
Client_SetType( Client, CLIENT_GOTNICK );
} else {
/* Nickname change */
+
+ /* Check that the user isn't on any channels set +N */
+ if(Client_Type(Client) == CLIENT_USER &&
+ !Client_HasMode(Client, 'o')) {
+ chan = Channel_First();
+ while (chan) {
+ if(Channel_HasMode(chan, 'N') &&
+ Channel_IsMemberOf(chan, Client))
+ return IRC_WriteErrClient(Client,
+ ERR_NONICKCHANGE_MSG,
+ Client_ID(Client),
+ Channel_Name(chan));
+ chan = Channel_Next(chan);
+ }
+ }
+
Change_Nick(Client, target, Req->argv[0],
Client_Type(Client) == CLIENT_USER ? true : false);
IRC_SetPenalty(target, 2);
/* Bad number of parameters? */
if (Req->argc != 2 && Req->argc != 7)
- return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+ return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
Client_ID(Client), Req->command);
if (Req->argc >= 7) {
* the new nick is already present on this server:
* the new and the old one have to be disconnected now.
*/
- Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
- Kill_Nick( Req->argv[0], "Nick collision" );
- return CONNECTED;
+ 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");
}
/* Find the Server this client is connected to */
intr_c = Client_GetFromToken(Client, token);
if (!intr_c) {
- Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
- Kill_Nick( Req->argv[0], "Unknown server" );
- return CONNECTED;
+ 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");
}
c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname,
Log(LOG_ALERT,
"Can't create client structure! (on connection %d)",
Client_Conn(Client));
- Kill_Nick(Req->argv[0], "Server error");
- return CONNECTED;
+ return IRC_KillClient(Client, NULL, Req->argv[0],
+ "Server error");
}
/* RFC 2813: client is now fully registered, inform all the
return CONNECTED;
}
else
- return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
+ return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
Client_ID(Client));
} /* IRC_NICK */
assert(Client != NULL);
assert(Req != NULL);
- _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 2)
+ _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
/* Search the originator */
from = Client_Search(Req->prefix);
/* Search the target */
target = Client_Search(Req->argv[0]);
- if (!target || Client_Type(target) != CLIENT_USER) {
- return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ if (!target || Client_Type(target) != CLIENT_USER)
+ return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
Client_ID(Client), Req->argv[0]);
- }
if (Client_Conn(target) <= NONE) {
/* We have to forward the message to the server handling
Client_Type(Client) == CLIENT_SERVICE) {
/* Server/service updating an user */
_IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4)
+ _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
c = Client_Search(Req->prefix);
if (!c)
- return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
Client_ID(Client),
Req->prefix);
return CONNECTED;
} else if (Client_Type(Client) == CLIENT_USER) {
/* Already registered connection */
- IRC_SetPenalty(Client, 2);
- return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
+ return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
Client_ID(Client));
} else {
/* Unexpected/invalid connection state? */
- IRC_SetPenalty(Client, 2);
- return IRC_WriteStrClient(Client, ERR_NOTREGISTERED_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOTREGISTERED_MSG,
Client_ID(Client));
}
} /* IRC_USER */
assert(Req != NULL);
if (Client_Type(Client) != CLIENT_GOTPASS &&
- Client_Type(Client) != CLIENT_SERVER) {
- IRC_SetPenalty(Client, 2);
- return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
+ Client_Type(Client) != CLIENT_SERVER)
+ return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG,
Client_ID(Client));
- }
-
- _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 6)
if (Client_Type(Client) != CLIENT_SERVER)
- return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
+ return IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
Client_ID(Client), Req->argv[0]);
nick = Req->argv[0];
c = Client_Search(nick);
if(c) {
/* Nickname collision: disconnect (KILL) both clients! */
- Log(LOG_ERR, "Server %s introduces already registered service \"%s\"!",
+ Log(LOG_ERR,
+ "Server %s introduces already registered service \"%s\"!",
Client_ID(Client), nick);
- Kill_Nick(nick, "Nick collision");
- return CONNECTED;
+ return IRC_KillClient(Client, NULL, nick, "Nick collision");
}
/* Get the server to which the service is connected */
intr_c = Client_GetFromToken(Client, token);
if (! intr_c) {
- Log(LOG_ERR, "Server %s introduces service \"%s\" on unknown server!?",
+ Log(LOG_ERR,
+ "Server %s introduces service \"%s\" on unknown server!?",
Client_ID(Client), nick);
- Kill_Nick(nick, "Unknown server");
- return CONNECTED;
+ return IRC_KillClient(Client, NULL, nick, "Unknown server");
}
/* Get user and host name */
if (! c) {
/* Couldn't create client structure, so KILL the service to
* keep network status consistent ... */
- Log(LOG_ALERT, "Can't create client structure! (on connection %d)",
+ Log(LOG_ALERT,
+ "Can't create client structure! (on connection %d)",
Client_Conn(Client));
- Kill_Nick(nick, "Server error");
- return CONNECTED;
+ return IRC_KillClient(Client, NULL, nick, "Server error");
}
Client_Introduce(Client, c, CLIENT_SERVICE);
GLOBAL bool
IRC_WEBIRC(CLIENT *Client, REQUEST *Req)
{
- _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4)
-
if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0)
- return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG,
+ return IRC_WriteErrClient(Client, ERR_PASSWDMISMATCH_MSG,
Client_ID(Client));
LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s",
Client_SetUser(Client, Req->argv[1], true);
Client_SetOrigUser(Client, Req->argv[1]);
- Client_SetHostname(Client, Req->argv[2]);
+ if (Conf_DNS)
+ Client_SetHostname(Client, Req->argv[2]);
+ else
+ Client_SetHostname(Client, Req->argv[3]);
+ Client_SetIPAText(Client, Req->argv[3]);
+
return CONNECTED;
} /* IRC_WEBIRC */
IRC_QUIT( CLIENT *Client, REQUEST *Req )
{
CLIENT *target;
- char quitmsg[LINE_LEN];
+ char quitmsg[COMMAND_LEN];
assert(Client != NULL);
assert(Req != NULL);
- _IRC_ARGC_LE_OR_RETURN_(Client, Req, 1)
-
if (Req->argc == 1)
strlcpy(quitmsg, Req->argv[0], sizeof quitmsg);
if (Client_Type(Client) == CLIENT_SERVER) {
/* Server */
+ _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
+
target = Client_Search(Req->prefix);
if (!target) {
Log(LOG_WARNING,
assert(Req != NULL);
if (Req->argc < 1)
- return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG,
Client_ID(Client));
#ifdef STRICT_RFC
/* Don't ignore additional arguments when in "strict" mode */
target = Client_Search(Req->argv[1]);
if (!target || Client_Type(target) != CLIENT_SERVER)
- return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
Client_ID(Client), Req->argv[1]);
if (target != Client_ThisServer()) {
/* Ok, we have to forward the PING */
- if (Client_Type(Client) == CLIENT_SERVER)
+ if (Client_Type(Client) == CLIENT_SERVER) {
+ _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
from = Client_Search(Req->prefix);
- else
+ } else
from = Client;
if (!from)
- return IRC_WriteStrClient(Client,
+ return IRC_WriteErrClient(Client,
ERR_NOSUCHSERVER_MSG,
Client_ID(Client), Req->prefix);
} else
from = Client_ThisServer();
if (!from)
- return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
Client_ID(Client), Req->prefix);
- Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...",
+ LogDebug("Connection %d: got PING, sending PONG ...",
Client_Conn(Client));
#ifdef STRICT_RFC
/* Wrong number of arguments? */
if (Req->argc < 1) {
if (Client_Type(Client) == CLIENT_USER)
- return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG,
Client_ID(Client));
else
return CONNECTED;
/* Forward? */
if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) {
+ _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
+
target = Client_Search(Req->argv[0]);
if (!target)
- return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
+ return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
Client_ID(Client), Req->argv[0]);
from = Client_Search(Req->prefix);
if (target != Client_ThisServer() && target != from) {
/* Ok, we have to forward the message. */
if (!from)
- return IRC_WriteStrClient(Client,
+ return IRC_WriteErrClient(Client,
ERR_NOSUCHSERVER_MSG,
Client_ID(Client), Req->prefix);
if (auth_ping) {
LogDebug("AUTH PONG: waiting for token \"%ld\", got \"%s\" ...",
auth_ping, Req->argv[0]);
- if (auth_ping == atoi(Req->argv[0])) {
+ if (auth_ping == atol(Req->argv[0])) {
Conn_SetAuthPing(conn, 0);
if (Client_Type(Client) == CLIENT_WAITAUTHPING)
Login_User(Client);
} else
if (!IRC_WriteStrClient(Client,
- "To connect, type /QUOTE PONG %ld",
- auth_ping))
+ "NOTICE %s :To connect, type /QUOTE PONG %ld",
+ Client_ID(Client), auth_ping))
return DISCONNECTED;
}
#endif
if (Client_Type(Client) == CLIENT_SERVER && Conn_LastPing(conn) == 0) {
Log(LOG_INFO,
"Synchronization with \"%s\" done (connection %d): %ld second%s [%ld users, %ld channels].",
- Client_ID(Client), conn, time(NULL) - Conn_GetSignon(conn),
+ Client_ID(Client), conn,
+ (long)(time(NULL) - Conn_GetSignon(conn)),
time(NULL) - Conn_GetSignon(conn) == 1 ? "" : "s",
Client_UserCount(), Channel_CountVisible(NULL));
- Conn_UpdatePing(conn);
- } else
- LogDebug("Connection %d: received PONG. Lag: %ld seconds.",
- conn, time(NULL) - Conn_LastPing(conn));
+ } else {
+ if (Conn_LastPing(conn) > 1)
+ LogDebug("Connection %d: received PONG. Lag: %ld seconds.",
+ conn, (long)(time(NULL) - Conn_LastPing(conn)));
+ else
+ LogDebug("Got unexpected PONG on connection %d. Ignored.",
+ conn);
+ }
+ /* We got a PONG, so signal that none is pending on this connection. */
+ Conn_UpdatePing(conn, 1);
return CONNECTED;
} /* IRC_PONG */
-/**
- * Kill all users with a specific nickname in the network.
- *
- * @param Nick Nickname.
- * @param Reason Reason for the KILL.
- */
-static void
-Kill_Nick(char *Nick, char *Reason)
-{
- REQUEST r;
-
- assert (Nick != NULL);
- assert (Reason != NULL);
-
- r.prefix = NULL;
- r.argv[0] = Nick;
- r.argv[1] = Reason;
- r.argc = 2;
-
- Log(LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s!",
- Nick, Reason);
-
- IRC_KILL(Client_ThisServer(), &r);
-} /* Kill_Nick */
-
/**
* Change the nickname of a client.
*