]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/client.c
ClientHost setting
[ngircd-alex.git] / src / ngircd / client.c
index 5ad412217e98eb615927d0620e8945d8c78030de..11decc8689584e116b6505a3369f20cbcd59f073 100644 (file)
@@ -1,22 +1,23 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2010 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
  * 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.
- *
- * Client management.
  */
 
-
 #define __client_c__
 
-
 #include "portab.h"
 
+/**
+ * @file
+ * Client management.
+ */
+
 #include "imp.h"
 #include <assert.h>
 #include <unistd.h>
@@ -35,7 +36,6 @@
 #include <imp.h>
 #include "ngircd.h"
 #include "channel.h"
-#include "resolve.h"
 #include "conf.h"
 #include "hash.h"
 #include "irc-write.h"
 
 #include <exp.h>
 
-
 #define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
 
-
 static CLIENT *This_Server, *My_Clients;
 
 static WHOWAS My_Whowas[MAX_WHOWAS];
@@ -94,7 +92,7 @@ Client_Init( void )
        This_Server->hops = 0;
 
        gethostname( This_Server->host, CLIENT_HOST_LEN );
-       if (!Conf_NoDNS) {
+       if (Conf_DNS) {
                h = gethostbyname( This_Server->host );
                if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
        }
@@ -181,42 +179,48 @@ Client_NewRemoteUser(CLIENT *Introducer, const char *Nick, int Hops, const char
  */
 static CLIENT *
 Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
int Type, const char *ID, const char *User, const char *Hostname, const char *Info, int Hops,
- int Token, const char *Modes, bool Idented)
 int Type, const char *ID, const char *User, const char *Hostname,
 const char *Info, int Hops, int Token, const char *Modes, bool Idented)
 {
        CLIENT *client;
 
-       assert( Idx >= NONE );
-       assert( Introducer != NULL );
-       assert( Hostname != NULL );
+       assert(Idx >= NONE);
+       assert(Introducer != NULL);
+       assert(Hostname != NULL);
 
-       client = New_Client_Struct( );
-       if( ! client ) return NULL;
+       client = New_Client_Struct();
+       if (!client)
+               return NULL;
 
-       /* Initialisieren */
        client->starttime = time(NULL);
        client->conn_id = Idx;
        client->introducer = Introducer;
        client->topserver = TopServer;
        client->type = Type;
-       if( ID ) Client_SetID( client, ID );
-       if( User ) Client_SetUser( client, User, Idented );
-       if( Hostname ) Client_SetHostname( client, Hostname );
-       if( Info ) Client_SetInfo( client, Info );
+       if (ID)
+               Client_SetID(client, ID);
+       if (User) {
+               Client_SetUser(client, User, Idented);
+               Client_SetOrigUser(client, User);
+       }
+       if (Hostname)
+               Client_SetHostname(client, Hostname);
+       if (Info)
+               Client_SetInfo(client, Info);
        client->hops = Hops;
        client->token = Token;
-       if( Modes ) Client_SetModes( client, Modes );
-       if( Type == CLIENT_SERVER ) Generate_MyToken( client );
+       if (Modes)
+               Client_SetModes(client, Modes);
+       if (Type == CLIENT_SERVER)
+               Generate_MyToken(client);
 
-       if( strchr( client->modes, 'a' ))
-               strlcpy( client->away, DEFAULT_AWAY_MSG, sizeof( client->away ));
+       if (strchr(client->modes, 'a'))
+               strlcpy(client->away, DEFAULT_AWAY_MSG, sizeof(client->away));
 
-       /* Verketten */
        client->next = (POINTER *)My_Clients;
        My_Clients = client;
 
-       /* Adjust counters */
-       Adjust_Counters( client );
+       Adjust_Counters(client);
 
        return client;
 } /* Init_New_Client */
@@ -225,7 +229,7 @@ Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
 GLOBAL void
 Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool SendQuit )
 {
-       /* Client entfernen. */
+       /* remove a client */
        
        CLIENT *last, *c;
        char msg[LINE_LEN];
@@ -237,7 +241,7 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen
        else txt = FwdMsg;
        if( ! txt ) txt = "Reason unknown.";
 
-       /* Netz-Split-Nachricht vorbereiten (noch nicht optimal) */
+       /* netsplit message */
        if( Client->type == CLIENT_SERVER ) {
                strlcpy(msg, This_Server->id, sizeof (msg));
                strlcat(msg, " ", sizeof (msg));
@@ -250,8 +254,16 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen
        {
                if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
                {
-                       /* der Client, der geloescht wird ist ein Server. Der Client, den wir gerade
-                        * pruefen, ist ein Child von diesem und muss daher auch entfernt werden */
+                       /*
+                        * 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.
+                        */
                        Client_Destroy( c, NULL, msg, false );
                        last = NULL;
                        c = My_Clients;
@@ -259,7 +271,7 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen
                }
                if( c == Client )
                {
-                       /* Wir haben den Client gefunden: entfernen */
+                       /* found  the client: remove it */
                        if( last ) last->next = c->next;
                        else My_Clients = (CLIENT *)c->next;
 
@@ -273,7 +285,7 @@ Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool Sen
                                        else Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered: %s", c->id, txt );
                                }
 
-                               /* andere Server informieren */
+                               /* inform other servers */
                                if( ! NGIRCd_SignalQuit )
                                {
                                        if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
@@ -307,7 +319,11 @@ Client_SetHostname( CLIENT *Client, const char *Hostname )
        assert( Client != NULL );
        assert( Hostname != NULL );
 
-       strlcpy( Client->host, Hostname, sizeof( Client->host ));
+       if (strlen(Conf_ClientHost)) {
+               strlcpy( Client->host, Conf_ClientHost, sizeof( Client->host ));
+       } else {
+               strlcpy( Client->host, Hostname, sizeof( Client->host ));
+       }
 } /* Client_SetHostname */
 
 
@@ -341,6 +357,26 @@ Client_SetUser( CLIENT *Client, const char *User, bool Idented )
 } /* Client_SetUser */
 
 
+/**
+ * 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
+Client_SetOrigUser(CLIENT UNUSED *Client, const char UNUSED *User)
+{
+       assert(Client != NULL);
+       assert(User != NULL);
+
+#if defined(PAM) && defined(IDENTAUTH)
+       strlcpy(Client->orig_user, User, sizeof(Client->orig_user));
+#endif
+} /* Client_SetOrigUser */
+
+
 GLOBAL void
 Client_SetInfo( CLIENT *Client, const char *Info )
 {
@@ -520,17 +556,19 @@ Client_Search( const char *Nick )
 } /* Client_Search */
 
 
+/**
+ * Get client structure ("introducer") identfied by a server token.
+ * @return CLIENT structure or NULL if none could be found.
+ */
 GLOBAL CLIENT *
 Client_GetFromToken( CLIENT *Client, int Token )
 {
-       /* Client-Struktur, die den entsprechenden Introducer (=Client)
-        * und das gegebene Token hat, liefern. Wird keine gefunden,
-        * so wird NULL geliefert. */
-
        CLIENT *c;
 
        assert( Client != NULL );
-       assert( Token > 0 );
+
+       if (!Token)
+               return NULL;
 
        c = My_Clients;
        while (c) {
@@ -590,14 +628,61 @@ Client_User( CLIENT *Client )
 } /* Client_User */
 
 
+#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
+
+
+/**
+ * Return the hostname of a client.
+ * @param Client Pointer to client structure
+ * @return Pointer to client hostname
+ */
 GLOBAL char *
-Client_Hostname( CLIENT *Client )
+Client_Hostname(CLIENT *Client)
 {
-       assert( Client != NULL );
+       assert (Client != NULL);
        return Client->host;
 } /* Client_Hostname */
 
 
+/**
+ * Get potentially cloaked hostname of a client.
+ * If the client has not enabled cloaking, the real hostname is used.
+ * @param Client Pointer to client structure
+ * @return Pointer to client hostname
+ */
+GLOBAL char *
+Client_HostnameCloaked(CLIENT *Client)
+{
+       assert(Client != NULL);
+       if (Client_HasMode(Client, 'x'))
+               return Client_ID(Client->introducer);
+       else
+               return Client_Hostname(Client);
+} /* Client_HostnameCloaked */
+
+
 GLOBAL char *
 Client_Password( CLIENT *Client )
 {
@@ -670,23 +755,56 @@ Client_NextHop( CLIENT *Client )
 
 
 /**
- * return Client-ID ("client!user@host"), this ID is needed for e.g.
- * prefixes.  Returnes pointer to static buffer.
+ * 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!
+ * @param Client Pointer to client structure
+ * @return Pointer to global buffer containing the client ID
  */
 GLOBAL char *
 Client_Mask( CLIENT *Client )
 {
-       static char GetID_Buffer[GETID_LEN];
+       static char Mask_Buffer[GETID_LEN];
 
-       assert( Client != NULL );
+       assert (Client != NULL);
 
-       if( Client->type == CLIENT_SERVER ) return Client->id;
+       /* Servers: return name only, there is no "mask" */
+       if (Client->type == CLIENT_SERVER)
+               return Client->id;
 
-       snprintf(GetID_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, Client->host);
-       return GetID_Buffer;
+       snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
+                Client->id, Client->user, Client->host);
+       return Mask_Buffer;
 } /* Client_Mask */
 
 
+/**
+ * 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!
+ * 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
+ */
+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'))
+           return Client_Mask(Client);
+
+       snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
+                Client->id, Client->user, Client_ID(Client->introducer));
+       return Mask_Buffer;
+} /* Client_MaskCloaked */
+
+
 GLOBAL CLIENT *
 Client_Introducer( CLIENT *Client )
 {
@@ -753,18 +871,18 @@ Client_CheckID( CLIENT *Client, char *ID )
        assert( Client->conn_id > NONE );
        assert( ID != NULL );
 
-       /* Nick too long? */
+       /* ID too long? */
        if (strlen(ID) > CLIENT_ID_LEN) {
                IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), ID);
                return false;
        }
 
-       /* does ID already exist? */
+       /* ID already in use? */
        c = My_Clients;
        while (c) {
                if (strcasecmp(c->id, ID) == 0) {
                        snprintf(str, sizeof(str), "ID \"%s\" already registered", ID);
-                       if (Client->conn_id != c->conn_id)
+                       if (c->conn_id != NONE)
                                Log(LOG_ERR, "%s (on connection %d)!", str, c->conn_id);
                        else
                                Log(LOG_ERR, "%s (via network)!", str);
@@ -1081,7 +1199,7 @@ Client_RegisterWhowas( CLIENT *Client )
                 sizeof( My_Whowas[slot].id ));
        strlcpy( My_Whowas[slot].user, Client_User( Client ),
                 sizeof( My_Whowas[slot].user ));
-       strlcpy( My_Whowas[slot].host, Client_Hostname( Client ),
+       strlcpy( My_Whowas[slot].host, Client_HostnameCloaked( Client ),
                 sizeof( My_Whowas[slot].host ));
        strlcpy( My_Whowas[slot].info, Client_Info( Client ),
                 sizeof( My_Whowas[slot].info ));
@@ -1092,7 +1210,7 @@ Client_RegisterWhowas( CLIENT *Client )
 } /* Client_RegisterWhowas */
 
 
-GLOBAL char *
+GLOBAL const char *
 Client_TypeText(CLIENT *Client)
 {
        assert(Client != NULL);
@@ -1124,6 +1242,9 @@ Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool
                    "%s \"%s\" unregistered (connection %d): %s",
                    Client_TypeText(Client), Client_Mask(Client),
                    Client->conn_id, Txt);
+               Log_ServerNotice('c', "Client exiting: %s (%s@%s) [%s]",
+                                Client_ID(Client), Client_User(Client),
+                                Client_Hostname(Client), Txt);
 
                if (SendQuit) {
                        /* Inforam all the other servers */
@@ -1159,4 +1280,26 @@ Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool
 } /* Destroy_UserOrService */
 
 
+#ifdef DEBUG
+
+GLOBAL void
+Client_DebugDump(void)
+{
+       CLIENT *c;
+
+       Log(LOG_DEBUG, "Client status:");
+       c = My_Clients;
+       while (c) {
+               Log(LOG_DEBUG,
+                   " - %s: type=%d, host=%s, user=%s, conn=%d, start=%ld, flags=%s",
+                   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
+
+
 /* -eof- */