2001-12-14 09:13:43 +01:00
|
|
|
/*
|
|
|
|
* ngIRCd -- The Next Generation IRC Daemon
|
2012-08-26 12:27:51 +02:00
|
|
|
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de)
|
2001-12-14 09:13:43 +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.
|
2001-12-14 09:13:43 +01:00
|
|
|
*/
|
|
|
|
|
2002-01-04 02:21:22 +01:00
|
|
|
#define __client_c__
|
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "portab.h"
|
2001-12-14 09:13:43 +01:00
|
|
|
|
2010-12-27 17:14:14 +01:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* Client management.
|
|
|
|
*/
|
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "imp.h"
|
2001-12-14 09:13:43 +01:00
|
|
|
#include <assert.h>
|
2001-12-23 23:04:37 +01:00
|
|
|
#include <unistd.h>
|
2001-12-27 17:54:51 +01:00
|
|
|
#include <stdio.h>
|
2002-01-01 19:25:44 +01:00
|
|
|
#include <stdlib.h>
|
2001-12-23 23:04:37 +01:00
|
|
|
#include <string.h>
|
2004-01-17 04:17:49 +01:00
|
|
|
#include <strings.h>
|
2001-12-27 18:15:29 +01:00
|
|
|
#include <netdb.h>
|
2001-12-14 09:13:43 +01:00
|
|
|
|
2005-04-27 09:46:50 +02:00
|
|
|
#include "defines.h"
|
2002-05-27 15:09:26 +02:00
|
|
|
#include "conn.h"
|
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "exp.h"
|
2001-12-26 15:45:37 +01:00
|
|
|
#include "client.h"
|
|
|
|
|
|
|
|
#include <imp.h>
|
2002-01-06 16:18:14 +01:00
|
|
|
#include "ngircd.h"
|
2001-12-14 09:13:43 +01:00
|
|
|
#include "channel.h"
|
2001-12-30 20:26:11 +01:00
|
|
|
#include "conf.h"
|
2012-03-31 15:24:30 +02:00
|
|
|
#include "conn-func.h"
|
2002-03-25 17:59:36 +01:00
|
|
|
#include "hash.h"
|
2002-02-28 00:23:53 +01:00
|
|
|
#include "irc-write.h"
|
2001-12-14 09:13:43 +01:00
|
|
|
#include "log.h"
|
2013-02-05 13:04:11 +01:00
|
|
|
#include "match.h"
|
2001-12-26 15:45:37 +01:00
|
|
|
#include "messages.h"
|
2001-12-14 09:13:43 +01:00
|
|
|
|
|
|
|
#include <exp.h>
|
2001-12-26 15:45:37 +01:00
|
|
|
|
2002-10-04 14:39:58 +02:00
|
|
|
#define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static CLIENT *This_Server, *My_Clients;
|
2001-12-14 09:13:43 +01:00
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static WHOWAS My_Whowas[MAX_WHOWAS];
|
|
|
|
static int Last_Whowas = -1;
|
2008-04-04 21:30:01 +02:00
|
|
|
static long Max_Users, My_Max_Users;
|
2005-05-16 14:23:48 +02:00
|
|
|
|
2001-12-14 09:13:43 +01:00
|
|
|
|
2006-10-07 12:40:52 +02:00
|
|
|
static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
|
|
|
|
static unsigned long MyCount PARAMS(( CLIENT_TYPE Type ));
|
2002-01-16 23:10:35 +01:00
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static CLIENT *New_Client_Struct PARAMS(( void ));
|
|
|
|
static void Generate_MyToken PARAMS(( CLIENT *Client ));
|
|
|
|
static void Adjust_Counters PARAMS(( CLIENT *Client ));
|
2002-12-23 00:29:09 +01:00
|
|
|
|
2006-03-11 02:37:31 +01:00
|
|
|
static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
|
2009-04-12 01:09:42 +02:00
|
|
|
CLIENT *TopServer, int Type, const char *ID,
|
|
|
|
const char *User, const char *Hostname, const char *Info,
|
|
|
|
int Hops, int Token, const char *Modes,
|
2008-08-16 17:19:27 +02:00
|
|
|
bool Idented));
|
|
|
|
|
2009-04-12 01:09:42 +02:00
|
|
|
static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
|
2008-08-16 17:19:27 +02:00
|
|
|
bool SendQuit));
|
2006-03-11 02:37:31 +01:00
|
|
|
|
2012-03-31 15:24:30 +02:00
|
|
|
static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix,
|
|
|
|
void *i));
|
2002-12-23 00:29:09 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Client_Init( void )
|
2001-12-14 09:13:43 +01:00
|
|
|
{
|
2001-12-27 18:15:29 +01:00
|
|
|
struct hostent *h;
|
|
|
|
|
2001-12-14 09:13:43 +01:00
|
|
|
This_Server = New_Client_Struct( );
|
|
|
|
if( ! This_Server )
|
|
|
|
{
|
|
|
|
Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
|
2003-03-31 17:54:21 +02:00
|
|
|
Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
|
2001-12-14 09:13:43 +01:00
|
|
|
exit( 1 );
|
|
|
|
}
|
|
|
|
|
2013-08-04 13:33:10 +02:00
|
|
|
/* Client structure for this server */
|
2001-12-14 09:13:43 +01:00
|
|
|
This_Server->next = NULL;
|
|
|
|
This_Server->type = CLIENT_SERVER;
|
|
|
|
This_Server->conn_id = NONE;
|
|
|
|
This_Server->introducer = This_Server;
|
2002-01-09 02:08:08 +01:00
|
|
|
This_Server->mytoken = 1;
|
2002-01-12 00:50:40 +01:00
|
|
|
This_Server->hops = 0;
|
2001-12-27 18:15:29 +01:00
|
|
|
|
2001-12-23 23:04:37 +01:00
|
|
|
gethostname( This_Server->host, CLIENT_HOST_LEN );
|
config: deprecate NoXX-Options
ngircd unfortunately uses several options using double-negation, e.g.
NoIdent = No, NoPam = No, etc.
This renames all options by dropping the "No" prefix, e.g.
"NoIdent = no" becomes "Ident = yes".
The old options will continue to work, but will cause a warning
message.
Also update man pages and default config.
To prevent silly
'Ident = yes' from appearing in --configtest output in the
'ident support not compiled in and Ident Option not used' case,
make default value depend on feature availability.
If feature is available, enable by default, otherwise disable.
We might consider moving these options to a new
[Feature]
section, or something like that, because none of these options are
essential.
Another possible improvement:
'Ident = yes' option in ngircd.conf causes a warning if ngircd was
built without ident support.
This does not happen with e.g. zeroconf....
2011-01-08 15:56:14 +01:00
|
|
|
if (Conf_DNS) {
|
2007-10-25 13:01:19 +02:00
|
|
|
h = gethostbyname( This_Server->host );
|
|
|
|
if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
|
|
|
|
}
|
2002-03-25 17:59:36 +01:00
|
|
|
Client_SetID( This_Server, Conf_ServerName );
|
|
|
|
Client_SetInfo( This_Server, Conf_ServerInfo );
|
2001-12-23 23:04:37 +01:00
|
|
|
|
2001-12-14 09:13:43 +01:00
|
|
|
My_Clients = This_Server;
|
2005-05-16 14:23:48 +02:00
|
|
|
|
|
|
|
memset( &My_Whowas, 0, sizeof( My_Whowas ));
|
2001-12-14 09:13:43 +01:00
|
|
|
} /* Client_Init */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Client_Exit( void )
|
2001-12-14 09:13:43 +01:00
|
|
|
{
|
2001-12-23 23:04:37 +01:00
|
|
|
CLIENT *c, *next;
|
2005-03-19 19:43:48 +01:00
|
|
|
int cnt;
|
2001-12-23 23:04:37 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
if( NGIRCd_SignalRestart ) Client_Destroy( This_Server, "Server going down (restarting).", NULL, false );
|
|
|
|
else Client_Destroy( This_Server, "Server going down.", NULL, false );
|
2001-12-23 23:04:37 +01:00
|
|
|
|
|
|
|
cnt = 0;
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
|
|
|
cnt++;
|
2002-03-25 20:11:01 +01:00
|
|
|
next = (CLIENT *)c->next;
|
2001-12-23 23:04:37 +01:00
|
|
|
free( c );
|
|
|
|
c = next;
|
|
|
|
}
|
2001-12-25 23:04:26 +01:00
|
|
|
if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
|
2002-01-06 16:18:14 +01:00
|
|
|
} /* Client_Exit */
|
2001-12-14 09:13:43 +01:00
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_ThisServer( void )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
return This_Server;
|
|
|
|
} /* Client_ThisServer */
|
|
|
|
|
|
|
|
|
2006-03-11 02:37:31 +01:00
|
|
|
/**
|
|
|
|
* Initialize new local client; wrapper function for Init_New_Client().
|
|
|
|
* @return New CLIENT structure.
|
|
|
|
*/
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_NewLocal(CONN_ID Idx, const char *Hostname, int Type, bool Idented)
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2006-03-11 02:37:31 +01:00
|
|
|
return Init_New_Client(Idx, This_Server, NULL, Type, NULL, NULL,
|
|
|
|
Hostname, NULL, 0, 0, NULL, Idented);
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_NewLocal */
|
|
|
|
|
|
|
|
|
2006-03-11 02:37:31 +01:00
|
|
|
/**
|
|
|
|
* Initialize new remote server; wrapper function for Init_New_Client().
|
|
|
|
* @return New CLIENT structure.
|
|
|
|
*/
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_NewRemoteServer(CLIENT *Introducer, const char *Hostname, CLIENT *TopServer,
|
|
|
|
int Hops, int Token, const char *Info, bool Idented)
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2006-03-11 02:37:31 +01:00
|
|
|
return Init_New_Client(NONE, Introducer, TopServer, CLIENT_SERVER,
|
|
|
|
Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented);
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_NewRemoteServer */
|
|
|
|
|
|
|
|
|
2006-03-11 02:37:31 +01:00
|
|
|
/**
|
|
|
|
* Initialize new remote client; wrapper function for Init_New_Client().
|
|
|
|
* @return New CLIENT structure.
|
|
|
|
*/
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_NewRemoteUser(CLIENT *Introducer, const char *Nick, int Hops, const char *User,
|
|
|
|
const char *Hostname, int Token, const char *Modes, const char *Info, bool Idented)
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2006-03-11 02:37:31 +01:00
|
|
|
return Init_New_Client(NONE, Introducer, NULL, CLIENT_USER, Nick,
|
|
|
|
User, Hostname, Info, Hops, Token, Modes, Idented);
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_NewRemoteUser */
|
|
|
|
|
|
|
|
|
2006-03-11 02:37:31 +01:00
|
|
|
/**
|
|
|
|
* Initialize new client and set up the given parameters like client type,
|
|
|
|
* user name, host name, introducing server etc. ...
|
|
|
|
* @return New CLIENT structure.
|
|
|
|
*/
|
2006-03-10 21:25:29 +01:00
|
|
|
static CLIENT *
|
2006-03-11 02:37:31 +01:00
|
|
|
Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
|
2010-02-10 23:40:03 +01:00
|
|
|
int Type, const char *ID, const char *User, const char *Hostname,
|
|
|
|
const char *Info, int Hops, int Token, const char *Modes, bool Idented)
|
2001-12-23 23:04:37 +01:00
|
|
|
{
|
|
|
|
CLIENT *client;
|
|
|
|
|
2010-02-10 23:40:03 +01:00
|
|
|
assert(Idx >= NONE);
|
|
|
|
assert(Introducer != NULL);
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2010-02-10 23:40:03 +01:00
|
|
|
client = New_Client_Struct();
|
|
|
|
if (!client)
|
|
|
|
return NULL;
|
2001-12-23 23:04:37 +01:00
|
|
|
|
2005-06-12 18:18:49 +02:00
|
|
|
client->starttime = time(NULL);
|
2001-12-23 23:04:37 +01:00
|
|
|
client->conn_id = Idx;
|
2002-01-04 02:21:22 +01:00
|
|
|
client->introducer = Introducer;
|
2002-01-29 01:14:49 +01:00
|
|
|
client->topserver = TopServer;
|
2002-01-04 02:21:22 +01:00
|
|
|
client->type = Type;
|
2010-02-10 23:40:03 +01:00
|
|
|
if (ID)
|
|
|
|
Client_SetID(client, ID);
|
2010-07-11 17:03:43 +02:00
|
|
|
if (User) {
|
2010-02-10 23:40:03 +01:00
|
|
|
Client_SetUser(client, User, Idented);
|
2010-07-11 17:03:43 +02:00
|
|
|
Client_SetOrigUser(client, User);
|
|
|
|
}
|
2010-02-10 23:40:03 +01:00
|
|
|
if (Hostname)
|
|
|
|
Client_SetHostname(client, Hostname);
|
|
|
|
if (Info)
|
|
|
|
Client_SetInfo(client, Info);
|
2002-01-04 02:21:22 +01:00
|
|
|
client->hops = Hops;
|
|
|
|
client->token = Token;
|
2010-02-10 23:40:03 +01:00
|
|
|
if (Modes)
|
|
|
|
Client_SetModes(client, Modes);
|
|
|
|
if (Type == CLIENT_SERVER)
|
|
|
|
Generate_MyToken(client);
|
2001-12-23 23:04:37 +01:00
|
|
|
|
2013-08-04 18:25:24 +02:00
|
|
|
if (Client_HasMode(client, 'a'))
|
2010-02-10 23:40:03 +01:00
|
|
|
strlcpy(client->away, DEFAULT_AWAY_MSG, sizeof(client->away));
|
2002-03-04 02:04:46 +01:00
|
|
|
|
2002-03-25 20:11:01 +01:00
|
|
|
client->next = (POINTER *)My_Clients;
|
2001-12-23 23:04:37 +01:00
|
|
|
My_Clients = client;
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2010-02-10 23:40:03 +01:00
|
|
|
Adjust_Counters(client);
|
2002-12-23 00:29:09 +01:00
|
|
|
|
2001-12-23 23:04:37 +01:00
|
|
|
return client;
|
2006-03-11 02:37:31 +01:00
|
|
|
} /* Init_New_Client */
|
2001-12-23 23:04:37 +01:00
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool SendQuit )
|
2001-12-23 23:04:37 +01:00
|
|
|
{
|
2009-04-21 08:40:10 +02:00
|
|
|
/* remove a client */
|
2001-12-23 23:04:37 +01:00
|
|
|
|
|
|
|
CLIENT *last, *c;
|
2009-04-12 01:09:42 +02:00
|
|
|
char msg[LINE_LEN];
|
|
|
|
const char *txt;
|
2001-12-23 23:04:37 +01:00
|
|
|
|
2001-12-24 02:31:14 +01:00
|
|
|
assert( Client != NULL );
|
2002-01-04 18:57:08 +01:00
|
|
|
|
2013-01-26 16:52:41 +01:00
|
|
|
txt = LogMsg ? LogMsg : FwdMsg;
|
|
|
|
if (!txt)
|
|
|
|
txt = "Reason unknown";
|
2002-01-06 16:18:14 +01:00
|
|
|
|
2009-04-21 08:40:10 +02:00
|
|
|
/* netsplit message */
|
2005-06-04 14:32:09 +02:00
|
|
|
if( Client->type == CLIENT_SERVER ) {
|
|
|
|
strlcpy(msg, This_Server->id, sizeof (msg));
|
|
|
|
strlcat(msg, " ", sizeof (msg));
|
|
|
|
strlcat(msg, Client->id, sizeof (msg));
|
|
|
|
}
|
2002-03-10 23:03:20 +01:00
|
|
|
|
2001-12-23 23:04:37 +01:00
|
|
|
last = NULL;
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
2002-01-04 18:57:08 +01:00
|
|
|
if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
|
|
|
|
{
|
2009-04-21 08:40:10 +02:00
|
|
|
/*
|
|
|
|
* The client that is about to be removed is a server,
|
|
|
|
* the client we are checking right now is a child of that
|
|
|
|
* server and thus has to be removed, too.
|
|
|
|
*
|
|
|
|
* Call Client_Destroy() recursively with the server as the
|
|
|
|
* new "object to be removed". This starts the cycle again, until
|
|
|
|
* all servers that are linked via the original server have been
|
|
|
|
* removed.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_Destroy( c, NULL, msg, false );
|
2002-01-04 18:57:08 +01:00
|
|
|
last = NULL;
|
|
|
|
c = My_Clients;
|
|
|
|
continue;
|
|
|
|
}
|
2001-12-23 23:04:37 +01:00
|
|
|
if( c == Client )
|
|
|
|
{
|
2009-04-21 08:40:10 +02:00
|
|
|
/* found the client: remove it */
|
2001-12-23 23:04:37 +01:00
|
|
|
if( last ) last->next = c->next;
|
2002-03-25 20:11:01 +01:00
|
|
|
else My_Clients = (CLIENT *)c->next;
|
2001-12-27 20:13:47 +01:00
|
|
|
|
2008-08-16 17:19:27 +02:00
|
|
|
if(c->type == CLIENT_USER || c->type == CLIENT_SERVICE)
|
|
|
|
Destroy_UserOrService(c, txt, FwdMsg, SendQuit);
|
2002-01-06 16:18:14 +01:00
|
|
|
else if( c->type == CLIENT_SERVER )
|
|
|
|
{
|
2013-01-26 16:52:41 +01:00
|
|
|
if (c != This_Server) {
|
|
|
|
if (c->conn_id != NONE)
|
|
|
|
Log(LOG_NOTICE|LOG_snotice,
|
|
|
|
"Server \"%s\" unregistered (connection %d): %s.",
|
|
|
|
c->id, c->conn_id, txt);
|
|
|
|
else
|
|
|
|
Log(LOG_NOTICE|LOG_snotice,
|
|
|
|
"Server \"%s\" unregistered: %s.",
|
|
|
|
c->id, txt);
|
2002-02-27 15:47:53 +01:00
|
|
|
}
|
2002-01-09 02:08:08 +01:00
|
|
|
|
2009-04-21 08:40:10 +02:00
|
|
|
/* inform other servers */
|
2002-12-19 05:33:27 +01:00
|
|
|
if( ! NGIRCd_SignalQuit )
|
2002-01-09 02:08:08 +01:00
|
|
|
{
|
|
|
|
if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
|
|
|
|
else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
|
|
|
|
}
|
2002-01-04 18:57:08 +01:00
|
|
|
}
|
2002-02-27 15:47:53 +01:00
|
|
|
else
|
|
|
|
{
|
2013-01-26 16:52:41 +01:00
|
|
|
if (c->conn_id != NONE) {
|
|
|
|
if (c->id[0])
|
|
|
|
Log(LOG_NOTICE,
|
|
|
|
"Client \"%s\" unregistered (connection %d): %s.",
|
|
|
|
c->id, c->conn_id, txt);
|
|
|
|
else
|
|
|
|
Log(LOG_NOTICE,
|
|
|
|
"Client unregistered (connection %d): %s.",
|
|
|
|
c->conn_id, txt);
|
2006-03-25 00:25:38 +01:00
|
|
|
} else {
|
2013-01-26 16:52:41 +01:00
|
|
|
Log(LOG_WARNING,
|
|
|
|
"Unregistered unknown client \"%s\": %s",
|
|
|
|
c->id[0] ? c->id : "(No Nick)", txt);
|
2002-02-27 15:47:53 +01:00
|
|
|
}
|
|
|
|
}
|
2001-12-27 20:13:47 +01:00
|
|
|
|
2013-08-04 11:15:11 +02:00
|
|
|
if (c->cloaked)
|
|
|
|
free(c->cloaked);
|
2001-12-23 23:04:37 +01:00
|
|
|
free( c );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last = c;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2001-12-23 23:04:37 +01:00
|
|
|
}
|
|
|
|
} /* Client_Destroy */
|
|
|
|
|
|
|
|
|
2012-01-25 17:11:00 +01:00
|
|
|
/**
|
|
|
|
* Set client hostname.
|
|
|
|
*
|
|
|
|
* If global hostname cloaking is in effect, don't set the real hostname
|
|
|
|
* but the configured one.
|
|
|
|
*
|
|
|
|
* @param Client The client of which the hostname should be set.
|
|
|
|
* @param Hostname The new hostname.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetHostname( CLIENT *Client, const char *Hostname )
|
2001-12-29 21:18:18 +01:00
|
|
|
{
|
2012-01-25 17:11:00 +01:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Hostname != NULL);
|
2006-12-07 23:24:14 +01:00
|
|
|
|
2011-03-19 16:58:29 +01:00
|
|
|
if (strlen(Conf_CloakHost)) {
|
2012-08-02 19:44:40 +02:00
|
|
|
char cloak[GETID_LEN];
|
|
|
|
|
|
|
|
strlcpy(cloak, Hostname, GETID_LEN);
|
|
|
|
strlcat(cloak, Conf_CloakHostSalt, GETID_LEN);
|
|
|
|
snprintf(cloak, GETID_LEN, Conf_CloakHost, Hash(cloak));
|
|
|
|
|
2012-01-25 17:11:00 +01:00
|
|
|
LogDebug("Updating hostname of \"%s\": \"%s\" -> \"%s\"",
|
2012-08-02 19:44:40 +02:00
|
|
|
Client_ID(Client), Client->host, cloak);
|
|
|
|
strlcpy(Client->host, cloak, sizeof(Client->host));
|
2011-02-14 16:16:07 +01:00
|
|
|
} else {
|
2012-01-25 17:11:00 +01:00
|
|
|
LogDebug("Updating hostname of \"%s\": \"%s\" -> \"%s\"",
|
|
|
|
Client_ID(Client), Client->host, Hostname);
|
|
|
|
strlcpy(Client->host, Hostname, sizeof(Client->host));
|
2011-02-14 16:16:07 +01:00
|
|
|
}
|
2001-12-29 21:18:18 +01:00
|
|
|
} /* Client_SetHostname */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetID( CLIENT *Client, const char *ID )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
2002-03-06 15:30:43 +01:00
|
|
|
assert( ID != NULL );
|
|
|
|
|
2002-12-26 17:25:43 +01:00
|
|
|
strlcpy( Client->id, ID, sizeof( Client->id ));
|
2002-03-25 17:59:36 +01:00
|
|
|
|
2011-06-19 06:08:33 +02:00
|
|
|
if (Conf_CloakUserToNick) {
|
2010-12-20 03:35:17 +01:00
|
|
|
strlcpy( Client->user, ID, sizeof( Client->user ));
|
2011-06-19 06:08:33 +02:00
|
|
|
strlcpy( Client->info, ID, sizeof( Client->info ));
|
|
|
|
}
|
2010-12-20 03:35:17 +01:00
|
|
|
|
2002-03-25 17:59:36 +01:00
|
|
|
/* Hash */
|
|
|
|
Client->hash = Hash( Client->id );
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_SetID */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetUser( CLIENT *Client, const char *User, bool Idented )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2009-04-20 08:34:09 +02:00
|
|
|
/* set clients username */
|
2002-01-04 02:21:22 +01:00
|
|
|
|
|
|
|
assert( Client != NULL );
|
2002-03-06 15:30:43 +01:00
|
|
|
assert( User != NULL );
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2011-06-19 06:08:33 +02:00
|
|
|
if (Conf_CloakUserToNick) {
|
|
|
|
strlcpy(Client->user, Client->id, sizeof(Client->user));
|
|
|
|
} else if (Idented) {
|
2009-04-20 08:34:09 +02:00
|
|
|
strlcpy(Client->user, User, sizeof(Client->user));
|
|
|
|
} else {
|
2002-01-06 00:26:05 +01:00
|
|
|
Client->user[0] = '~';
|
2009-04-20 08:34:09 +02:00
|
|
|
strlcpy(Client->user + 1, User, sizeof(Client->user) - 1);
|
2002-01-06 00:26:05 +01:00
|
|
|
}
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_SetUser */
|
|
|
|
|
|
|
|
|
2010-07-11 17:03:43 +02:00
|
|
|
/**
|
|
|
|
* Set "original" user name of a client.
|
|
|
|
* This function saves the "original" user name, the user name specified by
|
|
|
|
* the peer using the USER command, into the CLIENT structure. This user
|
|
|
|
* name may be used for authentication, for example.
|
|
|
|
* @param Client The client.
|
|
|
|
* @param User User name to set.
|
|
|
|
*/
|
|
|
|
GLOBAL void
|
2010-10-24 21:48:32 +02:00
|
|
|
Client_SetOrigUser(CLIENT UNUSED *Client, const char UNUSED *User)
|
|
|
|
{
|
2010-07-11 17:03:43 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(User != NULL);
|
|
|
|
|
2010-07-12 13:22:48 +02:00
|
|
|
#if defined(PAM) && defined(IDENTAUTH)
|
2010-07-11 17:03:43 +02:00
|
|
|
strlcpy(Client->orig_user, User, sizeof(Client->orig_user));
|
|
|
|
#endif
|
|
|
|
} /* Client_SetOrigUser */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetInfo( CLIENT *Client, const char *Info )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2009-04-20 08:34:09 +02:00
|
|
|
/* set client hostname */
|
2002-01-04 02:21:22 +01:00
|
|
|
|
|
|
|
assert( Client != NULL );
|
2002-03-06 15:30:43 +01:00
|
|
|
assert( Info != NULL );
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2011-06-19 06:08:33 +02:00
|
|
|
if (Conf_CloakUserToNick)
|
|
|
|
strlcpy(Client->info, Client->id, sizeof(Client->info));
|
|
|
|
else
|
|
|
|
strlcpy(Client->info, Info, sizeof(Client->info));
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_SetInfo */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetModes( CLIENT *Client, const char *Modes )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
2002-03-06 15:30:43 +01:00
|
|
|
assert( Modes != NULL );
|
|
|
|
|
2009-04-20 08:34:09 +02:00
|
|
|
strlcpy(Client->modes, Modes, sizeof( Client->modes ));
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_SetModes */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetFlags( CLIENT *Client, const char *Flags )
|
2002-09-03 20:54:31 +02:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
assert( Flags != NULL );
|
|
|
|
|
2009-04-20 08:34:09 +02:00
|
|
|
strlcpy(Client->flags, Flags, sizeof(Client->flags));
|
2002-09-03 20:54:31 +02:00
|
|
|
} /* Client_SetFlags */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Client_SetAway( CLIENT *Client, const char *Txt )
|
2002-02-27 19:22:09 +01:00
|
|
|
{
|
2003-01-08 23:03:21 +01:00
|
|
|
/* Set AWAY reason of client */
|
2002-02-27 19:22:09 +01:00
|
|
|
|
|
|
|
assert( Client != NULL );
|
2003-01-08 23:03:21 +01:00
|
|
|
assert( Txt != NULL );
|
2002-02-27 19:22:09 +01:00
|
|
|
|
2003-01-08 23:03:21 +01:00
|
|
|
strlcpy( Client->away, Txt, sizeof( Client->away ));
|
2008-08-16 17:52:02 +02:00
|
|
|
LogDebug("%s \"%s\" is away: %s", Client_TypeText(Client),
|
|
|
|
Client_Mask(Client), Txt);
|
2002-02-27 19:22:09 +01:00
|
|
|
} /* Client_SetAway */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Client_SetType( CLIENT *Client, int Type )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
Client->type = Type;
|
2002-01-08 00:42:12 +01:00
|
|
|
if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
|
2002-12-23 00:29:09 +01:00
|
|
|
Adjust_Counters( Client );
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_SetType */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Client_SetHops( CLIENT *Client, int Hops )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
Client->hops = Hops;
|
|
|
|
} /* Client_SetHops */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Client_SetToken( CLIENT *Client, int Token )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
Client->token = Token;
|
|
|
|
} /* Client_SetToken */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
2002-03-06 15:30:43 +01:00
|
|
|
assert( Introducer != NULL );
|
2002-01-04 02:21:22 +01:00
|
|
|
Client->introducer = Introducer;
|
|
|
|
} /* Client_SetIntroducer */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Client_SetOperByMe( CLIENT *Client, bool OperByMe )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
Client->oper_by_me = OperByMe;
|
|
|
|
} /* Client_SetOperByMe */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
|
|
|
Client_ModeAdd( CLIENT *Client, char Mode )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
/* Set Mode.
|
2013-08-04 13:33:10 +02:00
|
|
|
* If Client already had Mode, return false.
|
2005-03-19 19:43:48 +01:00
|
|
|
* If the Mode was newly set, return true.
|
|
|
|
*/
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
char x[2];
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2002-01-04 02:21:22 +01:00
|
|
|
assert( Client != NULL );
|
|
|
|
|
|
|
|
x[0] = Mode; x[1] = '\0';
|
2013-08-04 18:25:24 +02:00
|
|
|
if (!Client_HasMode(Client, x[0])) {
|
2002-12-26 17:48:14 +01:00
|
|
|
strlcat( Client->modes, x, sizeof( Client->modes ));
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2002-01-04 02:21:22 +01:00
|
|
|
}
|
2005-03-19 19:43:48 +01:00
|
|
|
else return false;
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_ModeAdd */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
|
|
|
Client_ModeDel( CLIENT *Client, char Mode )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
/* Delete Mode.
|
|
|
|
* If Mode was removed, return true.
|
|
|
|
* If Client did not have Mode, return false.
|
|
|
|
*/
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
char x[2], *p;
|
2002-01-04 02:21:22 +01:00
|
|
|
|
|
|
|
assert( Client != NULL );
|
|
|
|
|
|
|
|
x[0] = Mode; x[1] = '\0';
|
|
|
|
|
|
|
|
p = strchr( Client->modes, x[0] );
|
2005-03-19 19:43:48 +01:00
|
|
|
if( ! p ) return false;
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
/* Client has Mode -> delete */
|
2002-01-04 02:21:22 +01:00
|
|
|
while( *p )
|
|
|
|
{
|
|
|
|
*p = *(p + 1);
|
|
|
|
p++;
|
|
|
|
}
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_ModeDel */
|
|
|
|
|
|
|
|
|
2013-02-05 13:04:11 +01:00
|
|
|
/**
|
|
|
|
* Search CLIENT structure of a given nick name.
|
|
|
|
*
|
|
|
|
* @return Pointer to CLIENT structure or NULL if not found.
|
|
|
|
*/
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2008-05-03 21:20:02 +02:00
|
|
|
Client_Search( const char *Nick )
|
2001-12-31 03:18:51 +01:00
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
char search_id[CLIENT_ID_LEN], *ptr;
|
2002-01-27 23:07:36 +01:00
|
|
|
CLIENT *c = NULL;
|
2002-03-25 17:59:36 +01:00
|
|
|
UINT32 search_hash;
|
2001-12-31 03:18:51 +01:00
|
|
|
|
|
|
|
assert( Nick != NULL );
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
/* copy Nick and truncate hostmask if necessary */
|
2002-12-26 17:25:43 +01:00
|
|
|
strlcpy( search_id, Nick, sizeof( search_id ));
|
2002-03-25 17:59:36 +01:00
|
|
|
ptr = strchr( search_id, '!' );
|
2002-01-27 19:27:12 +01:00
|
|
|
if( ptr ) *ptr = '\0';
|
|
|
|
|
2009-04-20 08:34:09 +02:00
|
|
|
search_hash = Hash(search_id);
|
2002-03-25 17:59:36 +01:00
|
|
|
|
2001-12-31 03:18:51 +01:00
|
|
|
c = My_Clients;
|
2009-04-20 08:34:09 +02:00
|
|
|
while (c) {
|
|
|
|
if (c->hash == search_hash && strcasecmp(c->id, search_id) == 0)
|
|
|
|
return c;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2002-01-04 02:21:22 +01:00
|
|
|
}
|
|
|
|
return NULL;
|
2013-02-05 13:04:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-08-04 13:33:10 +02:00
|
|
|
* Search first CLIENT structure matching a given mask of a server.
|
2013-02-05 13:04:11 +01:00
|
|
|
*
|
|
|
|
* The order of servers is arbitrary, but this function makes sure that the
|
|
|
|
* local server is always returned if the mask matches it.
|
|
|
|
*
|
|
|
|
* @return Pointer to CLIENT structure or NULL if no server could be found.
|
|
|
|
*/
|
|
|
|
GLOBAL CLIENT *
|
|
|
|
Client_SearchServer(const char *Mask)
|
|
|
|
{
|
|
|
|
CLIENT *c;
|
|
|
|
|
|
|
|
assert(Mask != NULL);
|
|
|
|
|
|
|
|
/* First check if mask matches the local server */
|
|
|
|
if (MatchCaseInsensitive(Mask, Client_ID(Client_ThisServer())))
|
|
|
|
return Client_ThisServer();
|
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
while (c) {
|
|
|
|
if (Client_Type(c) == CLIENT_SERVER) {
|
|
|
|
/* This is a server: check if Mask matches */
|
|
|
|
if (MatchCaseInsensitive(Mask, c->id))
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
c = (CLIENT *)c->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-01-04 02:21:22 +01:00
|
|
|
|
|
|
|
|
2010-12-24 12:48:03 +01:00
|
|
|
/**
|
|
|
|
* Get client structure ("introducer") identfied by a server token.
|
|
|
|
* @return CLIENT structure or NULL if none could be found.
|
|
|
|
*/
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_GetFromToken( CLIENT *Client, int Token )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
|
|
|
|
|
|
|
assert( Client != NULL );
|
2010-12-24 12:48:03 +01:00
|
|
|
|
|
|
|
if (!Token)
|
|
|
|
return NULL;
|
2002-01-04 02:21:22 +01:00
|
|
|
|
|
|
|
c = My_Clients;
|
2009-04-20 08:34:09 +02:00
|
|
|
while (c) {
|
|
|
|
if ((c->type == CLIENT_SERVER) && (c->introducer == Client) &&
|
|
|
|
(c->token == Token))
|
|
|
|
return c;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2001-12-31 03:18:51 +01:00
|
|
|
}
|
|
|
|
return NULL;
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_GetFromToken */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL int
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Type( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->type;
|
|
|
|
} /* Client_Type */
|
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CONN_ID
|
|
|
|
Client_Conn( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->conn_id;
|
|
|
|
} /* Client_Conn */
|
2001-12-31 03:18:51 +01:00
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_ID( CLIENT *Client )
|
2001-12-26 04:19:16 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
|
2002-03-06 15:30:43 +01:00
|
|
|
#ifdef DEBUG
|
2007-11-21 13:16:33 +01:00
|
|
|
if(Client->type == CLIENT_USER)
|
|
|
|
assert(strlen(Client->id) < Conf_MaxNickLength);
|
2002-03-06 15:30:43 +01:00
|
|
|
#endif
|
|
|
|
|
2002-01-04 02:21:22 +01:00
|
|
|
if( Client->id[0] ) return Client->id;
|
2001-12-26 04:19:16 +01:00
|
|
|
else return "*";
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_ID */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Info( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->info;
|
|
|
|
} /* Client_Info */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_User( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
2006-12-07 23:24:14 +01:00
|
|
|
return Client->user[0] ? Client->user : "~";
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_User */
|
|
|
|
|
|
|
|
|
2010-07-11 17:03:43 +02:00
|
|
|
#ifdef PAM
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the "original" user name as supplied by the USER command.
|
|
|
|
* The user name as given by the client is used for authentication instead
|
|
|
|
* of the one detected using IDENT requests.
|
|
|
|
* @param Client The client.
|
|
|
|
* @return Original user name.
|
|
|
|
*/
|
|
|
|
GLOBAL char *
|
|
|
|
Client_OrigUser(CLIENT *Client) {
|
|
|
|
#ifndef IDENTAUTH
|
|
|
|
char *user = Client->user;
|
|
|
|
|
|
|
|
if (user[0] == '~')
|
|
|
|
user++;
|
|
|
|
return user;
|
|
|
|
#else
|
|
|
|
return Client->orig_user;
|
|
|
|
#endif
|
|
|
|
} /* Client_OrigUser */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-08-17 20:51:14 +02:00
|
|
|
/**
|
|
|
|
* Return the hostname of a client.
|
|
|
|
* @param Client Pointer to client structure
|
|
|
|
* @return Pointer to client hostname
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2010-08-17 20:51:14 +02:00
|
|
|
Client_Hostname(CLIENT *Client)
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2010-08-17 20:51:14 +02:00
|
|
|
assert (Client != NULL);
|
2002-01-04 02:21:22 +01:00
|
|
|
return Client->host;
|
2012-11-24 16:15:35 +01:00
|
|
|
}
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2012-11-24 16:15:35 +01:00
|
|
|
/**
|
|
|
|
* Return the cloaked hostname of a client, if set.
|
|
|
|
* @param Client Pointer to the client structure.
|
|
|
|
* @return Pointer to the cloaked hostname or NULL if not set.
|
|
|
|
*/
|
|
|
|
GLOBAL char *
|
|
|
|
Client_HostnameCloaked(CLIENT *Client)
|
|
|
|
{
|
|
|
|
assert(Client != NULL);
|
|
|
|
return Client->cloaked;
|
|
|
|
}
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2010-08-17 20:54:33 +02:00
|
|
|
/**
|
2012-11-24 13:37:56 +01:00
|
|
|
* Get (potentially cloaked) hostname of a client to display it to other users.
|
2012-08-28 23:26:43 +02:00
|
|
|
*
|
2010-08-17 20:54:33 +02:00
|
|
|
* If the client has not enabled cloaking, the real hostname is used.
|
2012-08-28 23:26:43 +02:00
|
|
|
*
|
2010-08-17 20:54:33 +02:00
|
|
|
* @param Client Pointer to client structure
|
|
|
|
* @return Pointer to client hostname
|
|
|
|
*/
|
|
|
|
GLOBAL char *
|
2012-11-24 13:37:56 +01:00
|
|
|
Client_HostnameDisplayed(CLIENT *Client)
|
2010-08-17 20:54:33 +02:00
|
|
|
{
|
|
|
|
assert(Client != NULL);
|
2012-08-28 23:26:43 +02:00
|
|
|
|
2012-11-05 23:46:26 +01:00
|
|
|
/* Client isn't cloaked at all, return real hostname: */
|
2012-08-28 23:26:43 +02:00
|
|
|
if (!Client_HasMode(Client, 'x'))
|
2010-08-17 20:54:33 +02:00
|
|
|
return Client_Hostname(Client);
|
2012-08-28 23:26:43 +02:00
|
|
|
|
2012-11-24 16:15:35 +01:00
|
|
|
/* Use an already saved cloaked hostname, if there is one */
|
2013-08-04 11:15:11 +02:00
|
|
|
if (Client->cloaked)
|
2012-11-24 16:15:35 +01:00
|
|
|
return Client->cloaked;
|
2012-08-28 23:26:43 +02:00
|
|
|
|
2012-11-24 16:15:35 +01:00
|
|
|
Client_UpdateCloakedHostname(Client, NULL, NULL);
|
|
|
|
return Client->cloaked;
|
|
|
|
}
|
2012-08-28 23:26:43 +02:00
|
|
|
|
2012-11-24 16:15:35 +01:00
|
|
|
/**
|
|
|
|
* Update (and generate, if necessary) the cloaked hostname of a client.
|
|
|
|
*
|
|
|
|
* The newly set cloaked hostname is announced in the network using METADATA
|
|
|
|
* commands to peers that support this feature.
|
|
|
|
*
|
|
|
|
* @param Client The client of which the cloaked hostname should be updated.
|
|
|
|
* @param Origin The originator of the hostname change, or NULL if this server.
|
|
|
|
* @param Hostname The new cloaked hostname, or NULL if it should be generated.
|
|
|
|
*/
|
|
|
|
GLOBAL void
|
|
|
|
Client_UpdateCloakedHostname(CLIENT *Client, CLIENT *Origin,
|
|
|
|
const char *Hostname)
|
|
|
|
{
|
2013-08-04 11:15:11 +02:00
|
|
|
char Cloak_Buffer[CLIENT_HOST_LEN];
|
2010-08-17 20:54:33 +02:00
|
|
|
|
2012-11-24 16:15:35 +01:00
|
|
|
assert(Client != NULL);
|
|
|
|
if (!Origin)
|
|
|
|
Origin = Client_ThisServer();
|
|
|
|
|
2013-08-04 11:15:11 +02:00
|
|
|
if (!Client->cloaked) {
|
|
|
|
Client->cloaked = malloc(CLIENT_HOST_LEN);
|
|
|
|
if (!Client->cloaked)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-24 16:15:35 +01:00
|
|
|
if (!Hostname) {
|
|
|
|
/* Generate new cloaked hostname */
|
|
|
|
if (*Conf_CloakHostModeX) {
|
2013-08-04 11:15:11 +02:00
|
|
|
strlcpy(Cloak_Buffer, Client->host,
|
|
|
|
sizeof(Cloak_Buffer));
|
2012-11-24 16:15:35 +01:00
|
|
|
strlcat(Cloak_Buffer, Conf_CloakHostSalt,
|
2013-08-04 11:15:11 +02:00
|
|
|
sizeof(Cloak_Buffer));
|
|
|
|
snprintf(Client->cloaked, CLIENT_HOST_LEN,
|
2012-11-24 16:15:35 +01:00
|
|
|
Conf_CloakHostModeX, Hash(Cloak_Buffer));
|
|
|
|
} else
|
|
|
|
strlcpy(Client->cloaked, Client_ID(Client->introducer),
|
2013-08-04 11:15:11 +02:00
|
|
|
CLIENT_HOST_LEN);
|
2012-11-24 16:15:35 +01:00
|
|
|
} else
|
2013-08-04 11:15:11 +02:00
|
|
|
strlcpy(Client->cloaked, Hostname, CLIENT_HOST_LEN);
|
2012-11-24 16:15:35 +01:00
|
|
|
LogDebug("Cloaked hostname of \"%s\" updated to \"%s\"",
|
|
|
|
Client_ID(Client), Client->cloaked);
|
|
|
|
|
|
|
|
/* Inform other servers in the network */
|
|
|
|
IRC_WriteStrServersPrefixFlag(Client_NextHop(Origin), Origin, 'M',
|
|
|
|
"METADATA %s cloakhost :%s",
|
|
|
|
Client_ID(Client), Client->cloaked);
|
|
|
|
}
|
2010-08-17 20:54:33 +02:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Modes( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->modes;
|
|
|
|
} /* Client_Modes */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-09-03 20:54:31 +02:00
|
|
|
Client_Flags( CLIENT *Client )
|
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->flags;
|
|
|
|
} /* Client_Flags */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_OperByMe( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->oper_by_me;
|
|
|
|
} /* Client_OperByMe */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL int
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Hops( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->hops;
|
|
|
|
} /* Client_Hops */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL int
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Token( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->token;
|
|
|
|
} /* Client_Token */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL int
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_MyToken( CLIENT *Client )
|
2002-01-08 00:42:12 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->mytoken;
|
|
|
|
} /* Client_MyToken */
|
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
|
|
|
Client_NextHop( CLIENT *Client )
|
2002-01-05 21:08:17 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2002-01-05 21:08:17 +01:00
|
|
|
assert( Client != NULL );
|
|
|
|
|
|
|
|
c = Client;
|
2006-10-07 12:40:52 +02:00
|
|
|
while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server ))
|
|
|
|
c = c->introducer;
|
|
|
|
|
2002-01-05 21:08:17 +01:00
|
|
|
return c;
|
|
|
|
} /* Client_NextHop */
|
|
|
|
|
|
|
|
|
2009-04-20 08:34:09 +02:00
|
|
|
/**
|
2010-08-17 20:51:14 +02:00
|
|
|
* Return ID of a client: "client!user@host"
|
|
|
|
* This client ID is used for IRC prefixes, for example.
|
|
|
|
* Please note that this function uses a global static buffer, so you can't
|
2011-12-30 00:50:27 +01:00
|
|
|
* nest invocations without overwriting earlier results!
|
2010-08-17 20:51:14 +02:00
|
|
|
* @param Client Pointer to client structure
|
|
|
|
* @return Pointer to global buffer containing the client ID
|
2009-04-20 08:34:09 +02:00
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Mask( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
2010-08-17 20:51:14 +02:00
|
|
|
static char Mask_Buffer[GETID_LEN];
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2010-08-17 20:51:14 +02:00
|
|
|
assert (Client != NULL);
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2010-08-17 20:51:14 +02:00
|
|
|
/* Servers: return name only, there is no "mask" */
|
|
|
|
if (Client->type == CLIENT_SERVER)
|
|
|
|
return Client->id;
|
2002-01-04 02:21:22 +01:00
|
|
|
|
2010-08-17 20:51:14 +02:00
|
|
|
snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
|
|
|
|
Client->id, Client->user, Client->host);
|
|
|
|
return Mask_Buffer;
|
2002-01-04 02:21:22 +01:00
|
|
|
} /* Client_Mask */
|
|
|
|
|
|
|
|
|
2010-08-17 20:54:33 +02:00
|
|
|
/**
|
|
|
|
* Return ID of a client with cloaked hostname: "client!user@server-name"
|
2012-08-28 23:26:43 +02:00
|
|
|
*
|
2010-08-17 20:54:33 +02:00
|
|
|
* This client ID is used for IRC prefixes, for example.
|
|
|
|
* Please note that this function uses a global static buffer, so you can't
|
2011-12-30 00:50:27 +01:00
|
|
|
* nest invocations without overwriting earlier results!
|
2010-08-17 20:54:33 +02:00
|
|
|
* If the client has not enabled cloaking, the real hostname is used.
|
2012-08-28 23:26:43 +02:00
|
|
|
*
|
2010-08-17 20:54:33 +02:00
|
|
|
* @param Client Pointer to client structure
|
|
|
|
* @return Pointer to global buffer containing the client ID
|
|
|
|
*/
|
|
|
|
GLOBAL char *
|
|
|
|
Client_MaskCloaked(CLIENT *Client)
|
|
|
|
{
|
|
|
|
static char Mask_Buffer[GETID_LEN];
|
|
|
|
|
|
|
|
assert (Client != NULL);
|
|
|
|
|
|
|
|
/* Is the client using cloaking at all? */
|
|
|
|
if (!Client_HasMode(Client, 'x'))
|
2012-08-02 13:53:46 +02:00
|
|
|
return Client_Mask(Client);
|
|
|
|
|
2012-08-28 23:26:43 +02:00
|
|
|
snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user,
|
2012-11-24 13:37:56 +01:00
|
|
|
Client_HostnameDisplayed(Client));
|
2012-08-02 13:53:46 +02:00
|
|
|
|
2010-08-17 20:54:33 +02:00
|
|
|
return Mask_Buffer;
|
|
|
|
} /* Client_MaskCloaked */
|
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
|
|
|
Client_Introducer( CLIENT *Client )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->introducer;
|
|
|
|
} /* Client_Introducer */
|
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
|
|
|
Client_TopServer( CLIENT *Client )
|
2002-01-29 01:14:49 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->topserver;
|
|
|
|
} /* Client_TopServer */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
|
|
|
Client_HasMode( CLIENT *Client, char Mode )
|
2002-01-04 02:21:22 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return strchr( Client->modes, Mode ) != NULL;
|
|
|
|
} /* Client_HasMode */
|
2001-12-26 04:19:16 +01:00
|
|
|
|
|
|
|
|
2013-08-04 04:20:13 +02:00
|
|
|
GLOBAL bool
|
|
|
|
Client_HasFlag( CLIENT *Client, char Flag )
|
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return strchr( Client->flags, Flag ) != NULL;
|
|
|
|
} /* Client_HasFlag */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL char *
|
2002-05-27 15:09:26 +02:00
|
|
|
Client_Away( CLIENT *Client )
|
2002-02-27 19:22:09 +01:00
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->away;
|
|
|
|
} /* Client_Away */
|
|
|
|
|
|
|
|
|
2011-08-19 10:44:26 +02:00
|
|
|
/**
|
|
|
|
* Make sure that a given nickname is valid.
|
|
|
|
*
|
|
|
|
* If the nickname is not valid for the given client, this function sends back
|
|
|
|
* the appropriate error messages.
|
|
|
|
*
|
|
|
|
* @param Client Client that wants to change the nickname.
|
2012-11-02 14:30:19 +01:00
|
|
|
* @param Nick New nickname.
|
2011-08-19 10:44:26 +02:00
|
|
|
* @returns true if nickname is valid, false otherwise.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2011-08-19 10:44:26 +02:00
|
|
|
Client_CheckNick(CLIENT *Client, char *Nick)
|
2001-12-26 15:45:37 +01:00
|
|
|
{
|
2011-08-19 10:44:26 +02:00
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Nick != NULL);
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2011-08-19 10:44:26 +02:00
|
|
|
if (!Client_IsValidNick(Nick)) {
|
2011-08-19 11:09:40 +02:00
|
|
|
if (strlen(Nick ) >= Conf_MaxNickLength)
|
|
|
|
IRC_WriteStrClient(Client, ERR_NICKNAMETOOLONG_MSG,
|
|
|
|
Client_ID(Client), Nick,
|
|
|
|
Conf_MaxNickLength - 1);
|
|
|
|
else
|
|
|
|
IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
|
|
|
|
Client_ID(Client), Nick);
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2002-02-17 20:02:49 +01:00
|
|
|
}
|
2001-12-26 15:45:37 +01:00
|
|
|
|
2012-08-26 12:33:21 +02:00
|
|
|
if (Client_Type(Client) != CLIENT_SERVER
|
|
|
|
&& Client_Type(Client) != CLIENT_SERVICE) {
|
2012-11-02 14:30:19 +01:00
|
|
|
/* Make sure that this isn't a restricted/forbidden nickname */
|
2012-08-26 12:33:21 +02:00
|
|
|
if (Conf_NickIsBlocked(Nick)) {
|
|
|
|
IRC_WriteStrClient(Client, ERR_FORBIDDENNICKNAME_MSG,
|
|
|
|
Client_ID(Client), Nick);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-19 10:44:26 +02:00
|
|
|
/* Nickname already registered? */
|
|
|
|
if (Client_Search(Nick)) {
|
|
|
|
IRC_WriteStrClient(Client, ERR_NICKNAMEINUSE_MSG,
|
|
|
|
Client_ID(Client), Nick);
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2001-12-26 15:45:37 +01:00
|
|
|
}
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2001-12-26 15:45:37 +01:00
|
|
|
} /* Client_CheckNick */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
|
|
|
Client_CheckID( CLIENT *Client, char *ID )
|
2002-01-03 03:28:06 +01:00
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
char str[COMMAND_LEN];
|
2002-01-03 03:28:06 +01:00
|
|
|
CLIENT *c;
|
|
|
|
|
|
|
|
assert( Client != NULL );
|
|
|
|
assert( Client->conn_id > NONE );
|
|
|
|
assert( ID != NULL );
|
|
|
|
|
2009-07-17 16:16:04 +02:00
|
|
|
/* ID too long? */
|
2009-04-20 08:34:09 +02:00
|
|
|
if (strlen(ID) > CLIENT_ID_LEN) {
|
|
|
|
IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), ID);
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2002-02-17 20:02:49 +01:00
|
|
|
}
|
2002-01-03 03:28:06 +01:00
|
|
|
|
2009-07-17 16:16:04 +02:00
|
|
|
/* ID already in use? */
|
2002-01-03 03:28:06 +01:00
|
|
|
c = My_Clients;
|
2009-04-20 08:34:09 +02:00
|
|
|
while (c) {
|
|
|
|
if (strcasecmp(c->id, ID) == 0) {
|
|
|
|
snprintf(str, sizeof(str), "ID \"%s\" already registered", ID);
|
2009-07-17 16:16:04 +02:00
|
|
|
if (c->conn_id != NONE)
|
2009-04-20 08:34:09 +02:00
|
|
|
Log(LOG_ERR, "%s (on connection %d)!", str, c->conn_id);
|
|
|
|
else
|
|
|
|
Log(LOG_ERR, "%s (via network)!", str);
|
|
|
|
Conn_Close(Client->conn_id, str, str, true);
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2002-01-03 03:28:06 +01:00
|
|
|
}
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2002-01-03 03:28:06 +01:00
|
|
|
}
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2002-01-03 03:28:06 +01:00
|
|
|
} /* Client_CheckID */
|
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_First( void )
|
2001-12-31 16:33:13 +01:00
|
|
|
{
|
|
|
|
return My_Clients;
|
|
|
|
} /* Client_First */
|
|
|
|
|
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
GLOBAL CLIENT *
|
|
|
|
Client_Next( CLIENT *c )
|
2001-12-31 16:33:13 +01:00
|
|
|
{
|
|
|
|
assert( c != NULL );
|
2002-03-25 20:11:01 +01:00
|
|
|
return (CLIENT *)c->next;
|
2001-12-31 16:33:13 +01:00
|
|
|
} /* Client_Next */
|
2002-01-16 23:10:35 +01:00
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_UserCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
return Count( CLIENT_USER );
|
|
|
|
} /* Client_UserCount */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_ServiceCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
return Count( CLIENT_SERVICE );;
|
|
|
|
} /* Client_ServiceCount */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_ServerCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
return Count( CLIENT_SERVER );
|
|
|
|
} /* Client_ServerCount */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_MyUserCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
return MyCount( CLIENT_USER );
|
|
|
|
} /* Client_MyUserCount */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_MyServiceCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
return MyCount( CLIENT_SERVICE );
|
|
|
|
} /* Client_MyServiceCount */
|
|
|
|
|
|
|
|
|
2006-10-07 12:40:52 +02:00
|
|
|
GLOBAL unsigned long
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_MyServerCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
2002-04-14 15:54:51 +02:00
|
|
|
CLIENT *c;
|
2006-12-07 23:24:14 +01:00
|
|
|
unsigned long cnt = 0;
|
2002-04-14 15:54:51 +02:00
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
|
|
|
if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
|
|
|
|
c = (CLIENT *)c->next;
|
|
|
|
}
|
|
|
|
return cnt;
|
2002-01-16 23:10:35 +01:00
|
|
|
} /* Client_MyServerCount */
|
|
|
|
|
|
|
|
|
2006-10-07 12:40:52 +02:00
|
|
|
GLOBAL unsigned long
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_OperCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2006-12-07 23:24:14 +01:00
|
|
|
unsigned long cnt = 0;
|
2002-01-16 23:10:35 +01:00
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
2013-08-04 18:25:24 +02:00
|
|
|
if (c && c->type == CLIENT_USER && Client_HasMode(c, 'o' ))
|
|
|
|
cnt++;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2002-01-16 23:10:35 +01:00
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
} /* Client_OperCount */
|
|
|
|
|
|
|
|
|
2006-10-07 12:40:52 +02:00
|
|
|
GLOBAL unsigned long
|
2005-03-19 19:43:48 +01:00
|
|
|
Client_UnknownCount( void )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2006-10-07 12:40:52 +02:00
|
|
|
unsigned long cnt = 0;
|
2002-01-16 23:10:35 +01:00
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
|
|
|
if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2002-01-16 23:10:35 +01:00
|
|
|
}
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2002-01-16 23:10:35 +01:00
|
|
|
return cnt;
|
|
|
|
} /* Client_UnknownCount */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_MaxUserCount( void )
|
2002-12-23 00:29:09 +01:00
|
|
|
{
|
|
|
|
return Max_Users;
|
|
|
|
} /* Client_MaxUserCount */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL long
|
|
|
|
Client_MyMaxUserCount( void )
|
2002-12-23 00:29:09 +01:00
|
|
|
{
|
|
|
|
return My_Max_Users;
|
|
|
|
} /* Client_MyMaxUserCount */
|
|
|
|
|
|
|
|
|
2011-08-19 10:44:26 +02:00
|
|
|
/**
|
|
|
|
* Check that a given nickname is valid.
|
|
|
|
*
|
|
|
|
* @param Nick the nickname to check.
|
|
|
|
* @returns true if nickname is valid, false otherwise.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2011-08-19 10:44:26 +02:00
|
|
|
Client_IsValidNick(const char *Nick)
|
2002-02-06 17:49:41 +01:00
|
|
|
{
|
2006-10-06 21:57:56 +02:00
|
|
|
const char *ptr;
|
|
|
|
static const char goodchars[] = ";0123456789-";
|
2002-03-02 02:35:50 +01:00
|
|
|
|
2011-08-19 10:44:26 +02:00
|
|
|
assert (Nick != NULL);
|
2002-02-06 17:49:41 +01:00
|
|
|
|
2011-08-19 10:44:26 +02:00
|
|
|
if (strchr(goodchars, Nick[0]))
|
|
|
|
return false;
|
|
|
|
if (strlen(Nick ) >= Conf_MaxNickLength)
|
|
|
|
return false;
|
2002-03-02 02:35:50 +01:00
|
|
|
|
|
|
|
ptr = Nick;
|
2011-08-19 10:44:26 +02:00
|
|
|
while (*ptr) {
|
|
|
|
if (*ptr < 'A' && !strchr(goodchars, *ptr ))
|
|
|
|
return false;
|
|
|
|
if (*ptr > '}')
|
|
|
|
return false;
|
2002-03-02 02:35:50 +01:00
|
|
|
ptr++;
|
|
|
|
}
|
2006-10-06 21:57:56 +02:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2002-02-06 17:49:41 +01:00
|
|
|
} /* Client_IsValidNick */
|
|
|
|
|
|
|
|
|
2005-05-16 14:23:48 +02:00
|
|
|
/**
|
|
|
|
* Return pointer to "My_Whowas" structure.
|
|
|
|
*/
|
|
|
|
GLOBAL WHOWAS *
|
|
|
|
Client_GetWhowas( void )
|
|
|
|
{
|
|
|
|
return My_Whowas;
|
|
|
|
} /* Client_GetWhowas */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the index of the last used WHOWAS entry.
|
|
|
|
*/
|
|
|
|
GLOBAL int
|
|
|
|
Client_GetLastWhowasIndex( void )
|
|
|
|
{
|
|
|
|
return Last_Whowas;
|
|
|
|
} /* Client_GetLastWhowasIndex */
|
|
|
|
|
|
|
|
|
2005-06-12 18:18:49 +02:00
|
|
|
/**
|
|
|
|
* Get the start time of this client.
|
|
|
|
* The result is the start time in seconds since 1970-01-01, as reported
|
|
|
|
* by the C function time(NULL).
|
|
|
|
*/
|
|
|
|
GLOBAL time_t
|
|
|
|
Client_StartTime(CLIENT *Client)
|
|
|
|
{
|
|
|
|
assert( Client != NULL );
|
|
|
|
return Client->starttime;
|
|
|
|
} /* Client_Uptime */
|
|
|
|
|
|
|
|
|
2012-01-22 18:17:28 +01:00
|
|
|
/**
|
|
|
|
* Reject a client when logging in.
|
|
|
|
*
|
|
|
|
* This function is called when a client isn't allowed to connect to this
|
|
|
|
* server. Possible reasons are bad server password, bad PAM password,
|
|
|
|
* or that the client is G/K-Line'd.
|
|
|
|
*
|
|
|
|
* After calling this function, the client isn't connected any more.
|
|
|
|
*
|
|
|
|
* @param Client The client to reject.
|
|
|
|
* @param Reason The reason why the client has been rejected.
|
|
|
|
* @param InformClient If true, send the exact reason to the client.
|
|
|
|
*/
|
|
|
|
GLOBAL void
|
|
|
|
Client_Reject(CLIENT *Client, const char *Reason, bool InformClient)
|
|
|
|
{
|
|
|
|
char info[COMMAND_LEN];
|
|
|
|
|
|
|
|
assert(Client != NULL);
|
|
|
|
assert(Reason != NULL);
|
|
|
|
|
|
|
|
if (InformClient)
|
|
|
|
snprintf(info, sizeof(info), "Access denied: %s", Reason);
|
|
|
|
else
|
|
|
|
strcpy(info, "Access denied: Bad password?");
|
|
|
|
|
|
|
|
Log(LOG_ERR,
|
|
|
|
"User \"%s\" rejected (connection %d): %s!",
|
|
|
|
Client_Mask(Client), Client_Conn(Client), Reason);
|
|
|
|
Conn_Close(Client_Conn(Client), Reason, info, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-31 15:24:30 +02:00
|
|
|
/**
|
|
|
|
* Introduce a new user or service client in the network.
|
|
|
|
*
|
|
|
|
* @param From Remote server introducing the client or NULL (local).
|
|
|
|
* @param Client New client.
|
|
|
|
* @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
|
|
|
|
*/
|
|
|
|
GLOBAL void
|
|
|
|
Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
|
|
|
|
{
|
|
|
|
/* Set client type (user or service) */
|
|
|
|
Client_SetType(Client, Type);
|
|
|
|
|
|
|
|
if (From) {
|
2012-08-26 12:27:51 +02:00
|
|
|
if (Conf_NickIsService(Conf_GetServer(Client_Conn(From)),
|
2012-03-31 15:24:30 +02:00
|
|
|
Client_ID(Client)))
|
|
|
|
Client_SetType(Client, CLIENT_SERVICE);
|
|
|
|
LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
|
|
|
|
Client_TypeText(Client), Client_Mask(Client),
|
|
|
|
Client_Modes(Client), Client_ID(From),
|
|
|
|
Client_ID(Client_Introducer(Client)),
|
|
|
|
Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
|
|
|
|
} else {
|
|
|
|
Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
|
|
|
|
Client_TypeText(Client), Client_Mask(Client),
|
|
|
|
Client_Conn(Client));
|
|
|
|
Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
|
|
|
|
Client_ID(Client), Client_User(Client),
|
|
|
|
Client_Hostname(Client),
|
|
|
|
Conn_IPA(Client_Conn(Client)),
|
|
|
|
Client_TypeText(Client));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Inform other servers */
|
|
|
|
IRC_WriteStrServersPrefixFlag_CB(From,
|
|
|
|
From != NULL ? From : Client_ThisServer(),
|
|
|
|
'\0', cb_introduceClient, (void *)Client);
|
|
|
|
} /* Client_Introduce */
|
|
|
|
|
|
|
|
|
2006-10-07 12:40:52 +02:00
|
|
|
static unsigned long
|
2002-05-27 15:09:26 +02:00
|
|
|
Count( CLIENT_TYPE Type )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2006-10-07 12:40:52 +02:00
|
|
|
unsigned long cnt = 0;
|
2002-01-16 23:10:35 +01:00
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
2002-04-14 15:54:51 +02:00
|
|
|
if( c->type == Type ) cnt++;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2002-01-16 23:10:35 +01:00
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
} /* Count */
|
|
|
|
|
|
|
|
|
2006-10-07 12:40:52 +02:00
|
|
|
static unsigned long
|
2002-05-27 15:09:26 +02:00
|
|
|
MyCount( CLIENT_TYPE Type )
|
2002-01-16 23:10:35 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2006-10-07 12:40:52 +02:00
|
|
|
unsigned long cnt = 0;
|
2002-01-16 23:10:35 +01:00
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
while( c )
|
|
|
|
{
|
2002-04-14 15:54:51 +02:00
|
|
|
if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
|
2002-03-25 20:11:01 +01:00
|
|
|
c = (CLIENT *)c->next;
|
2002-01-16 23:10:35 +01:00
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
} /* MyCount */
|
2001-12-31 16:33:13 +01:00
|
|
|
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static CLIENT *
|
2005-03-19 19:43:48 +01:00
|
|
|
New_Client_Struct( void )
|
2001-12-14 09:13:43 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2004-03-11 23:16:31 +01:00
|
|
|
c = (CLIENT *)malloc( sizeof( CLIENT ));
|
2001-12-14 09:13:43 +01:00
|
|
|
if( ! c )
|
|
|
|
{
|
2002-06-10 23:09:39 +02:00
|
|
|
Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
|
2001-12-14 09:13:43 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-01-20 01:11:49 +01:00
|
|
|
memset( c, 0, sizeof ( CLIENT ));
|
|
|
|
|
2001-12-14 09:13:43 +01:00
|
|
|
c->type = CLIENT_UNKNOWN;
|
|
|
|
c->conn_id = NONE;
|
2005-03-19 19:43:48 +01:00
|
|
|
c->oper_by_me = false;
|
2002-01-04 02:21:22 +01:00
|
|
|
c->hops = -1;
|
|
|
|
c->token = -1;
|
2002-01-08 00:42:12 +01:00
|
|
|
c->mytoken = -1;
|
2001-12-23 23:04:37 +01:00
|
|
|
|
2001-12-14 09:13:43 +01:00
|
|
|
return c;
|
|
|
|
} /* New_Client */
|
|
|
|
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2002-05-27 15:09:26 +02:00
|
|
|
Generate_MyToken( CLIENT *Client )
|
2002-01-08 00:42:12 +01:00
|
|
|
{
|
|
|
|
CLIENT *c;
|
2005-03-19 19:43:48 +01:00
|
|
|
int token;
|
2002-01-08 00:42:12 +01:00
|
|
|
|
|
|
|
c = My_Clients;
|
|
|
|
token = 2;
|
|
|
|
while( c )
|
|
|
|
{
|
|
|
|
if( c->mytoken == token )
|
|
|
|
{
|
2013-08-04 13:33:10 +02:00
|
|
|
/* The token is already in use */
|
2002-01-08 00:42:12 +01:00
|
|
|
token++;
|
|
|
|
c = My_Clients;
|
|
|
|
continue;
|
|
|
|
}
|
2002-03-25 20:11:01 +01:00
|
|
|
else c = (CLIENT *)c->next;
|
2002-01-08 00:42:12 +01:00
|
|
|
}
|
|
|
|
Client->mytoken = token;
|
2009-01-10 00:44:34 +01:00
|
|
|
LogDebug("Assigned token %d to server \"%s\".", token, Client->id);
|
2002-01-08 00:42:12 +01:00
|
|
|
} /* Generate_MyToken */
|
|
|
|
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2002-12-23 00:29:09 +01:00
|
|
|
Adjust_Counters( CLIENT *Client )
|
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
long count;
|
2002-12-23 00:29:09 +01:00
|
|
|
|
|
|
|
assert( Client != NULL );
|
|
|
|
|
|
|
|
if( Client->type != CLIENT_USER ) return;
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2002-12-23 00:29:09 +01:00
|
|
|
if( Client->conn_id != NONE )
|
|
|
|
{
|
|
|
|
/* Local connection */
|
|
|
|
count = Client_MyUserCount( );
|
|
|
|
if( count > My_Max_Users ) My_Max_Users = count;
|
|
|
|
}
|
|
|
|
count = Client_UserCount( );
|
|
|
|
if( count > Max_Users ) Max_Users = count;
|
|
|
|
} /* Adjust_Counters */
|
|
|
|
|
|
|
|
|
2005-05-16 14:23:48 +02:00
|
|
|
/**
|
|
|
|
* Register client in My_Whowas structure for further recall by WHOWAS.
|
2005-06-12 18:39:42 +02:00
|
|
|
* Note: Only clients that have been connected at least 30 seconds will be
|
|
|
|
* registered to prevent automated IRC bots to "destroy" a nice server
|
|
|
|
* history database.
|
2005-05-16 14:23:48 +02:00
|
|
|
*/
|
2005-05-18 01:18:54 +02:00
|
|
|
GLOBAL void
|
|
|
|
Client_RegisterWhowas( CLIENT *Client )
|
2005-05-16 14:23:48 +02:00
|
|
|
{
|
|
|
|
int slot;
|
2006-03-11 11:33:30 +01:00
|
|
|
time_t now;
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2005-05-16 14:23:48 +02:00
|
|
|
assert( Client != NULL );
|
|
|
|
|
2011-07-10 14:45:33 +02:00
|
|
|
/* Don't register WHOWAS information when "MorePrivacy" is enabled. */
|
|
|
|
if (Conf_MorePrivacy)
|
|
|
|
return;
|
|
|
|
|
2006-03-11 11:33:30 +01:00
|
|
|
now = time(NULL);
|
2005-06-12 18:39:42 +02:00
|
|
|
/* Don't register clients that were connected less than 30 seconds. */
|
2006-03-11 11:33:30 +01:00
|
|
|
if( now - Client->starttime < 30 )
|
2005-06-12 18:39:42 +02:00
|
|
|
return;
|
|
|
|
|
2005-05-16 14:23:48 +02:00
|
|
|
slot = Last_Whowas + 1;
|
|
|
|
if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
|
|
|
|
#endif
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2006-03-11 11:33:30 +01:00
|
|
|
My_Whowas[slot].time = now;
|
2005-05-16 14:23:48 +02:00
|
|
|
strlcpy( My_Whowas[slot].id, Client_ID( Client ),
|
|
|
|
sizeof( My_Whowas[slot].id ));
|
|
|
|
strlcpy( My_Whowas[slot].user, Client_User( Client ),
|
|
|
|
sizeof( My_Whowas[slot].user ));
|
2012-11-24 13:37:56 +01:00
|
|
|
strlcpy( My_Whowas[slot].host, Client_HostnameDisplayed( Client ),
|
2005-05-16 14:23:48 +02:00
|
|
|
sizeof( My_Whowas[slot].host ));
|
|
|
|
strlcpy( My_Whowas[slot].info, Client_Info( Client ),
|
|
|
|
sizeof( My_Whowas[slot].info ));
|
|
|
|
strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
|
|
|
|
sizeof( My_Whowas[slot].server ));
|
2006-10-07 12:40:52 +02:00
|
|
|
|
2005-05-16 14:23:48 +02:00
|
|
|
Last_Whowas = slot;
|
2005-05-18 01:18:54 +02:00
|
|
|
} /* Client_RegisterWhowas */
|
2005-05-16 14:23:48 +02:00
|
|
|
|
|
|
|
|
2010-06-26 00:31:08 +02:00
|
|
|
GLOBAL const char *
|
2008-08-16 17:19:27 +02:00
|
|
|
Client_TypeText(CLIENT *Client)
|
|
|
|
{
|
|
|
|
assert(Client != NULL);
|
|
|
|
switch (Client_Type(Client)) {
|
|
|
|
case CLIENT_USER:
|
|
|
|
return "User";
|
|
|
|
break;
|
|
|
|
case CLIENT_SERVICE:
|
|
|
|
return "Service";
|
|
|
|
break;
|
|
|
|
case CLIENT_SERVER:
|
|
|
|
return "Server";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "Client";
|
|
|
|
}
|
|
|
|
} /* Client_TypeText */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy user or service client.
|
|
|
|
*/
|
|
|
|
static void
|
2009-04-12 01:09:42 +02:00
|
|
|
Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool SendQuit)
|
2008-08-16 17:19:27 +02:00
|
|
|
{
|
|
|
|
if(Client->conn_id != NONE) {
|
|
|
|
/* Local (directly connected) client */
|
|
|
|
Log(LOG_NOTICE,
|
2013-01-26 16:52:41 +01:00
|
|
|
"%s \"%s\" unregistered (connection %d): %s.",
|
2008-08-16 17:19:27 +02:00
|
|
|
Client_TypeText(Client), Client_Mask(Client),
|
|
|
|
Client->conn_id, Txt);
|
2010-05-22 17:19:24 +02:00
|
|
|
Log_ServerNotice('c', "Client exiting: %s (%s@%s) [%s]",
|
|
|
|
Client_ID(Client), Client_User(Client),
|
|
|
|
Client_Hostname(Client), Txt);
|
2008-08-16 17:19:27 +02:00
|
|
|
|
|
|
|
if (SendQuit) {
|
|
|
|
/* Inforam all the other servers */
|
|
|
|
if (FwdMsg)
|
|
|
|
IRC_WriteStrServersPrefix(NULL,
|
|
|
|
Client, "QUIT :%s", FwdMsg );
|
|
|
|
else
|
|
|
|
IRC_WriteStrServersPrefix(NULL,
|
|
|
|
Client, "QUIT :");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Remote client */
|
2013-01-26 16:52:41 +01:00
|
|
|
LogDebug("%s \"%s\" unregistered: %s.",
|
2008-08-16 17:19:27 +02:00
|
|
|
Client_TypeText(Client), Client_Mask(Client), Txt);
|
|
|
|
|
|
|
|
if(SendQuit) {
|
|
|
|
/* Inform all the other servers, but the ones in the
|
|
|
|
* direction we got the QUIT from */
|
|
|
|
if(FwdMsg)
|
|
|
|
IRC_WriteStrServersPrefix(Client_NextHop(Client),
|
|
|
|
Client, "QUIT :%s", FwdMsg );
|
|
|
|
else
|
|
|
|
IRC_WriteStrServersPrefix(Client_NextHop(Client),
|
|
|
|
Client, "QUIT :" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unregister client from channels */
|
|
|
|
Channel_Quit(Client, FwdMsg ? FwdMsg : Client->id);
|
|
|
|
|
|
|
|
/* Register client in My_Whowas structure */
|
|
|
|
Client_RegisterWhowas(Client);
|
|
|
|
} /* Destroy_UserOrService */
|
|
|
|
|
|
|
|
|
2012-03-31 15:24:30 +02:00
|
|
|
/**
|
|
|
|
* Introduce a new user or service client to a remote server.
|
|
|
|
*
|
|
|
|
* @param To The remote server to inform.
|
|
|
|
* @param Prefix Prefix for the generated commands.
|
|
|
|
* @param data CLIENT structure of the new client.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data)
|
|
|
|
{
|
|
|
|
CLIENT *c = (CLIENT *)data;
|
2013-08-04 01:22:38 +02:00
|
|
|
|
|
|
|
(void)Client_Announce(To, Prefix, c);
|
|
|
|
|
|
|
|
} /* cb_introduceClient */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Announce an user or service to a server.
|
|
|
|
*
|
|
|
|
* This function differentiates between RFC1459 and RFC2813 server links and
|
|
|
|
* generates the appropriate commands to register the user or service.
|
|
|
|
*
|
|
|
|
* @param Client Server
|
|
|
|
* @param Prefix Prefix for the generated commands
|
|
|
|
* @param User User to announce
|
|
|
|
*/
|
|
|
|
GLOBAL bool
|
|
|
|
Client_Announce(CLIENT * Client, CLIENT * Prefix, CLIENT * User)
|
|
|
|
{
|
2012-03-31 15:24:30 +02:00
|
|
|
CONN_ID conn;
|
|
|
|
char *modes, *user, *host;
|
|
|
|
|
2013-08-04 01:22:38 +02:00
|
|
|
modes = Client_Modes(User);
|
|
|
|
user = Client_User(User) ? Client_User(User) : "-";
|
|
|
|
host = Client_Hostname(User) ? Client_Hostname(User) : "-";
|
2012-03-31 15:24:30 +02:00
|
|
|
|
2013-08-04 01:22:38 +02:00
|
|
|
conn = Client_Conn(Client);
|
2012-03-31 15:24:30 +02:00
|
|
|
if (Conn_Options(conn) & CONN_RFC1459) {
|
|
|
|
/* RFC 1459 mode: separate NICK and USER commands */
|
2013-08-04 01:22:38 +02:00
|
|
|
if (! Conn_WriteStr(conn, "NICK %s :%d",
|
|
|
|
Client_ID(User), Client_Hops(User) + 1))
|
|
|
|
return DISCONNECTED;
|
|
|
|
if (! Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
|
|
|
|
Client_ID(User), user, host,
|
|
|
|
Client_ID(Client_Introducer(User)),
|
|
|
|
Client_Info(User)))
|
|
|
|
return DISCONNECTED;
|
|
|
|
if (modes[0]) {
|
|
|
|
if (! Conn_WriteStr(conn, ":%s MODE %s +%s",
|
|
|
|
Client_ID(User), Client_ID(User),
|
|
|
|
modes))
|
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
2012-03-31 15:24:30 +02:00
|
|
|
} else {
|
|
|
|
/* RFC 2813 mode: one combined NICK or SERVICE command */
|
2013-08-04 01:22:38 +02:00
|
|
|
if (Client_Type(User) == CLIENT_SERVICE
|
2013-08-04 18:25:24 +02:00
|
|
|
&& Client_HasFlag(Client, 'S')) {
|
2013-08-04 01:22:38 +02:00
|
|
|
if (!IRC_WriteStrClientPrefix(Client, Prefix,
|
|
|
|
"SERVICE %s %d * +%s %d :%s",
|
|
|
|
Client_Mask(User),
|
|
|
|
Client_MyToken(Client_Introducer(User)),
|
|
|
|
modes, Client_Hops(User) + 1,
|
|
|
|
Client_Info(User)))
|
|
|
|
return DISCONNECTED;
|
|
|
|
} else {
|
|
|
|
if (!IRC_WriteStrClientPrefix(Client, Prefix,
|
|
|
|
"NICK %s %d %s %s %d +%s :%s",
|
|
|
|
Client_ID(User), Client_Hops(User) + 1,
|
|
|
|
user, host,
|
|
|
|
Client_MyToken(Client_Introducer(User)),
|
|
|
|
modes, Client_Info(User)))
|
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
2012-03-31 15:24:30 +02:00
|
|
|
}
|
2013-08-04 01:22:38 +02:00
|
|
|
|
2013-08-04 18:25:24 +02:00
|
|
|
if (Client_HasFlag(Client, 'M')) {
|
2013-08-04 01:22:38 +02:00
|
|
|
/* Synchronize metadata */
|
|
|
|
if (Client_HostnameCloaked(User)) {
|
|
|
|
if (!IRC_WriteStrClientPrefix(Client, Prefix,
|
|
|
|
"METADATA %s cloakhost :%s",
|
|
|
|
Client_ID(User),
|
|
|
|
Client_HostnameCloaked(User)))
|
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
|
|
|
|
2013-08-04 04:14:27 +02:00
|
|
|
if (Conn_GetCertFp(Client_Conn(User))) {
|
2013-08-04 01:22:38 +02:00
|
|
|
if (!IRC_WriteStrClientPrefix(Client, Prefix,
|
|
|
|
"METADATA %s certfp :%s",
|
|
|
|
Client_ID(User),
|
2013-08-04 04:14:27 +02:00
|
|
|
Conn_GetCertFp(Client_Conn(User))))
|
2013-08-04 01:22:38 +02:00
|
|
|
return DISCONNECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return CONNECTED;
|
|
|
|
} /* Client_Announce */
|
2012-03-31 15:24:30 +02:00
|
|
|
|
|
|
|
|
2008-04-09 19:03:24 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
GLOBAL void
|
|
|
|
Client_DebugDump(void)
|
|
|
|
{
|
|
|
|
CLIENT *c;
|
|
|
|
|
|
|
|
Log(LOG_DEBUG, "Client status:");
|
|
|
|
c = My_Clients;
|
|
|
|
while (c) {
|
|
|
|
Log(LOG_DEBUG,
|
2010-09-10 21:10:17 +02:00
|
|
|
" - %s: type=%d, host=%s, user=%s, conn=%d, start=%ld, flags=%s",
|
2008-04-09 19:03:24 +02:00
|
|
|
Client_ID(c), Client_Type(c), Client_Hostname(c),
|
|
|
|
Client_User(c), Client_Conn(c), Client_StartTime(c),
|
|
|
|
Client_Flags(c));
|
|
|
|
c = (CLIENT *)c->next;
|
|
|
|
}
|
|
|
|
} /* Client_DumpClients */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2001-12-14 09:13:43 +01:00
|
|
|
/* -eof- */
|