]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/client.c
Change cloaked hostname to be malloc'd on demand
[ngircd-alex.git] / src / ngircd / client.c
index d10775a88fad4a39ecb363dc7b6c433b5e497306..d70cfb4e3b307bf7b13f2be2e3939aa0f4f5f543 100644 (file)
@@ -41,6 +41,7 @@
 #include "hash.h"
 #include "irc-write.h"
 #include "log.h"
+#include "match.h"
 #include "messages.h"
 
 #include <exp.h>
@@ -317,6 +318,8 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen
                                }
                        }
 
+                       if (c->cloaked)
+                               free(c->cloaked);
                        free( c );
                        break;
                }
@@ -556,13 +559,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 +587,39 @@ Client_Search( const char *Nick )
                c = (CLIENT *)c->next;
        }
        return NULL;
-} /* Client_Search */
+}
+
+
+/**
+ * Serach 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 +746,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 +760,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 +781,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 +957,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 )
 {
@@ -1479,9 +1528,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 +1536,92 @@ 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
+                   && strchr(Client_Flags(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 (strchr(Client_Flags(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 (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