X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fclient.c;h=4728c7a4672ac802d944dc599d23031f75e50d60;hp=1a6ad931f8b128604296c17c2b3ebbac64bb7bc3;hb=33fae67579eeab31d7f96f9e53f0529f584b0b1f;hpb=71d8c371711f70e2d4b7ef9c908443a018cd6701 diff --git a/src/ngircd/client.c b/src/ngircd/client.c index 1a6ad931..4728c7a4 100644 --- a/src/ngircd/client.c +++ b/src/ngircd/client.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) * * 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 @@ -37,6 +37,7 @@ #include "ngircd.h" #include "channel.h" #include "conf.h" +#include "conn-func.h" #include "hash.h" #include "irc-write.h" #include "log.h" @@ -69,6 +70,8 @@ static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer, static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg, bool SendQuit)); +static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix, + void *i)); GLOBAL void Client_Init( void ) @@ -186,7 +189,6 @@ Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer, assert(Idx >= NONE); assert(Introducer != NULL); - assert(Hostname != NULL); client = New_Client_Struct(); if (!client) @@ -313,16 +315,35 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen } /* Client_Destroy */ +/** + * 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. + */ GLOBAL void Client_SetHostname( CLIENT *Client, const char *Hostname ) { - assert( Client != NULL ); - assert( Hostname != NULL ); + assert(Client != NULL); + assert(Hostname != NULL); + + if (strlen(Conf_CloakHost)) { + char cloak[GETID_LEN]; + + strlcpy(cloak, Hostname, GETID_LEN); + strlcat(cloak, Conf_CloakHostSalt, GETID_LEN); + snprintf(cloak, GETID_LEN, Conf_CloakHost, Hash(cloak)); - if (strlen(Conf_ClientHost)) { - strlcpy( Client->host, Conf_ClientHost, sizeof( Client->host )); + LogDebug("Updating hostname of \"%s\": \"%s\" -> \"%s\"", + Client_ID(Client), Client->host, cloak); + strlcpy(Client->host, cloak, sizeof(Client->host)); } else { - strlcpy( Client->host, Hostname, sizeof( Client->host )); + LogDebug("Updating hostname of \"%s\": \"%s\" -> \"%s\"", + Client_ID(Client), Client->host, Hostname); + strlcpy(Client->host, Hostname, sizeof(Client->host)); } } /* Client_SetHostname */ @@ -335,8 +356,10 @@ Client_SetID( CLIENT *Client, const char *ID ) strlcpy( Client->id, ID, sizeof( Client->id )); - if (Conf_ClientUserNick) + if (Conf_CloakUserToNick) { strlcpy( Client->user, ID, sizeof( Client->user )); + strlcpy( Client->info, ID, sizeof( Client->info )); + } /* Hash */ Client->hash = Hash( Client->id ); @@ -351,9 +374,9 @@ Client_SetUser( CLIENT *Client, const char *User, bool Idented ) assert( Client != NULL ); assert( User != NULL ); - if (Conf_ClientUserNick) return; - - if (Idented) { + if (Conf_CloakUserToNick) { + strlcpy(Client->user, Client->id, sizeof(Client->user)); + } else if (Idented) { strlcpy(Client->user, User, sizeof(Client->user)); } else { Client->user[0] = '~'; @@ -390,7 +413,10 @@ Client_SetInfo( CLIENT *Client, const char *Info ) assert( Client != NULL ); assert( Info != NULL ); - strlcpy(Client->info, Info, sizeof(Client->info)); + if (Conf_CloakUserToNick) + strlcpy(Client->info, Client->id, sizeof(Client->info)); + else + strlcpy(Client->info, Info, sizeof(Client->info)); } /* Client_SetInfo */ @@ -414,18 +440,6 @@ Client_SetFlags( CLIENT *Client, const char *Flags ) } /* Client_SetFlags */ -GLOBAL void -Client_SetPassword( CLIENT *Client, const char *Pwd ) -{ - /* set password sent by client */ - - assert( Client != NULL ); - assert( Pwd != NULL ); - - strlcpy(Client->pwd, Pwd, sizeof(Client->pwd)); -} /* Client_SetPassword */ - - GLOBAL void Client_SetAway( CLIENT *Client, const char *Txt ) { @@ -673,27 +687,36 @@ Client_Hostname(CLIENT *Client) /** * Get potentially cloaked hostname of a client. + * * If the client has not enabled cloaking, the real hostname is used. + * Please note that this function uses a global static buffer, so you can't + * nest invocations without overwriting earlier results! + * * @param Client Pointer to client structure * @return Pointer to client hostname */ GLOBAL char * Client_HostnameCloaked(CLIENT *Client) { + static char Cloak_Buffer[CLIENT_HOST_LEN]; + assert(Client != NULL); - if (Client_HasMode(Client, 'x')) - return Client_ID(Client->introducer); - else + + if (!Client_HasMode(Client, 'x')) return Client_Hostname(Client); -} /* Client_HostnameCloaked */ + /* Do simple mapping to the server ID? */ + if (!*Conf_CloakHostModeX) + return Client_ID(Client->introducer); -GLOBAL char * -Client_Password( CLIENT *Client ) -{ - assert( Client != NULL ); - return Client->pwd; -} /* Client_Password */ + strlcpy(Cloak_Buffer, Client->host, CLIENT_HOST_LEN); + strlcat(Cloak_Buffer, Conf_CloakHostSalt, CLIENT_HOST_LEN); + + snprintf(Cloak_Buffer, CLIENT_HOST_LEN, Conf_CloakHostModeX, + Hash(Cloak_Buffer)); + + return Cloak_Buffer; +} /* Client_HostnameCloaked */ GLOBAL char * @@ -763,7 +786,7 @@ Client_NextHop( CLIENT *Client ) * 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 - * nest invocations without overwriting erlier results! + * nest invocations without overwriting earlier results! * @param Client Pointer to client structure * @return Pointer to global buffer containing the client ID */ @@ -786,10 +809,12 @@ Client_Mask( CLIENT *Client ) /** * Return ID of a client with cloaked hostname: "client!user@server-name" + * * This client ID is used for IRC prefixes, for example. * Please note that this function uses a global static buffer, so you can't - * nest invocations without overwriting erlier results! + * nest invocations without overwriting earlier results! * If the client has not enabled cloaking, the real hostname is used. + * * @param Client Pointer to client structure * @return Pointer to global buffer containing the client ID */ @@ -802,10 +827,11 @@ Client_MaskCloaked(CLIENT *Client) /* Is the client using cloaking at all? */ if (!Client_HasMode(Client, 'x')) - return Client_Mask(Client); + return Client_Mask(Client); + + snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, + Client_HostnameCloaked(Client)); - snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s", - Client->id, Client->user, Client_ID(Client->introducer)); return Mask_Buffer; } /* Client_MaskCloaked */ @@ -842,23 +868,47 @@ Client_Away( CLIENT *Client ) } /* Client_Away */ +/** + * 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. + * @param Nick New nick name. + * @returns true if nickname is valid, false otherwise. + */ GLOBAL bool -Client_CheckNick( CLIENT *Client, char *Nick ) +Client_CheckNick(CLIENT *Client, char *Nick) { - assert( Client != NULL ); - assert( Nick != NULL ); - - if (! Client_IsValidNick( Nick )) - { - IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick ); + assert(Client != NULL); + assert(Nick != NULL); + + if (!Client_IsValidNick(Nick)) { + 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); return false; } - /* Nick bereits vergeben? */ - if( Client_Search( Nick )) - { - /* den Nick gibt es bereits */ - IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick ); + if (Client_Type(Client) != CLIENT_SERVER + && Client_Type(Client) != CLIENT_SERVICE) { + /* Make sure that this isn't a restricted/forbidden nick name */ + if (Conf_NickIsBlocked(Nick)) { + IRC_WriteStrClient(Client, ERR_FORBIDDENNICKNAME_MSG, + Client_ID(Client), Nick); + return false; + } + } + + /* Nickname already registered? */ + if (Client_Search(Nick)) { + IRC_WriteStrClient(Client, ERR_NICKNAMEINUSE_MSG, + Client_ID(Client), Nick); return false; } @@ -1014,23 +1064,31 @@ Client_MyMaxUserCount( void ) } /* Client_MyMaxUserCount */ +/** + * Check that a given nickname is valid. + * + * @param Nick the nickname to check. + * @returns true if nickname is valid, false otherwise. + */ GLOBAL bool -Client_IsValidNick( const char *Nick ) +Client_IsValidNick(const char *Nick) { const char *ptr; static const char goodchars[] = ";0123456789-"; - assert( Nick != NULL ); + assert (Nick != NULL); - if( Nick[0] == '#' ) return false; - if( strchr( goodchars, Nick[0] )) return false; - if( strlen( Nick ) >= Conf_MaxNickLength) return false; + if (strchr(goodchars, Nick[0])) + return false; + if (strlen(Nick ) >= Conf_MaxNickLength) + return false; ptr = Nick; - while( *ptr ) - { - if (( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false; - if ( *ptr > '}' ) return false; + while (*ptr) { + if (*ptr < 'A' && !strchr(goodchars, *ptr )) + return false; + if (*ptr > '}') + return false; ptr++; } @@ -1070,6 +1128,79 @@ Client_StartTime(CLIENT *Client) } /* Client_Uptime */ +/** + * 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); +} + + +/** + * 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) { + if (Conf_NickIsService(Conf_GetServer(Client_Conn(From)), + 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 */ + + static unsigned long Count( CLIENT_TYPE Type ) { @@ -1187,6 +1318,10 @@ Client_RegisterWhowas( CLIENT *Client ) assert( Client != NULL ); + /* Don't register WHOWAS information when "MorePrivacy" is enabled. */ + if (Conf_MorePrivacy) + return; + now = time(NULL); /* Don't register clients that were connected less than 30 seconds. */ if( now - Client->starttime < 30 ) @@ -1285,6 +1420,59 @@ Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool } /* Destroy_UserOrService */ +/** + * Introduce a new user or service client to a remote server. + * + * This function differentiates between RFC1459 and RFC2813 server links and + * generates the appropriate commands to register the new user or service. + * + * @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; + CONN_ID conn; + char *modes, *user, *host; + + modes = Client_Modes(c); + user = Client_User(c) ? Client_User(c) : "-"; + host = Client_Hostname(c) ? Client_Hostname(c) : "-"; + + conn = Client_Conn(To); + if (Conn_Options(conn) & CONN_RFC1459) { + /* RFC 1459 mode: separate NICK and USER commands */ + Conn_WriteStr(conn, "NICK %s :%d", Client_ID(c), + Client_Hops(c) + 1); + Conn_WriteStr(conn, ":%s USER %s %s %s :%s", + Client_ID(c), user, host, + Client_ID(Client_Introducer(c)), Client_Info(c)); + if (modes[0]) + Conn_WriteStr(conn, ":%s MODE %s +%s", + Client_ID(c), Client_ID(c), modes); + } else { + /* RFC 2813 mode: one combined NICK or SERVICE command */ + if (Client_Type(c) == CLIENT_SERVICE + && strchr(Client_Flags(To), 'S')) + IRC_WriteStrClientPrefix(To, Prefix, + "SERVICE %s %d * +%s %d :%s", + Client_Mask(c), + Client_MyToken(Client_Introducer(c)), + Client_Modes(c), Client_Hops(c) + 1, + Client_Info(c)); + else + IRC_WriteStrClientPrefix(To, Prefix, + "NICK %s %d %s %s %d +%s :%s", + Client_ID(c), Client_Hops(c) + 1, + user, host, + Client_MyToken(Client_Introducer(c)), + modes, Client_Info(c)); + } +} /* cb_introduceClient */ + + #ifdef DEBUG GLOBAL void