X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fclient.c;h=32690288529499097c0b6d88c1127774202f51bd;hp=d10775a88fad4a39ecb363dc7b6c433b5e497306;hb=3af0ece2bcf550cccd7b647c111ce503c2faa459;hpb=7fce71914287dc962d3c3cfdb7ebda7bfaa7311d diff --git a/src/ngircd/client.c b/src/ngircd/client.c index d10775a8..32690288 100644 --- a/src/ngircd/client.c +++ b/src/ngircd/client.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2013 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 @@ -41,6 +41,7 @@ #include "hash.h" #include "irc-write.h" #include "log.h" +#include "match.h" #include "messages.h" #include @@ -86,7 +87,7 @@ Client_Init( void ) exit( 1 ); } - /* Client-Struktur dieses Servers */ + /* Client structure for this server */ This_Server->next = NULL; This_Server->type = CLIENT_SERVER; This_Server->conn_id = NONE; @@ -123,6 +124,8 @@ Client_Exit( void ) { cnt++; next = (CLIENT *)c->next; + if (c->account_name) + free(c->account_name); free( c ); c = next; } @@ -216,7 +219,7 @@ Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer, if (Type == CLIENT_SERVER) Generate_MyToken(client); - if (strchr(client->modes, 'a')) + if (Client_HasMode(client, 'a')) strlcpy(client->away, DEFAULT_AWAY_MSG, sizeof(client->away)); client->next = (POINTER *)My_Clients; @@ -317,6 +320,10 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen } } + if (c->account_name) + free(c->account_name); + if (c->cloaked) + free(c->cloaked); free( c ); break; } @@ -451,6 +458,21 @@ Client_SetFlags( CLIENT *Client, const char *Flags ) } /* Client_SetFlags */ +GLOBAL void +Client_SetAccountName(CLIENT *Client, const char *AccountName) +{ + assert(Client != NULL); + + if (Client->account_name) + free(Client->account_name); + + if (*AccountName) + Client->account_name = strdup(AccountName); + else + Client->account_name = NULL; +} + + GLOBAL void Client_SetAway( CLIENT *Client, const char *Txt ) { @@ -512,7 +534,7 @@ GLOBAL bool Client_ModeAdd( CLIENT *Client, char Mode ) { /* Set Mode. - * If Client already alread had Mode, return false. + * If Client already had Mode, return false. * If the Mode was newly set, return true. */ @@ -521,7 +543,7 @@ Client_ModeAdd( CLIENT *Client, char Mode ) assert( Client != NULL ); x[0] = Mode; x[1] = '\0'; - if (!strchr( Client->modes, x[0])) { + if (!Client_HasMode(Client, x[0])) { strlcat( Client->modes, x, sizeof( Client->modes )); return true; } @@ -556,13 +578,14 @@ Client_ModeDel( CLIENT *Client, char Mode ) } /* Client_ModeDel */ +/** + * Search CLIENT structure of a given nick name. + * + * @return Pointer to CLIENT structure or NULL if not found. + */ GLOBAL CLIENT * Client_Search( const char *Nick ) { - /* return Client-Structure that has the corresponding Nick. - * If none is found, return NULL. - */ - char search_id[CLIENT_ID_LEN], *ptr; CLIENT *c = NULL; UINT32 search_hash; @@ -583,7 +606,39 @@ Client_Search( const char *Nick ) c = (CLIENT *)c->next; } return NULL; -} /* Client_Search */ +} + + +/** + * Search first CLIENT structure matching a given mask of a server. + * + * 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; +} /** @@ -710,8 +765,6 @@ Client_HostnameCloaked(CLIENT *Client) * Get (potentially cloaked) hostname of a client to display it to other users. * * 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 @@ -726,7 +779,7 @@ Client_HostnameDisplayed(CLIENT *Client) return Client_Hostname(Client); /* Use an already saved cloaked hostname, if there is one */ - if (Client->cloaked[0]) + if (Client->cloaked) return Client->cloaked; Client_UpdateCloakedHostname(Client, NULL, NULL); @@ -747,25 +800,32 @@ GLOBAL void Client_UpdateCloakedHostname(CLIENT *Client, CLIENT *Origin, const char *Hostname) { - static char Cloak_Buffer[CLIENT_HOST_LEN]; + char Cloak_Buffer[CLIENT_HOST_LEN]; assert(Client != NULL); if (!Origin) Origin = Client_ThisServer(); + if (!Client->cloaked) { + Client->cloaked = malloc(CLIENT_HOST_LEN); + if (!Client->cloaked) + return; + } + if (!Hostname) { /* Generate new cloaked hostname */ if (*Conf_CloakHostModeX) { - strlcpy(Cloak_Buffer, Client->host, CLIENT_HOST_LEN); + strlcpy(Cloak_Buffer, Client->host, + sizeof(Cloak_Buffer)); strlcat(Cloak_Buffer, Conf_CloakHostSalt, - CLIENT_HOST_LEN); - snprintf(Client->cloaked, sizeof(Client->cloaked), + sizeof(Cloak_Buffer)); + snprintf(Client->cloaked, CLIENT_HOST_LEN, Conf_CloakHostModeX, Hash(Cloak_Buffer)); } else strlcpy(Client->cloaked, Client_ID(Client->introducer), - sizeof(Client->cloaked)); + CLIENT_HOST_LEN); } else - strlcpy(Client->cloaked, Hostname, sizeof(Client->cloaked)); + strlcpy(Client->cloaked, Hostname, CLIENT_HOST_LEN); LogDebug("Cloaked hostname of \"%s\" updated to \"%s\"", Client_ID(Client), Client->cloaked); @@ -916,6 +976,14 @@ Client_HasMode( CLIENT *Client, char Mode ) } /* Client_HasMode */ +GLOBAL bool +Client_HasFlag( CLIENT *Client, char Flag ) +{ + assert( Client != NULL ); + return strchr( Client->flags, Flag ) != NULL; +} /* Client_HasFlag */ + + GLOBAL char * Client_Away( CLIENT *Client ) { @@ -924,6 +992,14 @@ Client_Away( CLIENT *Client ) } /* Client_Away */ +GLOBAL char * +Client_AccountName(CLIENT *Client) +{ + assert(Client != NULL); + return Client->account_name; +} + + /** * Make sure that a given nickname is valid. * @@ -942,11 +1018,11 @@ Client_CheckNick(CLIENT *Client, char *Nick) if (!Client_IsValidNick(Nick)) { if (strlen(Nick ) >= Conf_MaxNickLength) - IRC_WriteStrClient(Client, ERR_NICKNAMETOOLONG_MSG, + IRC_WriteErrClient(Client, ERR_NICKNAMETOOLONG_MSG, Client_ID(Client), Nick, Conf_MaxNickLength - 1); else - IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, + IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), Nick); return false; } @@ -955,7 +1031,7 @@ Client_CheckNick(CLIENT *Client, char *Nick) && Client_Type(Client) != CLIENT_SERVICE) { /* Make sure that this isn't a restricted/forbidden nickname */ if (Conf_NickIsBlocked(Nick)) { - IRC_WriteStrClient(Client, ERR_FORBIDDENNICKNAME_MSG, + IRC_WriteErrClient(Client, ERR_FORBIDDENNICKNAME_MSG, Client_ID(Client), Nick); return false; } @@ -963,7 +1039,7 @@ Client_CheckNick(CLIENT *Client, char *Nick) /* Nickname already registered? */ if (Client_Search(Nick)) { - IRC_WriteStrClient(Client, ERR_NICKNAMEINUSE_MSG, + IRC_WriteErrClient(Client, ERR_NICKNAMEINUSE_MSG, Client_ID(Client), Nick); return false; } @@ -984,7 +1060,8 @@ Client_CheckID( CLIENT *Client, char *ID ) /* ID too long? */ if (strlen(ID) > CLIENT_ID_LEN) { - IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), ID); + IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG, + Client_ID(Client), ID); return false; } @@ -1082,7 +1159,8 @@ Client_OperCount( void ) c = My_Clients; while( c ) { - if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++; + if (c && c->type == CLIENT_USER && Client_HasMode(c, 'o' )) + cnt++; c = (CLIENT *)c->next; } return cnt; @@ -1292,8 +1370,6 @@ MyCount( CLIENT_TYPE Type ) static CLIENT * New_Client_Struct( void ) { - /* Neue CLIENT-Struktur pre-initialisieren */ - CLIENT *c; c = (CLIENT *)malloc( sizeof( CLIENT )); @@ -1328,7 +1404,7 @@ Generate_MyToken( CLIENT *Client ) { if( c->mytoken == token ) { - /* Das Token wurde bereits vergeben */ + /* The token is already in use */ token++; c = My_Clients; continue; @@ -1479,9 +1555,6 @@ Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool /** * 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. @@ -1490,43 +1563,100 @@ static void cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data) { CLIENT *c = (CLIENT *)data; + + (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) +{ 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) : "-"; + modes = Client_Modes(User); + user = Client_User(User) ? Client_User(User) : "-"; + host = Client_Hostname(User) ? Client_Hostname(User) : "-"; - conn = Client_Conn(To); + conn = Client_Conn(Client); 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); + 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; + } } 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)); + if (Client_Type(User) == CLIENT_SERVICE + && Client_HasFlag(Client, 'S')) { + 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; + } } -} /* cb_introduceClient */ + + if (Client_HasFlag(Client, 'M')) { + /* Synchronize metadata */ + if (Client_HostnameCloaked(User)) { + if (!IRC_WriteStrClientPrefix(Client, Prefix, + "METADATA %s cloakhost :%s", + Client_ID(User), + Client_HostnameCloaked(User))) + return DISCONNECTED; + } + + if (Client_AccountName(User)) { + if (!IRC_WriteStrClientPrefix(Client, Prefix, + "METADATA %s accountname :%s", + Client_ID(User), + Client_AccountName(User))) + return DISCONNECTED; + } + + if (Conn_GetCertFp(Client_Conn(User))) { + if (!IRC_WriteStrClientPrefix(Client, Prefix, + "METADATA %s certfp :%s", + Client_ID(User), + Conn_GetCertFp(Client_Conn(User)))) + return DISCONNECTED; + } + } + + return CONNECTED; +} /* Client_Announce */ #ifdef DEBUG