X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fclient.c;h=07d448fdbaf9a84873f32e22584636251e2d3fd5;hp=37b168ff8d5dac07cb835b86eb37b366da6fcbe3;hb=bf2eae3249cd7890c0189dfcf1a50b0e40e199b2;hpb=0ad0fe207ab1705a2b042e7f47f1e0d8ce46e2a9 diff --git a/src/ngircd/client.c b/src/ngircd/client.c index 37b168ff..07d448fd 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-2014 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 @@ -18,22 +18,16 @@ * Client management. */ -#include "imp.h" #include #include #include #include #include #include +#include #include -#include "defines.h" #include "conn.h" - -#include "exp.h" -#include "client.h" - -#include #include "ngircd.h" #include "channel.h" #include "conf.h" @@ -44,8 +38,6 @@ #include "match.h" #include "messages.h" -#include - #define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1 static CLIENT *This_Server, *My_Clients; @@ -62,6 +54,8 @@ static CLIENT *New_Client_Struct PARAMS(( void )); static void Generate_MyToken PARAMS(( CLIENT *Client )); static void Adjust_Counters PARAMS(( CLIENT *Client )); +static void Free_Client PARAMS(( CLIENT **Client )); + static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer, int Type, const char *ID, const char *User, const char *Hostname, const char *Info, @@ -87,7 +81,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; @@ -120,14 +114,15 @@ Client_Exit( void ) cnt = 0; c = My_Clients; - while( c ) - { + while(c) { cnt++; next = (CLIENT *)c->next; - free( c ); + Free_Client(&c); c = next; } - if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" ); + if (cnt) + Log(LOG_INFO, "Freed %d client structure%s.", + cnt, cnt == 1 ? "" : "s"); } /* Client_Exit */ @@ -217,8 +212,8 @@ Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer, if (Type == CLIENT_SERVER) Generate_MyToken(client); - if (strchr(client->modes, 'a')) - strlcpy(client->away, DEFAULT_AWAY_MSG, sizeof(client->away)); + if (Client_HasMode(client, 'a')) + client->away = strndup(DEFAULT_AWAY_MSG, CLIENT_AWAY_LEN - 1); client->next = (POINTER *)My_Clients; My_Clients = client; @@ -235,7 +230,7 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen /* remove a client */ CLIENT *last, *c; - char msg[LINE_LEN]; + char msg[COMMAND_LEN]; const char *txt; assert( Client != NULL ); @@ -318,7 +313,7 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen } } - free( c ); + Free_Client(&c); break; } last = c; @@ -342,7 +337,7 @@ Client_SetHostname( CLIENT *Client, const char *Hostname ) assert(Client != NULL); assert(Hostname != NULL); - if (strlen(Conf_CloakHost)) { + if (Conf_CloakHost[0]) { char cloak[GETID_LEN]; strlcpy(cloak, Hostname, GETID_LEN); @@ -360,6 +355,27 @@ Client_SetHostname( CLIENT *Client, const char *Hostname ) } /* Client_SetHostname */ +/** + * Set IP address to display for a client. + * + * @param Client The client. + * @param IPAText Textual representation of the IP address or NULL to unset. + */ +GLOBAL void +Client_SetIPAText(CLIENT *Client, const char *IPAText) +{ + assert(Client != NULL); + + if (Client->ipa_text) + free(Client->ipa_text); + + if (*IPAText) + Client->ipa_text = strndup(IPAText, CLIENT_HOST_LEN - 1); + else + Client->ipa_text = NULL; +} + + GLOBAL void Client_SetID( CLIENT *Client, const char *ID ) { @@ -411,7 +427,7 @@ Client_SetOrigUser(CLIENT UNUSED *Client, const char UNUSED *User) assert(Client != NULL); assert(User != NULL); -#if defined(PAM) && defined(IDENTAUTH) +#if defined(PAM) strlcpy(Client->orig_user, User, sizeof(Client->orig_user)); #endif } /* Client_SetOrigUser */ @@ -452,6 +468,22 @@ 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 = strndup(AccountName, + CLIENT_NICK_LEN - 1); + else + Client->account_name = NULL; +} + + GLOBAL void Client_SetAway( CLIENT *Client, const char *Txt ) { @@ -460,7 +492,11 @@ Client_SetAway( CLIENT *Client, const char *Txt ) assert( Client != NULL ); assert( Txt != NULL ); - strlcpy( Client->away, Txt, sizeof( Client->away )); + if (Client->away) + free(Client->away); + + Client->away = strndup(Txt, CLIENT_AWAY_LEN - 1); + LogDebug("%s \"%s\" is away: %s", Client_TypeText(Client), Client_Mask(Client), Txt); } /* Client_SetAway */ @@ -501,19 +537,11 @@ Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer ) } /* Client_SetIntroducer */ -GLOBAL void -Client_SetOperByMe( CLIENT *Client, bool OperByMe ) -{ - assert( Client != NULL ); - Client->oper_by_me = OperByMe; -} /* Client_SetOperByMe */ - - 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. */ @@ -522,7 +550,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; } @@ -589,7 +617,7 @@ Client_Search( const char *Nick ) /** - * Serach first CLIENT structure matching a given mask of a server. + * 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. @@ -703,15 +731,7 @@ Client_User( CLIENT *Client ) */ 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 @@ -744,8 +764,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 @@ -760,13 +778,28 @@ 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); return Client->cloaked; } +GLOBAL const char * +Client_IPAText(CLIENT *Client) +{ + assert(Client != NULL); + + /* Not a local client? */ + if (Client_Conn(Client) <= NONE) + return "0.0.0.0"; + + if (!Client->ipa_text) + return Conn_GetIPAInfo(Client_Conn(Client)); + else + return Client->ipa_text; +} + /** * Update (and generate, if necessary) the cloaked hostname of a client. * @@ -781,25 +814,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); @@ -825,14 +865,6 @@ Client_Flags( CLIENT *Client ) } /* Client_Flags */ -GLOBAL bool -Client_OperByMe( CLIENT *Client ) -{ - assert( Client != NULL ); - return Client->oper_by_me; -} /* Client_OperByMe */ - - GLOBAL int Client_Hops( CLIENT *Client ) { @@ -950,6 +982,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 ) { @@ -958,6 +998,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. * @@ -976,11 +1024,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; } @@ -989,7 +1037,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; } @@ -997,7 +1045,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; } @@ -1018,7 +1066,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; } @@ -1116,7 +1165,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; @@ -1323,11 +1373,14 @@ MyCount( CLIENT_TYPE Type ) } /* MyCount */ +/** + * Allocate and initialize new CLIENT strcuture. + * + * @return Pointer to CLIENT structure or NULL on error. + */ static CLIENT * New_Client_Struct( void ) { - /* Neue CLIENT-Struktur pre-initialisieren */ - CLIENT *c; c = (CLIENT *)malloc( sizeof( CLIENT )); @@ -1341,14 +1394,34 @@ New_Client_Struct( void ) c->type = CLIENT_UNKNOWN; c->conn_id = NONE; - c->oper_by_me = false; c->hops = -1; c->token = -1; c->mytoken = -1; return c; -} /* New_Client */ +} +/** + * Free a CLIENT structure and its member variables. + */ +static void +Free_Client(CLIENT **Client) +{ + assert(Client != NULL); + assert(*Client != NULL); + + if ((*Client)->account_name) + free((*Client)->account_name); + if ((*Client)->away) + free((*Client)->away); + if ((*Client)->cloaked) + free((*Client)->cloaked); + if ((*Client)->ipa_text) + free((*Client)->ipa_text); + + free(*Client); + *Client = NULL; +} static void Generate_MyToken( CLIENT *Client ) @@ -1362,7 +1435,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; @@ -1513,9 +1586,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. @@ -1524,43 +1594,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