[BACK]Return to client.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

Annotation of ircnowd/src/ngircd/client.c, Revision 1.1

1.1     ! tomglok     1: /*
        !             2:  * ngIRCd -- The Next Generation IRC Daemon
        !             3:  * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify
        !             6:  * it under the terms of the GNU General Public License as published by
        !             7:  * the Free Software Foundation; either version 2 of the License, or
        !             8:  * (at your option) any later version.
        !             9:  * Please read the file COPYING, README and AUTHORS for more information.
        !            10:  */
        !            11:
        !            12: #define __client_c__
        !            13:
        !            14: #include "portab.h"
        !            15:
        !            16: /**
        !            17:  * @file
        !            18:  * Client management.
        !            19:  */
        !            20:
        !            21: #include <assert.h>
        !            22: #include <unistd.h>
        !            23: #include <stdio.h>
        !            24: #include <stdlib.h>
        !            25: #include <string.h>
        !            26: #include <strings.h>
        !            27: #include <time.h>
        !            28: #include <netdb.h>
        !            29:
        !            30: #include "conn.h"
        !            31: #include "ngircd.h"
        !            32: #include "channel.h"
        !            33: #include "conf.h"
        !            34: #include "conn-func.h"
        !            35: #include "hash.h"
        !            36: #include "irc-write.h"
        !            37: #include "log.h"
        !            38: #include "match.h"
        !            39: #include "messages.h"
        !            40:
        !            41: #define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
        !            42:
        !            43: static CLIENT *This_Server, *My_Clients;
        !            44:
        !            45: static WHOWAS My_Whowas[MAX_WHOWAS];
        !            46: static int Last_Whowas = -1;
        !            47: static long Max_Users, My_Max_Users;
        !            48:
        !            49:
        !            50: static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
        !            51: static unsigned long MyCount PARAMS(( CLIENT_TYPE Type ));
        !            52:
        !            53: static CLIENT *New_Client_Struct PARAMS(( void ));
        !            54: static void Generate_MyToken PARAMS(( CLIENT *Client ));
        !            55: static void Adjust_Counters PARAMS(( CLIENT *Client ));
        !            56:
        !            57: static void Free_Client PARAMS(( CLIENT **Client ));
        !            58:
        !            59: static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
        !            60:                                       CLIENT *TopServer, int Type, const char *ID,
        !            61:                                       const char *User, const char *Hostname, const char *Info,
        !            62:                                       int Hops, int Token, const char *Modes,
        !            63:                                       bool Idented));
        !            64:
        !            65: static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
        !            66:                                        bool SendQuit));
        !            67:
        !            68: static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix,
        !            69:                                       void *i));
        !            70:
        !            71: GLOBAL void
        !            72: Client_Init( void )
        !            73: {
        !            74:        struct hostent *h;
        !            75:
        !            76:        This_Server = New_Client_Struct( );
        !            77:        if( ! This_Server )
        !            78:        {
        !            79:                Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
        !            80:                Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
        !            81:                exit( 1 );
        !            82:        }
        !            83:
        !            84:        /* Client structure for this server */
        !            85:        This_Server->next = NULL;
        !            86:        This_Server->type = CLIENT_SERVER;
        !            87:        This_Server->conn_id = NONE;
        !            88:        This_Server->introducer = This_Server;
        !            89:        This_Server->mytoken = 1;
        !            90:        This_Server->hops = 0;
        !            91:
        !            92:        gethostname( This_Server->host, CLIENT_HOST_LEN );
        !            93:        if (Conf_DNS) {
        !            94:                h = gethostbyname( This_Server->host );
        !            95:                if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
        !            96:        }
        !            97:        Client_SetID( This_Server, Conf_ServerName );
        !            98:        Client_SetInfo( This_Server, Conf_ServerInfo );
        !            99:
        !           100:        My_Clients = This_Server;
        !           101:
        !           102:        memset( &My_Whowas, 0, sizeof( My_Whowas ));
        !           103: } /* Client_Init */
        !           104:
        !           105:
        !           106: GLOBAL void
        !           107: Client_Exit( void )
        !           108: {
        !           109:        CLIENT *c, *next;
        !           110:        int cnt;
        !           111:
        !           112:        if( NGIRCd_SignalRestart ) Client_Destroy( This_Server, "Server going down (restarting).", NULL, false );
        !           113:        else Client_Destroy( This_Server, "Server going down.", NULL, false );
        !           114:
        !           115:        cnt = 0;
        !           116:        c = My_Clients;
        !           117:        while(c) {
        !           118:                cnt++;
        !           119:                next = (CLIENT *)c->next;
        !           120:                Free_Client(&c);
        !           121:                c = next;
        !           122:        }
        !           123:        if (cnt)
        !           124:                Log(LOG_INFO, "Freed %d client structure%s.",
        !           125:                    cnt, cnt == 1 ? "" : "s");
        !           126: } /* Client_Exit */
        !           127:
        !           128:
        !           129: GLOBAL CLIENT *
        !           130: Client_ThisServer( void )
        !           131: {
        !           132:        return This_Server;
        !           133: } /* Client_ThisServer */
        !           134:
        !           135:
        !           136: /**
        !           137:  * Initialize new local client; wrapper function for Init_New_Client().
        !           138:  * @return New CLIENT structure.
        !           139:  */
        !           140: GLOBAL CLIENT *
        !           141: Client_NewLocal(CONN_ID Idx, const char *Hostname, int Type, bool Idented)
        !           142: {
        !           143:        return Init_New_Client(Idx, This_Server, NULL, Type, NULL, NULL,
        !           144:                Hostname, NULL, 0, 0, NULL, Idented);
        !           145: } /* Client_NewLocal */
        !           146:
        !           147:
        !           148: /**
        !           149:  * Initialize new remote server; wrapper function for Init_New_Client().
        !           150:  * @return New CLIENT structure.
        !           151:  */
        !           152: GLOBAL CLIENT *
        !           153: Client_NewRemoteServer(CLIENT *Introducer, const char *Hostname, CLIENT *TopServer,
        !           154:  int Hops, int Token, const char *Info, bool Idented)
        !           155: {
        !           156:        return Init_New_Client(NONE, Introducer, TopServer, CLIENT_SERVER,
        !           157:                Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented);
        !           158: } /* Client_NewRemoteServer */
        !           159:
        !           160:
        !           161: /**
        !           162:  * Initialize new remote client; wrapper function for Init_New_Client().
        !           163:  * @return New CLIENT structure.
        !           164:  */
        !           165: GLOBAL CLIENT *
        !           166: Client_NewRemoteUser(CLIENT *Introducer, const char *Nick, int Hops, const char *User,
        !           167:  const char *Hostname, int Token, const char *Modes, const char *Info, bool Idented)
        !           168: {
        !           169:        return Init_New_Client(NONE, Introducer, NULL, CLIENT_USER, Nick,
        !           170:                User, Hostname, Info, Hops, Token, Modes, Idented);
        !           171: } /* Client_NewRemoteUser */
        !           172:
        !           173:
        !           174: /**
        !           175:  * Initialize new client and set up the given parameters like client type,
        !           176:  * user name, host name, introducing server etc. ...
        !           177:  * @return New CLIENT structure.
        !           178:  */
        !           179: static CLIENT *
        !           180: Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
        !           181:   int Type, const char *ID, const char *User, const char *Hostname,
        !           182:   const char *Info, int Hops, int Token, const char *Modes, bool Idented)
        !           183: {
        !           184:        CLIENT *client;
        !           185:
        !           186:        assert(Idx >= NONE);
        !           187:        assert(Introducer != NULL);
        !           188:
        !           189:        client = New_Client_Struct();
        !           190:        if (!client)
        !           191:                return NULL;
        !           192:
        !           193:        client->starttime = time(NULL);
        !           194:        client->conn_id = Idx;
        !           195:        client->introducer = Introducer;
        !           196:        client->topserver = TopServer;
        !           197:        client->type = Type;
        !           198:        if (ID)
        !           199:                Client_SetID(client, ID);
        !           200:        if (User) {
        !           201:                Client_SetUser(client, User, Idented);
        !           202:                Client_SetOrigUser(client, User);
        !           203:        }
        !           204:        if (Hostname)
        !           205:                Client_SetHostname(client, Hostname);
        !           206:        if (Info)
        !           207:                Client_SetInfo(client, Info);
        !           208:        client->hops = Hops;
        !           209:        client->token = Token;
        !           210:        if (Modes)
        !           211:                Client_SetModes(client, Modes);
        !           212:        if (Type == CLIENT_SERVER)
        !           213:                Generate_MyToken(client);
        !           214:
        !           215:        if (Client_HasMode(client, 'a'))
        !           216:                client->away = strndup(DEFAULT_AWAY_MSG, CLIENT_AWAY_LEN - 1);
        !           217:
        !           218:        client->next = (POINTER *)My_Clients;
        !           219:        My_Clients = client;
        !           220:
        !           221:        Adjust_Counters(client);
        !           222:
        !           223:        return client;
        !           224: } /* Init_New_Client */
        !           225:
        !           226:
        !           227: GLOBAL void
        !           228: Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool SendQuit )
        !           229: {
        !           230:        /* remove a client */
        !           231:
        !           232:        CLIENT *last, *c;
        !           233:        char msg[COMMAND_LEN];
        !           234:        const char *txt;
        !           235:
        !           236:        assert( Client != NULL );
        !           237:
        !           238:        txt = LogMsg ? LogMsg : FwdMsg;
        !           239:        if (!txt)
        !           240:                txt = "Reason unknown";
        !           241:
        !           242:        /* netsplit message */
        !           243:        if( Client->type == CLIENT_SERVER ) {
        !           244:                strlcpy(msg, This_Server->id, sizeof (msg));
        !           245:                strlcat(msg, " ", sizeof (msg));
        !           246:                strlcat(msg, Client->id, sizeof (msg));
        !           247:        }
        !           248:
        !           249:        last = NULL;
        !           250:        c = My_Clients;
        !           251:        while( c )
        !           252:        {
        !           253:                if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
        !           254:                {
        !           255:                        /*
        !           256:                         * The client that is about to be removed is a server,
        !           257:                         * the client we are checking right now is a child of that
        !           258:                         * server and thus has to be removed, too.
        !           259:                         *
        !           260:                         * Call Client_Destroy() recursively with the server as the
        !           261:                         * new "object to be removed". This starts the cycle again, until
        !           262:                         * all servers that are linked via the original server have been
        !           263:                         * removed.
        !           264:                         */
        !           265:                        Client_Destroy( c, NULL, msg, false );
        !           266:                        last = NULL;
        !           267:                        c = My_Clients;
        !           268:                        continue;
        !           269:                }
        !           270:                if( c == Client )
        !           271:                {
        !           272:                        /* found  the client: remove it */
        !           273:                        if( last ) last->next = c->next;
        !           274:                        else My_Clients = (CLIENT *)c->next;
        !           275:
        !           276:                        if(c->type == CLIENT_USER || c->type == CLIENT_SERVICE)
        !           277:                                Destroy_UserOrService(c, txt, FwdMsg, SendQuit);
        !           278:                        else if( c->type == CLIENT_SERVER )
        !           279:                        {
        !           280:                                if (c != This_Server) {
        !           281:                                        if (c->conn_id != NONE)
        !           282:                                                Log(LOG_NOTICE|LOG_snotice,
        !           283:                                                    "Server \"%s\" unregistered (connection %d): %s.",
        !           284:                                                c->id, c->conn_id, txt);
        !           285:                                        else
        !           286:                                                Log(LOG_NOTICE|LOG_snotice,
        !           287:                                                    "Server \"%s\" unregistered: %s.",
        !           288:                                                    c->id, txt);
        !           289:                                }
        !           290:
        !           291:                                /* inform other servers */
        !           292:                                if( ! NGIRCd_SignalQuit )
        !           293:                                {
        !           294:                                        if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
        !           295:                                        else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
        !           296:                                }
        !           297:                        }
        !           298:                        else
        !           299:                        {
        !           300:                                if (c->conn_id != NONE) {
        !           301:                                        if (c->id[0])
        !           302:                                                Log(LOG_NOTICE,
        !           303:                                                    "Client \"%s\" unregistered (connection %d): %s.",
        !           304:                                                    c->id, c->conn_id, txt);
        !           305:                                        else
        !           306:                                                Log(LOG_NOTICE,
        !           307:                                                    "Client unregistered (connection %d): %s.",
        !           308:                                                    c->conn_id, txt);
        !           309:                                } else {
        !           310:                                        Log(LOG_WARNING,
        !           311:                                            "Unregistered unknown client \"%s\": %s",
        !           312:                                            c->id[0] ? c->id : "(No Nick)", txt);
        !           313:                                }
        !           314:                        }
        !           315:
        !           316:                        Free_Client(&c);
        !           317:                        break;
        !           318:                }
        !           319:                last = c;
        !           320:                c = (CLIENT *)c->next;
        !           321:        }
        !           322: } /* Client_Destroy */
        !           323:
        !           324:
        !           325: /**
        !           326:  * Set client hostname.
        !           327:  *
        !           328:  * If global hostname cloaking is in effect, don't set the real hostname
        !           329:  * but the configured one.
        !           330:  *
        !           331:  * @param Client The client of which the hostname should be set.
        !           332:  * @param Hostname The new hostname.
        !           333:  */
        !           334: GLOBAL void
        !           335: Client_SetHostname( CLIENT *Client, const char *Hostname )
        !           336: {
        !           337:        assert(Client != NULL);
        !           338:        assert(Hostname != NULL);
        !           339:
        !           340:        /* Only cloak the hostmask if it has not yet been cloaked.
        !           341:         * The period or colon indicates it's still an IP address.
        !           342:         * An empty string means a rDNS lookup did not happen (yet). */
        !           343:        if (Conf_CloakHost[0] && (!Client->host[0] || strchr(Client->host, '.')
        !           344:                                  || strchr(Client->host, ':'))) {
        !           345:                char cloak[GETID_LEN];
        !           346:
        !           347:                strlcpy(cloak, Hostname, GETID_LEN);
        !           348:                strlcat(cloak, Conf_CloakHostSalt, GETID_LEN);
        !           349:                snprintf(cloak, GETID_LEN, Conf_CloakHost, Hash(cloak));
        !           350:
        !           351:                LogDebug("Updating hostname of \"%s\": \"%s\" -> \"%s\"",
        !           352:                        Client_ID(Client), Client->host, cloak);
        !           353:                strlcpy(Client->host, cloak, sizeof(Client->host));
        !           354:        } else {
        !           355:                LogDebug("Updating hostname of \"%s\": \"%s\" -> \"%s\"",
        !           356:                         Client_ID(Client), Client->host, Hostname);
        !           357:                strlcpy(Client->host, Hostname, sizeof(Client->host));
        !           358:        }
        !           359: } /* Client_SetHostname */
        !           360:
        !           361:
        !           362: /**
        !           363:  * Set IP address to display for a client.
        !           364:  *
        !           365:  * @param Client The client.
        !           366:  * @param IPAText Textual representation of the IP address or NULL to unset.
        !           367:  */
        !           368: GLOBAL void
        !           369: Client_SetIPAText(CLIENT *Client, const char *IPAText)
        !           370: {
        !           371:        assert(Client != NULL);
        !           372:
        !           373:        if (Client->ipa_text)
        !           374:                free(Client->ipa_text);
        !           375:
        !           376:        if (*IPAText)
        !           377:                Client->ipa_text = strndup(IPAText, CLIENT_HOST_LEN - 1);
        !           378:        else
        !           379:                Client->ipa_text = NULL;
        !           380: }
        !           381:
        !           382:
        !           383: GLOBAL void
        !           384: Client_SetID( CLIENT *Client, const char *ID )
        !           385: {
        !           386:        assert( Client != NULL );
        !           387:        assert( ID != NULL );
        !           388:
        !           389:        strlcpy( Client->id, ID, sizeof( Client->id ));
        !           390:
        !           391:        if (Conf_CloakUserToNick) {
        !           392:                strlcpy( Client->user, ID, sizeof( Client->user ));
        !           393:                strlcpy( Client->info, ID, sizeof( Client->info ));
        !           394:        }
        !           395:
        !           396:        /* Hash */
        !           397:        Client->hash = Hash( Client->id );
        !           398: } /* Client_SetID */
        !           399:
        !           400:
        !           401: GLOBAL void
        !           402: Client_SetUser( CLIENT *Client, const char *User, bool Idented )
        !           403: {
        !           404:        /* set clients username */
        !           405:
        !           406:        assert( Client != NULL );
        !           407:        assert( User != NULL );
        !           408:
        !           409:        if (Conf_CloakUserToNick) {
        !           410:                strlcpy(Client->user, Client->id, sizeof(Client->user));
        !           411:        } else if (Idented) {
        !           412:                strlcpy(Client->user, User, sizeof(Client->user));
        !           413:        } else {
        !           414:                Client->user[0] = '~';
        !           415:                strlcpy(Client->user + 1, User, sizeof(Client->user) - 1);
        !           416:        }
        !           417: } /* Client_SetUser */
        !           418:
        !           419:
        !           420: /**
        !           421:  * Set "original" user name of a client.
        !           422:  * This function saves the "original" user name, the user name specified by
        !           423:  * the peer using the USER command, into the CLIENT structure. This user
        !           424:  * name may be used for authentication, for example.
        !           425:  * @param Client The client.
        !           426:  * @param User User name to set.
        !           427:  */
        !           428: GLOBAL void
        !           429: Client_SetOrigUser(CLIENT UNUSED *Client, const char UNUSED *User)
        !           430: {
        !           431:        assert(Client != NULL);
        !           432:        assert(User != NULL);
        !           433:
        !           434: #if defined(PAM)
        !           435:        strlcpy(Client->orig_user, User, sizeof(Client->orig_user));
        !           436: #endif
        !           437: } /* Client_SetOrigUser */
        !           438:
        !           439:
        !           440: GLOBAL void
        !           441: Client_SetInfo( CLIENT *Client, const char *Info )
        !           442: {
        !           443:        /* set client hostname */
        !           444:
        !           445:        assert( Client != NULL );
        !           446:        assert( Info != NULL );
        !           447:
        !           448:        if (Conf_CloakUserToNick)
        !           449:                strlcpy(Client->info, Client->id, sizeof(Client->info));
        !           450:        else
        !           451:                strlcpy(Client->info, Info, sizeof(Client->info));
        !           452: } /* Client_SetInfo */
        !           453:
        !           454:
        !           455: GLOBAL void
        !           456: Client_SetModes( CLIENT *Client, const char *Modes )
        !           457: {
        !           458:        assert( Client != NULL );
        !           459:        assert( Modes != NULL );
        !           460:
        !           461:        strlcpy(Client->modes, Modes, sizeof( Client->modes ));
        !           462: } /* Client_SetModes */
        !           463:
        !           464:
        !           465: GLOBAL void
        !           466: Client_SetFlags( CLIENT *Client, const char *Flags )
        !           467: {
        !           468:        assert( Client != NULL );
        !           469:        assert( Flags != NULL );
        !           470:
        !           471:        strlcpy(Client->flags, Flags, sizeof(Client->flags));
        !           472: } /* Client_SetFlags */
        !           473:
        !           474:
        !           475: GLOBAL void
        !           476: Client_SetAccountName(CLIENT *Client, const char *AccountName)
        !           477: {
        !           478:        assert(Client != NULL);
        !           479:
        !           480:        if (Client->account_name)
        !           481:                free(Client->account_name);
        !           482:
        !           483:        if (*AccountName)
        !           484:                Client->account_name = strndup(AccountName,
        !           485:                                               CLIENT_NICK_LEN - 1);
        !           486:        else
        !           487:                Client->account_name = NULL;
        !           488: }
        !           489:
        !           490:
        !           491: GLOBAL void
        !           492: Client_SetAway( CLIENT *Client, const char *Txt )
        !           493: {
        !           494:        /* Set AWAY reason of client */
        !           495:
        !           496:        assert( Client != NULL );
        !           497:        assert( Txt != NULL );
        !           498:
        !           499:        if (Client->away)
        !           500:                free(Client->away);
        !           501:
        !           502:        Client->away = strndup(Txt, CLIENT_AWAY_LEN - 1);
        !           503:
        !           504:        LogDebug("%s \"%s\" is away: %s", Client_TypeText(Client),
        !           505:                 Client_Mask(Client), Txt);
        !           506: } /* Client_SetAway */
        !           507:
        !           508:
        !           509: GLOBAL void
        !           510: Client_SetType( CLIENT *Client, int Type )
        !           511: {
        !           512:        assert( Client != NULL );
        !           513:        Client->type = Type;
        !           514:        if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
        !           515:        Adjust_Counters( Client );
        !           516: } /* Client_SetType */
        !           517:
        !           518:
        !           519: GLOBAL void
        !           520: Client_SetHops( CLIENT *Client, int Hops )
        !           521: {
        !           522:        assert( Client != NULL );
        !           523:        Client->hops = Hops;
        !           524: } /* Client_SetHops */
        !           525:
        !           526:
        !           527: GLOBAL void
        !           528: Client_SetToken( CLIENT *Client, int Token )
        !           529: {
        !           530:        assert( Client != NULL );
        !           531:        Client->token = Token;
        !           532: } /* Client_SetToken */
        !           533:
        !           534:
        !           535: GLOBAL void
        !           536: Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
        !           537: {
        !           538:        assert( Client != NULL );
        !           539:        assert( Introducer != NULL );
        !           540:        Client->introducer = Introducer;
        !           541: } /* Client_SetIntroducer */
        !           542:
        !           543:
        !           544: GLOBAL bool
        !           545: Client_ModeAdd( CLIENT *Client, char Mode )
        !           546: {
        !           547:        /* Set Mode.
        !           548:         * If Client already had Mode, return false.
        !           549:         * If the Mode was newly set, return true.
        !           550:         */
        !           551:
        !           552:        char x[2];
        !           553:
        !           554:        assert( Client != NULL );
        !           555:
        !           556:        x[0] = Mode; x[1] = '\0';
        !           557:        if (!Client_HasMode(Client, x[0])) {
        !           558:                strlcat( Client->modes, x, sizeof( Client->modes ));
        !           559:                return true;
        !           560:        }
        !           561:        else return false;
        !           562: } /* Client_ModeAdd */
        !           563:
        !           564:
        !           565: GLOBAL bool
        !           566: Client_ModeDel( CLIENT *Client, char Mode )
        !           567: {
        !           568:        /* Delete Mode.
        !           569:         * If Mode was removed, return true.
        !           570:         * If Client did not have Mode, return false.
        !           571:         */
        !           572:
        !           573:        char x[2], *p;
        !           574:
        !           575:        assert( Client != NULL );
        !           576:
        !           577:        x[0] = Mode; x[1] = '\0';
        !           578:
        !           579:        p = strchr( Client->modes, x[0] );
        !           580:        if( ! p ) return false;
        !           581:
        !           582:        /* Client has Mode -> delete */
        !           583:        while( *p )
        !           584:        {
        !           585:                *p = *(p + 1);
        !           586:                p++;
        !           587:        }
        !           588:        return true;
        !           589: } /* Client_ModeDel */
        !           590:
        !           591:
        !           592: /**
        !           593:  * Search CLIENT structure of a given nick name.
        !           594:  *
        !           595:  * @return Pointer to CLIENT structure or NULL if not found.
        !           596:  */
        !           597: GLOBAL CLIENT *
        !           598: Client_Search( const char *Nick )
        !           599: {
        !           600:        char search_id[CLIENT_ID_LEN], *ptr;
        !           601:        CLIENT *c = NULL;
        !           602:        UINT32 search_hash;
        !           603:
        !           604:        assert( Nick != NULL );
        !           605:
        !           606:        /* copy Nick and truncate hostmask if necessary */
        !           607:        strlcpy( search_id, Nick, sizeof( search_id ));
        !           608:        ptr = strchr( search_id, '!' );
        !           609:        if( ptr ) *ptr = '\0';
        !           610:
        !           611:        search_hash = Hash(search_id);
        !           612:
        !           613:        c = My_Clients;
        !           614:        while (c) {
        !           615:                if (c->hash == search_hash && strcasecmp(c->id, search_id) == 0)
        !           616:                        return c;
        !           617:                c = (CLIENT *)c->next;
        !           618:        }
        !           619:        return NULL;
        !           620: }
        !           621:
        !           622:
        !           623: /**
        !           624:  * Search first CLIENT structure matching a given mask of a server.
        !           625:  *
        !           626:  * The order of servers is arbitrary, but this function makes sure that the
        !           627:  * local server is always returned if the mask matches it.
        !           628:  *
        !           629:  * @return Pointer to CLIENT structure or NULL if no server could be found.
        !           630:  */
        !           631: GLOBAL CLIENT *
        !           632: Client_SearchServer(const char *Mask)
        !           633: {
        !           634:        CLIENT *c;
        !           635:
        !           636:        assert(Mask != NULL);
        !           637:
        !           638:        /* First check if mask matches the local server */
        !           639:        if (MatchCaseInsensitive(Mask, Client_ID(Client_ThisServer())))
        !           640:                return Client_ThisServer();
        !           641:
        !           642:        c = My_Clients;
        !           643:        while (c) {
        !           644:                if (Client_Type(c) == CLIENT_SERVER) {
        !           645:                        /* This is a server: check if Mask matches */
        !           646:                        if (MatchCaseInsensitive(Mask, c->id))
        !           647:                                return c;
        !           648:                }
        !           649:                c = (CLIENT *)c->next;
        !           650:        }
        !           651:        return NULL;
        !           652: }
        !           653:
        !           654:
        !           655: /**
        !           656:  * Get client structure ("introducer") identfied by a server token.
        !           657:  * @return CLIENT structure or NULL if none could be found.
        !           658:  */
        !           659: GLOBAL CLIENT *
        !           660: Client_GetFromToken( CLIENT *Client, int Token )
        !           661: {
        !           662:        CLIENT *c;
        !           663:
        !           664:        assert( Client != NULL );
        !           665:
        !           666:        if (!Token)
        !           667:                return NULL;
        !           668:
        !           669:        c = My_Clients;
        !           670:        while (c) {
        !           671:                if ((c->type == CLIENT_SERVER) && (c->introducer == Client) &&
        !           672:                        (c->token == Token))
        !           673:                                return c;
        !           674:                c = (CLIENT *)c->next;
        !           675:        }
        !           676:        return NULL;
        !           677: } /* Client_GetFromToken */
        !           678:
        !           679:
        !           680: GLOBAL int
        !           681: Client_Type( CLIENT *Client )
        !           682: {
        !           683:        assert( Client != NULL );
        !           684:        return Client->type;
        !           685: } /* Client_Type */
        !           686:
        !           687:
        !           688: GLOBAL CONN_ID
        !           689: Client_Conn( CLIENT *Client )
        !           690: {
        !           691:        assert( Client != NULL );
        !           692:        return Client->conn_id;
        !           693: } /* Client_Conn */
        !           694:
        !           695:
        !           696: GLOBAL char *
        !           697: Client_ID( CLIENT *Client )
        !           698: {
        !           699:        assert( Client != NULL );
        !           700:
        !           701: #ifdef DEBUG
        !           702:        if(Client->type == CLIENT_USER)
        !           703:                assert(strlen(Client->id) < Conf_MaxNickLength);
        !           704: #endif
        !           705:
        !           706:        if( Client->id[0] ) return Client->id;
        !           707:        else return "*";
        !           708: } /* Client_ID */
        !           709:
        !           710:
        !           711: GLOBAL char *
        !           712: Client_Info( CLIENT *Client )
        !           713: {
        !           714:        assert( Client != NULL );
        !           715:        return Client->info;
        !           716: } /* Client_Info */
        !           717:
        !           718:
        !           719: GLOBAL char *
        !           720: Client_User( CLIENT *Client )
        !           721: {
        !           722:        assert( Client != NULL );
        !           723:        return Client->user[0] ? Client->user : "~";
        !           724: } /* Client_User */
        !           725:
        !           726:
        !           727: #ifdef PAM
        !           728:
        !           729: /**
        !           730:  * Get the "original" user name as supplied by the USER command.
        !           731:  * The user name as given by the client is used for authentication instead
        !           732:  * of the one detected using IDENT requests.
        !           733:  * @param Client The client.
        !           734:  * @return Original user name.
        !           735:  */
        !           736: GLOBAL char *
        !           737: Client_OrigUser(CLIENT *Client) {
        !           738:        return Client->orig_user;
        !           739: } /* Client_OrigUser */
        !           740:
        !           741: #endif
        !           742:
        !           743: /**
        !           744:  * Return the hostname of a client.
        !           745:  * @param Client Pointer to client structure
        !           746:  * @return Pointer to client hostname
        !           747:  */
        !           748: GLOBAL char *
        !           749: Client_Hostname(CLIENT *Client)
        !           750: {
        !           751:        assert (Client != NULL);
        !           752:        return Client->host;
        !           753: }
        !           754:
        !           755: /**
        !           756:  * Return the cloaked hostname of a client, if set.
        !           757:  * @param Client Pointer to the client structure.
        !           758:  * @return Pointer to the cloaked hostname or NULL if not set.
        !           759:  */
        !           760: GLOBAL char *
        !           761: Client_HostnameCloaked(CLIENT *Client)
        !           762: {
        !           763:        assert(Client != NULL);
        !           764:        return Client->cloaked;
        !           765: }
        !           766:
        !           767: /**
        !           768:  * Get (potentially cloaked) hostname of a client to display it to other users.
        !           769:  *
        !           770:  * If the client has not enabled cloaking, the real hostname is used.
        !           771:  *
        !           772:  * @param Client Pointer to client structure
        !           773:  * @return Pointer to client hostname
        !           774:  */
        !           775: GLOBAL char *
        !           776: Client_HostnameDisplayed(CLIENT *Client)
        !           777: {
        !           778:        assert(Client != NULL);
        !           779:
        !           780:        /* Client isn't cloaked at all, return real hostname: */
        !           781:        if (!Client_HasMode(Client, 'x'))
        !           782:                return Client_Hostname(Client);
        !           783:
        !           784:        /* Use an already saved cloaked hostname, if there is one */
        !           785:        if (Client->cloaked)
        !           786:                return Client->cloaked;
        !           787:
        !           788:        Client_UpdateCloakedHostname(Client, NULL, NULL);
        !           789:        return Client->cloaked;
        !           790: }
        !           791:
        !           792: GLOBAL const char *
        !           793: Client_IPAText(CLIENT *Client)
        !           794: {
        !           795:        assert(Client != NULL);
        !           796:
        !           797:        /* Not a local client? */
        !           798:        if (Client_Conn(Client) <= NONE)
        !           799:                return "0.0.0.0";
        !           800:
        !           801:        if (!Client->ipa_text)
        !           802:                return Conn_GetIPAInfo(Client_Conn(Client));
        !           803:        else
        !           804:                return Client->ipa_text;
        !           805: }
        !           806:
        !           807: /**
        !           808:  * Update (and generate, if necessary) the cloaked hostname of a client.
        !           809:  *
        !           810:  * The newly set cloaked hostname is announced in the network using METADATA
        !           811:  * commands to peers that support this feature.
        !           812:  *
        !           813:  * @param Client The client of which the cloaked hostname should be updated.
        !           814:  * @param Origin The originator of the hostname change, or NULL if this server.
        !           815:  * @param Hostname The new cloaked hostname, or NULL if it should be generated.
        !           816:  */
        !           817: GLOBAL void
        !           818: Client_UpdateCloakedHostname(CLIENT *Client, CLIENT *Origin,
        !           819:                             const char *Hostname)
        !           820: {
        !           821:        char Cloak_Buffer[CLIENT_HOST_LEN];
        !           822:
        !           823:        assert(Client != NULL);
        !           824:        if (!Origin)
        !           825:                Origin = Client_ThisServer();
        !           826:
        !           827:        if (!Client->cloaked) {
        !           828:                Client->cloaked = malloc(CLIENT_HOST_LEN);
        !           829:                if (!Client->cloaked)
        !           830:                        return;
        !           831:        }
        !           832:
        !           833:        if (!Hostname) {
        !           834:                /* Generate new cloaked hostname */
        !           835:                if (*Conf_CloakHostModeX) {
        !           836:                        strlcpy(Cloak_Buffer, Client->host,
        !           837:                                sizeof(Cloak_Buffer));
        !           838:                        strlcat(Cloak_Buffer, Conf_CloakHostSalt,
        !           839:                                sizeof(Cloak_Buffer));
        !           840:                        snprintf(Client->cloaked, CLIENT_HOST_LEN,
        !           841:                                 Conf_CloakHostModeX, Hash(Cloak_Buffer));
        !           842:                } else
        !           843:                        strlcpy(Client->cloaked, Client_ID(Client->introducer),
        !           844:                                CLIENT_HOST_LEN);
        !           845:        } else
        !           846:                strlcpy(Client->cloaked, Hostname, CLIENT_HOST_LEN);
        !           847:        LogDebug("Cloaked hostname of \"%s\" updated to \"%s\"",
        !           848:                 Client_ID(Client), Client->cloaked);
        !           849:
        !           850:        /* Inform other servers in the network */
        !           851:        IRC_WriteStrServersPrefixFlag(Client_NextHop(Origin), Origin, 'M',
        !           852:                                      "METADATA %s cloakhost :%s",
        !           853:                                      Client_ID(Client), Client->cloaked);
        !           854: }
        !           855:
        !           856: GLOBAL char *
        !           857: Client_Modes( CLIENT *Client )
        !           858: {
        !           859:        assert( Client != NULL );
        !           860:        return Client->modes;
        !           861: } /* Client_Modes */
        !           862:
        !           863:
        !           864: GLOBAL char *
        !           865: Client_Flags( CLIENT *Client )
        !           866: {
        !           867:        assert( Client != NULL );
        !           868:        return Client->flags;
        !           869: } /* Client_Flags */
        !           870:
        !           871:
        !           872: GLOBAL int
        !           873: Client_Hops( CLIENT *Client )
        !           874: {
        !           875:        assert( Client != NULL );
        !           876:        return Client->hops;
        !           877: } /* Client_Hops */
        !           878:
        !           879:
        !           880: GLOBAL int
        !           881: Client_Token( CLIENT *Client )
        !           882: {
        !           883:        assert( Client != NULL );
        !           884:        return Client->token;
        !           885: } /* Client_Token */
        !           886:
        !           887:
        !           888: GLOBAL int
        !           889: Client_MyToken( CLIENT *Client )
        !           890: {
        !           891:        assert( Client != NULL );
        !           892:        return Client->mytoken;
        !           893: } /* Client_MyToken */
        !           894:
        !           895:
        !           896: GLOBAL CLIENT *
        !           897: Client_NextHop( CLIENT *Client )
        !           898: {
        !           899:        CLIENT *c;
        !           900:
        !           901:        assert( Client != NULL );
        !           902:
        !           903:        c = Client;
        !           904:        while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server ))
        !           905:                c = c->introducer;
        !           906:
        !           907:        return c;
        !           908: } /* Client_NextHop */
        !           909:
        !           910:
        !           911: /**
        !           912:  * Return ID of a client: "client!user@host"
        !           913:  * This client ID is used for IRC prefixes, for example.
        !           914:  * Please note that this function uses a global static buffer, so you can't
        !           915:  * nest invocations without overwriting earlier results!
        !           916:  * @param Client Pointer to client structure
        !           917:  * @return Pointer to global buffer containing the client ID
        !           918:  */
        !           919: GLOBAL char *
        !           920: Client_Mask( CLIENT *Client )
        !           921: {
        !           922:        static char Mask_Buffer[GETID_LEN];
        !           923:
        !           924:        assert (Client != NULL);
        !           925:
        !           926:        /* Servers: return name only, there is no "mask" */
        !           927:        if (Client->type == CLIENT_SERVER)
        !           928:                return Client->id;
        !           929:
        !           930:        snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
        !           931:                 Client->id, Client->user, Client->host);
        !           932:        return Mask_Buffer;
        !           933: } /* Client_Mask */
        !           934:
        !           935:
        !           936: /**
        !           937:  * Return ID of a client with cloaked hostname: "client!user@server-name"
        !           938:  *
        !           939:  * This client ID is used for IRC prefixes, for example.
        !           940:  * Please note that this function uses a global static buffer, so you can't
        !           941:  * nest invocations without overwriting earlier results!
        !           942:  * If the client has not enabled cloaking, the real hostname is used.
        !           943:  *
        !           944:  * @param Client Pointer to client structure
        !           945:  * @return Pointer to global buffer containing the client ID
        !           946:  */
        !           947: GLOBAL char *
        !           948: Client_MaskCloaked(CLIENT *Client)
        !           949: {
        !           950:        static char Mask_Buffer[GETID_LEN];
        !           951:
        !           952:        assert (Client != NULL);
        !           953:
        !           954:        /* Is the client using cloaking at all? */
        !           955:        if (!Client_HasMode(Client, 'x'))
        !           956:                return Client_Mask(Client);
        !           957:
        !           958:        snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user,
        !           959:                 Client_HostnameDisplayed(Client));
        !           960:
        !           961:        return Mask_Buffer;
        !           962: } /* Client_MaskCloaked */
        !           963:
        !           964:
        !           965: GLOBAL CLIENT *
        !           966: Client_Introducer( CLIENT *Client )
        !           967: {
        !           968:        assert( Client != NULL );
        !           969:        return Client->introducer;
        !           970: } /* Client_Introducer */
        !           971:
        !           972:
        !           973: GLOBAL CLIENT *
        !           974: Client_TopServer( CLIENT *Client )
        !           975: {
        !           976:        assert( Client != NULL );
        !           977:        return Client->topserver;
        !           978: } /* Client_TopServer */
        !           979:
        !           980:
        !           981: GLOBAL bool
        !           982: Client_HasMode( CLIENT *Client, char Mode )
        !           983: {
        !           984:        assert( Client != NULL );
        !           985:        return strchr( Client->modes, Mode ) != NULL;
        !           986: } /* Client_HasMode */
        !           987:
        !           988:
        !           989: GLOBAL bool
        !           990: Client_HasFlag( CLIENT *Client, char Flag )
        !           991: {
        !           992:        assert( Client != NULL );
        !           993:        return strchr( Client->flags, Flag ) != NULL;
        !           994: } /* Client_HasFlag */
        !           995:
        !           996:
        !           997: GLOBAL char *
        !           998: Client_Away( CLIENT *Client )
        !           999: {
        !          1000:        assert( Client != NULL );
        !          1001:        return Client->away;
        !          1002: } /* Client_Away */
        !          1003:
        !          1004:
        !          1005: GLOBAL char *
        !          1006: Client_AccountName(CLIENT *Client)
        !          1007: {
        !          1008:        assert(Client != NULL);
        !          1009:        return Client->account_name;
        !          1010: }
        !          1011:
        !          1012:
        !          1013: /**
        !          1014:  * Make sure that a given nickname is valid.
        !          1015:  *
        !          1016:  * If the nickname is not valid for the given client, this function sends back
        !          1017:  * the appropriate error messages.
        !          1018:  *
        !          1019:  * @param      Client Client that wants to change the nickname.
        !          1020:  * @param      Nick New nickname.
        !          1021:  * @returns    true if nickname is valid, false otherwise.
        !          1022:  */
        !          1023: GLOBAL bool
        !          1024: Client_CheckNick(CLIENT *Client, char *Nick)
        !          1025: {
        !          1026:        assert(Client != NULL);
        !          1027:        assert(Nick != NULL);
        !          1028:
        !          1029:        if (!Client_IsValidNick(Nick)) {
        !          1030:                if (strlen(Nick ) >= Conf_MaxNickLength)
        !          1031:                        IRC_WriteErrClient(Client, ERR_NICKNAMETOOLONG_MSG,
        !          1032:                                           Client_ID(Client), Nick,
        !          1033:                                           Conf_MaxNickLength - 1);
        !          1034:                else
        !          1035:                        IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
        !          1036:                                           Client_ID(Client), Nick);
        !          1037:                return false;
        !          1038:        }
        !          1039:
        !          1040:        if (Client_Type(Client) != CLIENT_SERVER
        !          1041:            && Client_Type(Client) != CLIENT_SERVICE) {
        !          1042:                /* Make sure that this isn't a restricted/forbidden nickname */
        !          1043:                if (Conf_NickIsBlocked(Nick)) {
        !          1044:                        IRC_WriteErrClient(Client, ERR_FORBIDDENNICKNAME_MSG,
        !          1045:                                           Client_ID(Client), Nick);
        !          1046:                        return false;
        !          1047:                }
        !          1048:        }
        !          1049:
        !          1050:        /* Nickname already registered? */
        !          1051:        if (Client_Search(Nick)) {
        !          1052:                IRC_WriteErrClient(Client, ERR_NICKNAMEINUSE_MSG,
        !          1053:                        Client_ID(Client), Nick);
        !          1054:                return false;
        !          1055:        }
        !          1056:
        !          1057:        return true;
        !          1058: } /* Client_CheckNick */
        !          1059:
        !          1060:
        !          1061: GLOBAL bool
        !          1062: Client_CheckID( CLIENT *Client, char *ID )
        !          1063: {
        !          1064:        char str[COMMAND_LEN];
        !          1065:        CLIENT *c;
        !          1066:
        !          1067:        assert( Client != NULL );
        !          1068:        assert( Client->conn_id > NONE );
        !          1069:        assert( ID != NULL );
        !          1070:
        !          1071:        /* ID too long? */
        !          1072:        if (strlen(ID) > CLIENT_ID_LEN) {
        !          1073:                IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
        !          1074:                                   Client_ID(Client), ID);
        !          1075:                return false;
        !          1076:        }
        !          1077:
        !          1078:        /* ID already in use? */
        !          1079:        c = My_Clients;
        !          1080:        while (c) {
        !          1081:                if (strcasecmp(c->id, ID) == 0) {
        !          1082:                        snprintf(str, sizeof(str), "ID \"%s\" already registered", ID);
        !          1083:                        if (c->conn_id != NONE)
        !          1084:                                Log(LOG_ERR, "%s (on connection %d)!", str, c->conn_id);
        !          1085:                        else
        !          1086:                                Log(LOG_ERR, "%s (via network)!", str);
        !          1087:                        Conn_Close(Client->conn_id, str, str, true);
        !          1088:                        return false;
        !          1089:                }
        !          1090:                c = (CLIENT *)c->next;
        !          1091:        }
        !          1092:
        !          1093:        return true;
        !          1094: } /* Client_CheckID */
        !          1095:
        !          1096:
        !          1097: GLOBAL CLIENT *
        !          1098: Client_First( void )
        !          1099: {
        !          1100:        return My_Clients;
        !          1101: } /* Client_First */
        !          1102:
        !          1103:
        !          1104: GLOBAL CLIENT *
        !          1105: Client_Next( CLIENT *c )
        !          1106: {
        !          1107:        assert( c != NULL );
        !          1108:        return (CLIENT *)c->next;
        !          1109: } /* Client_Next */
        !          1110:
        !          1111:
        !          1112: GLOBAL long
        !          1113: Client_UserCount( void )
        !          1114: {
        !          1115:        return Count( CLIENT_USER );
        !          1116: } /* Client_UserCount */
        !          1117:
        !          1118:
        !          1119: GLOBAL long
        !          1120: Client_ServiceCount( void )
        !          1121: {
        !          1122:        return Count( CLIENT_SERVICE );;
        !          1123: } /* Client_ServiceCount */
        !          1124:
        !          1125:
        !          1126: GLOBAL long
        !          1127: Client_ServerCount( void )
        !          1128: {
        !          1129:        return Count( CLIENT_SERVER );
        !          1130: } /* Client_ServerCount */
        !          1131:
        !          1132:
        !          1133: GLOBAL long
        !          1134: Client_MyUserCount( void )
        !          1135: {
        !          1136:        return MyCount( CLIENT_USER );
        !          1137: } /* Client_MyUserCount */
        !          1138:
        !          1139:
        !          1140: GLOBAL long
        !          1141: Client_MyServiceCount( void )
        !          1142: {
        !          1143:        return MyCount( CLIENT_SERVICE );
        !          1144: } /* Client_MyServiceCount */
        !          1145:
        !          1146:
        !          1147: GLOBAL unsigned long
        !          1148: Client_MyServerCount( void )
        !          1149: {
        !          1150:        CLIENT *c;
        !          1151:        unsigned long cnt = 0;
        !          1152:
        !          1153:        c = My_Clients;
        !          1154:        while( c )
        !          1155:        {
        !          1156:                if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
        !          1157:                c = (CLIENT *)c->next;
        !          1158:        }
        !          1159:        return cnt;
        !          1160: } /* Client_MyServerCount */
        !          1161:
        !          1162:
        !          1163: GLOBAL unsigned long
        !          1164: Client_OperCount( void )
        !          1165: {
        !          1166:        CLIENT *c;
        !          1167:        unsigned long cnt = 0;
        !          1168:
        !          1169:        c = My_Clients;
        !          1170:        while( c )
        !          1171:        {
        !          1172:                if (c && c->type == CLIENT_USER && Client_HasMode(c, 'o' ))
        !          1173:                        cnt++;
        !          1174:                c = (CLIENT *)c->next;
        !          1175:        }
        !          1176:        return cnt;
        !          1177: } /* Client_OperCount */
        !          1178:
        !          1179:
        !          1180: GLOBAL unsigned long
        !          1181: Client_UnknownCount( void )
        !          1182: {
        !          1183:        CLIENT *c;
        !          1184:        unsigned long cnt = 0;
        !          1185:
        !          1186:        c = My_Clients;
        !          1187:        while( c )
        !          1188:        {
        !          1189:                if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
        !          1190:                c = (CLIENT *)c->next;
        !          1191:        }
        !          1192:
        !          1193:        return cnt;
        !          1194: } /* Client_UnknownCount */
        !          1195:
        !          1196:
        !          1197: GLOBAL long
        !          1198: Client_MaxUserCount( void )
        !          1199: {
        !          1200:        return Max_Users;
        !          1201: } /* Client_MaxUserCount */
        !          1202:
        !          1203:
        !          1204: GLOBAL long
        !          1205: Client_MyMaxUserCount( void )
        !          1206: {
        !          1207:        return My_Max_Users;
        !          1208: } /* Client_MyMaxUserCount */
        !          1209:
        !          1210:
        !          1211: /**
        !          1212:  * Check that a given nickname is valid.
        !          1213:  *
        !          1214:  * @param      Nick the nickname to check.
        !          1215:  * @returns    true if nickname is valid, false otherwise.
        !          1216:  */
        !          1217: GLOBAL bool
        !          1218: Client_IsValidNick(const char *Nick)
        !          1219: {
        !          1220:        const char *ptr;
        !          1221:        static const char goodchars[] = ";0123456789-";
        !          1222:
        !          1223:        assert (Nick != NULL);
        !          1224:
        !          1225:        if (strchr(goodchars, Nick[0]))
        !          1226:                return false;
        !          1227:        if (strlen(Nick ) >= Conf_MaxNickLength)
        !          1228:                return false;
        !          1229:
        !          1230:        ptr = Nick;
        !          1231:        while (*ptr) {
        !          1232:                if (*ptr < 'A' && !strchr(goodchars, *ptr ))
        !          1233:                        return false;
        !          1234:                if (*ptr > '}')
        !          1235:                        return false;
        !          1236:                ptr++;
        !          1237:        }
        !          1238:
        !          1239:        return true;
        !          1240: } /* Client_IsValidNick */
        !          1241:
        !          1242:
        !          1243: /**
        !          1244:  * Return pointer to "My_Whowas" structure.
        !          1245:  */
        !          1246: GLOBAL WHOWAS *
        !          1247: Client_GetWhowas( void )
        !          1248: {
        !          1249:        return My_Whowas;
        !          1250: } /* Client_GetWhowas */
        !          1251:
        !          1252: /**
        !          1253:  * Return the index of the last used WHOWAS entry.
        !          1254:  */
        !          1255: GLOBAL int
        !          1256: Client_GetLastWhowasIndex( void )
        !          1257: {
        !          1258:        return Last_Whowas;
        !          1259: } /* Client_GetLastWhowasIndex */
        !          1260:
        !          1261:
        !          1262: /**
        !          1263:  * Get the start time of this client.
        !          1264:  * The result is the start time in seconds since 1970-01-01, as reported
        !          1265:  * by the C function time(NULL).
        !          1266:  */
        !          1267: GLOBAL time_t
        !          1268: Client_StartTime(CLIENT *Client)
        !          1269: {
        !          1270:        assert( Client != NULL );
        !          1271:        return Client->starttime;
        !          1272: } /* Client_Uptime */
        !          1273:
        !          1274:
        !          1275: /**
        !          1276:  * Reject a client when logging in.
        !          1277:  *
        !          1278:  * This function is called when a client isn't allowed to connect to this
        !          1279:  * server. Possible reasons are bad server password, bad PAM password,
        !          1280:  * or that the client is G/K-Line'd.
        !          1281:  *
        !          1282:  * After calling this function, the client isn't connected any more.
        !          1283:  *
        !          1284:  * @param Client The client to reject.
        !          1285:  * @param Reason The reason why the client has been rejected.
        !          1286:  * @param InformClient If true, send the exact reason to the client.
        !          1287:  */
        !          1288: GLOBAL void
        !          1289: Client_Reject(CLIENT *Client, const char *Reason, bool InformClient)
        !          1290: {
        !          1291:        char info[COMMAND_LEN];
        !          1292:
        !          1293:        assert(Client != NULL);
        !          1294:        assert(Reason != NULL);
        !          1295:
        !          1296:        if (InformClient)
        !          1297:                snprintf(info, sizeof(info), "Access denied: %s", Reason);
        !          1298:        else
        !          1299:                strcpy(info, "Access denied: Bad password?");
        !          1300:
        !          1301:        Log(LOG_ERR,
        !          1302:            "User \"%s\" rejected (connection %d): %s!",
        !          1303:            Client_Mask(Client), Client_Conn(Client), Reason);
        !          1304:        Conn_Close(Client_Conn(Client), Reason, info, true);
        !          1305: }
        !          1306:
        !          1307:
        !          1308: /**
        !          1309:  * Introduce a new user or service client in the network.
        !          1310:  *
        !          1311:  * @param From Remote server introducing the client or NULL (local).
        !          1312:  * @param Client New client.
        !          1313:  * @param Type Type of the client (CLIENT_USER or CLIENT_SERVICE).
        !          1314:  */
        !          1315: GLOBAL void
        !          1316: Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
        !          1317: {
        !          1318:        /* Set client type (user or service) */
        !          1319:        Client_SetType(Client, Type);
        !          1320:
        !          1321:        if (From) {
        !          1322:                if (Conf_NickIsService(Conf_GetServer(Client_Conn(From)),
        !          1323:                                   Client_ID(Client)))
        !          1324:                        Client_SetType(Client, CLIENT_SERVICE);
        !          1325:                LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
        !          1326:                         Client_TypeText(Client), Client_Mask(Client),
        !          1327:                         Client_Modes(Client), Client_ID(From),
        !          1328:                         Client_ID(Client_Introducer(Client)),
        !          1329:                         Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
        !          1330:        } else {
        !          1331:                Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
        !          1332:                    Client_TypeText(Client), Client_Mask(Client),
        !          1333:                    Client_Conn(Client));
        !          1334:                Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
        !          1335:                                 Client_ID(Client), Client_User(Client),
        !          1336:                                 Client_Hostname(Client),
        !          1337:                                 Conn_IPA(Client_Conn(Client)),
        !          1338:                                 Client_TypeText(Client));
        !          1339:        }
        !          1340:
        !          1341:        /* Inform other servers */
        !          1342:        IRC_WriteStrServersPrefixFlag_CB(From,
        !          1343:                                From != NULL ? From : Client_ThisServer(),
        !          1344:                                '\0', cb_introduceClient, (void *)Client);
        !          1345: } /* Client_Introduce */
        !          1346:
        !          1347:
        !          1348: static unsigned long
        !          1349: Count( CLIENT_TYPE Type )
        !          1350: {
        !          1351:        CLIENT *c;
        !          1352:        unsigned long cnt = 0;
        !          1353:
        !          1354:        c = My_Clients;
        !          1355:        while( c )
        !          1356:        {
        !          1357:                if( c->type == Type ) cnt++;
        !          1358:                c = (CLIENT *)c->next;
        !          1359:        }
        !          1360:        return cnt;
        !          1361: } /* Count */
        !          1362:
        !          1363:
        !          1364: static unsigned long
        !          1365: MyCount( CLIENT_TYPE Type )
        !          1366: {
        !          1367:        CLIENT *c;
        !          1368:        unsigned long cnt = 0;
        !          1369:
        !          1370:        c = My_Clients;
        !          1371:        while( c )
        !          1372:        {
        !          1373:                if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
        !          1374:                c = (CLIENT *)c->next;
        !          1375:        }
        !          1376:        return cnt;
        !          1377: } /* MyCount */
        !          1378:
        !          1379:
        !          1380: /**
        !          1381:  * Allocate and initialize new CLIENT strcuture.
        !          1382:  *
        !          1383:  * @return Pointer to CLIENT structure or NULL on error.
        !          1384:  */
        !          1385: static CLIENT *
        !          1386: New_Client_Struct( void )
        !          1387: {
        !          1388:        CLIENT *c;
        !          1389:
        !          1390:        c = (CLIENT *)malloc( sizeof( CLIENT ));
        !          1391:        if( ! c )
        !          1392:        {
        !          1393:                Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
        !          1394:                return NULL;
        !          1395:        }
        !          1396:
        !          1397:        memset( c, 0, sizeof ( CLIENT ));
        !          1398:
        !          1399:        c->type = CLIENT_UNKNOWN;
        !          1400:        c->conn_id = NONE;
        !          1401:        c->hops = -1;
        !          1402:        c->token = -1;
        !          1403:        c->mytoken = -1;
        !          1404:
        !          1405:        return c;
        !          1406: }
        !          1407:
        !          1408: /**
        !          1409:  * Free a CLIENT structure and its member variables.
        !          1410:  */
        !          1411: static void
        !          1412: Free_Client(CLIENT **Client)
        !          1413: {
        !          1414:        assert(Client != NULL);
        !          1415:        assert(*Client != NULL);
        !          1416:
        !          1417:        if ((*Client)->account_name)
        !          1418:                free((*Client)->account_name);
        !          1419:        if ((*Client)->away)
        !          1420:                free((*Client)->away);
        !          1421:        if ((*Client)->cloaked)
        !          1422:                free((*Client)->cloaked);
        !          1423:        if ((*Client)->ipa_text)
        !          1424:                free((*Client)->ipa_text);
        !          1425:
        !          1426:        free(*Client);
        !          1427:        *Client = NULL;
        !          1428: }
        !          1429:
        !          1430: static void
        !          1431: Generate_MyToken( CLIENT *Client )
        !          1432: {
        !          1433:        CLIENT *c;
        !          1434:        int token;
        !          1435:
        !          1436:        c = My_Clients;
        !          1437:        token = 2;
        !          1438:        while( c )
        !          1439:        {
        !          1440:                if( c->mytoken == token )
        !          1441:                {
        !          1442:                        /* The token is already in use */
        !          1443:                        token++;
        !          1444:                        c = My_Clients;
        !          1445:                        continue;
        !          1446:                }
        !          1447:                else c = (CLIENT *)c->next;
        !          1448:        }
        !          1449:        Client->mytoken = token;
        !          1450:        LogDebug("Assigned token %d to server \"%s\".", token, Client->id);
        !          1451: } /* Generate_MyToken */
        !          1452:
        !          1453:
        !          1454: static void
        !          1455: Adjust_Counters( CLIENT *Client )
        !          1456: {
        !          1457:        long count;
        !          1458:
        !          1459:        assert( Client != NULL );
        !          1460:
        !          1461:        if( Client->type != CLIENT_USER ) return;
        !          1462:
        !          1463:        if( Client->conn_id != NONE )
        !          1464:        {
        !          1465:                /* Local connection */
        !          1466:                count = Client_MyUserCount( );
        !          1467:                if( count > My_Max_Users ) My_Max_Users = count;
        !          1468:        }
        !          1469:        count = Client_UserCount( );
        !          1470:        if( count > Max_Users ) Max_Users = count;
        !          1471: } /* Adjust_Counters */
        !          1472:
        !          1473:
        !          1474: /**
        !          1475:  * Register client in My_Whowas structure for further recall by WHOWAS.
        !          1476:  * Note: Only clients that have been connected at least 30 seconds will be
        !          1477:  * registered to prevent automated IRC bots to "destroy" a nice server
        !          1478:  * history database.
        !          1479:  */
        !          1480: GLOBAL void
        !          1481: Client_RegisterWhowas( CLIENT *Client )
        !          1482: {
        !          1483:        int slot;
        !          1484:        time_t now;
        !          1485:
        !          1486:        assert( Client != NULL );
        !          1487:
        !          1488:        /* Don't register WHOWAS information when "MorePrivacy" is enabled. */
        !          1489:        if (Conf_MorePrivacy)
        !          1490:                return;
        !          1491:
        !          1492:        now = time(NULL);
        !          1493:        /* Don't register clients that were connected less than 30 seconds. */
        !          1494:        if( now - Client->starttime < 30 )
        !          1495:                return;
        !          1496:
        !          1497:        slot = Last_Whowas + 1;
        !          1498:        if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
        !          1499:
        !          1500: #ifdef DEBUG
        !          1501:        Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
        !          1502: #endif
        !          1503:
        !          1504:        My_Whowas[slot].time = now;
        !          1505:        strlcpy( My_Whowas[slot].id, Client_ID( Client ),
        !          1506:                 sizeof( My_Whowas[slot].id ));
        !          1507:        strlcpy( My_Whowas[slot].user, Client_User( Client ),
        !          1508:                 sizeof( My_Whowas[slot].user ));
        !          1509:        strlcpy( My_Whowas[slot].host, Client_HostnameDisplayed( Client ),
        !          1510:                 sizeof( My_Whowas[slot].host ));
        !          1511:        strlcpy( My_Whowas[slot].info, Client_Info( Client ),
        !          1512:                 sizeof( My_Whowas[slot].info ));
        !          1513:        strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
        !          1514:                 sizeof( My_Whowas[slot].server ));
        !          1515:
        !          1516:        Last_Whowas = slot;
        !          1517: } /* Client_RegisterWhowas */
        !          1518:
        !          1519:
        !          1520: GLOBAL const char *
        !          1521: Client_TypeText(CLIENT *Client)
        !          1522: {
        !          1523:        assert(Client != NULL);
        !          1524:        switch (Client_Type(Client)) {
        !          1525:                case CLIENT_USER:
        !          1526:                        return "User";
        !          1527:                        break;
        !          1528:                case CLIENT_SERVICE:
        !          1529:                        return "Service";
        !          1530:                        break;
        !          1531:                case CLIENT_SERVER:
        !          1532:                        return "Server";
        !          1533:                        break;
        !          1534:                default:
        !          1535:                        return "Client";
        !          1536:        }
        !          1537: } /* Client_TypeText */
        !          1538:
        !          1539:
        !          1540: /**
        !          1541:  * Destroy user or service client.
        !          1542:  */
        !          1543: static void
        !          1544: Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool SendQuit)
        !          1545: {
        !          1546:        if(Client->conn_id != NONE) {
        !          1547:                /* Local (directly connected) client */
        !          1548:                Log(LOG_NOTICE,
        !          1549:                    "%s \"%s\" unregistered (connection %d): %s.",
        !          1550:                    Client_TypeText(Client), Client_Mask(Client),
        !          1551:                    Client->conn_id, Txt);
        !          1552:                Log_ServerNotice('c', "Client exiting: %s (%s@%s) [%s]",
        !          1553:                                 Client_ID(Client), Client_User(Client),
        !          1554:                                 Client_Hostname(Client), Txt);
        !          1555:
        !          1556:                if (SendQuit) {
        !          1557:                        /* Inforam all the other servers */
        !          1558:                        if (FwdMsg)
        !          1559:                                IRC_WriteStrServersPrefix(NULL,
        !          1560:                                                Client, "QUIT :%s", FwdMsg );
        !          1561:                        else
        !          1562:                                IRC_WriteStrServersPrefix(NULL,
        !          1563:                                                Client, "QUIT :");
        !          1564:                }
        !          1565:        } else {
        !          1566:                /* Remote client */
        !          1567:                LogDebug("%s \"%s\" unregistered: %s.",
        !          1568:                         Client_TypeText(Client), Client_Mask(Client), Txt);
        !          1569:
        !          1570:                if(SendQuit) {
        !          1571:                        /* Inform all the other servers, but the ones in the
        !          1572:                         * direction we got the QUIT from */
        !          1573:                        if(FwdMsg)
        !          1574:                                IRC_WriteStrServersPrefix(Client_NextHop(Client),
        !          1575:                                                Client, "QUIT :%s", FwdMsg );
        !          1576:                        else
        !          1577:                                IRC_WriteStrServersPrefix(Client_NextHop(Client),
        !          1578:                                                Client, "QUIT :" );
        !          1579:                }
        !          1580:        }
        !          1581:
        !          1582:        /* Unregister client from channels */
        !          1583:        Channel_Quit(Client, FwdMsg ? FwdMsg : Client->id);
        !          1584:
        !          1585:        /* Register client in My_Whowas structure */
        !          1586:        Client_RegisterWhowas(Client);
        !          1587: } /* Destroy_UserOrService */
        !          1588:
        !          1589:
        !          1590: /**
        !          1591:  * Introduce a new user or service client to a remote server.
        !          1592:  *
        !          1593:  * @param To           The remote server to inform.
        !          1594:  * @param Prefix       Prefix for the generated commands.
        !          1595:  * @param data         CLIENT structure of the new client.
        !          1596:  */
        !          1597: static void
        !          1598: cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data)
        !          1599: {
        !          1600:        CLIENT *c = (CLIENT *)data;
        !          1601:
        !          1602:        (void)Client_Announce(To, Prefix, c);
        !          1603:
        !          1604: } /* cb_introduceClient */
        !          1605:
        !          1606:
        !          1607: /**
        !          1608:  * Announce an user or service to a server.
        !          1609:  *
        !          1610:  * This function differentiates between RFC1459 and RFC2813 server links and
        !          1611:  * generates the appropriate commands to register the user or service.
        !          1612:  *
        !          1613:  * @param Client       Server
        !          1614:  * @param Prefix       Prefix for the generated commands
        !          1615:  * @param User         User to announce
        !          1616:  */
        !          1617: GLOBAL bool
        !          1618: Client_Announce(CLIENT * Client, CLIENT * Prefix, CLIENT * User)
        !          1619: {
        !          1620:        CONN_ID conn;
        !          1621:        char *modes, *user, *host;
        !          1622:
        !          1623:        modes = Client_Modes(User);
        !          1624:        user = Client_User(User) ? Client_User(User) : "-";
        !          1625:        host = Client_Hostname(User) ? Client_Hostname(User) : "-";
        !          1626:
        !          1627:        conn = Client_Conn(Client);
        !          1628:        if (Conn_Options(conn) & CONN_RFC1459) {
        !          1629:                /* RFC 1459 mode: separate NICK and USER commands */
        !          1630:                if (! Conn_WriteStr(conn, "NICK %s :%d",
        !          1631:                                    Client_ID(User), Client_Hops(User) + 1))
        !          1632:                        return DISCONNECTED;
        !          1633:                if (! Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
        !          1634:                                     Client_ID(User), user, host,
        !          1635:                                     Client_ID(Client_Introducer(User)),
        !          1636:                                     Client_Info(User)))
        !          1637:                        return DISCONNECTED;
        !          1638:                if (modes[0]) {
        !          1639:                        if (! Conn_WriteStr(conn, ":%s MODE %s +%s",
        !          1640:                                     Client_ID(User), Client_ID(User),
        !          1641:                                     modes))
        !          1642:                                return DISCONNECTED;
        !          1643:                }
        !          1644:        } else {
        !          1645:                /* RFC 2813 mode: one combined NICK or SERVICE command */
        !          1646:                if (Client_Type(User) == CLIENT_SERVICE
        !          1647:                    && Client_HasFlag(Client, 'S')) {
        !          1648:                        if (!IRC_WriteStrClientPrefix(Client, Prefix,
        !          1649:                                        "SERVICE %s %d * +%s %d :%s",
        !          1650:                                        Client_Mask(User),
        !          1651:                                        Client_MyToken(Client_Introducer(User)),
        !          1652:                                        modes, Client_Hops(User) + 1,
        !          1653:                                        Client_Info(User)))
        !          1654:                                return DISCONNECTED;
        !          1655:                } else {
        !          1656:                        if (!IRC_WriteStrClientPrefix(Client, Prefix,
        !          1657:                                        "NICK %s %d %s %s %d +%s :%s",
        !          1658:                                        Client_ID(User), Client_Hops(User) + 1,
        !          1659:                                        user, host,
        !          1660:                                        Client_MyToken(Client_Introducer(User)),
        !          1661:                                        modes, Client_Info(User)))
        !          1662:                                return DISCONNECTED;
        !          1663:                }
        !          1664:        }
        !          1665:
        !          1666:        if (Client_HasFlag(Client, 'M')) {
        !          1667:                /* Synchronize metadata */
        !          1668:                if (Client_HostnameCloaked(User)) {
        !          1669:                        if (!IRC_WriteStrClientPrefix(Client, Prefix,
        !          1670:                                        "METADATA %s cloakhost :%s",
        !          1671:                                        Client_ID(User),
        !          1672:                                        Client_HostnameCloaked(User)))
        !          1673:                                return DISCONNECTED;
        !          1674:                }
        !          1675:
        !          1676:                if (Client_AccountName(User)) {
        !          1677:                        if (!IRC_WriteStrClientPrefix(Client, Prefix,
        !          1678:                                        "METADATA %s accountname :%s",
        !          1679:                                        Client_ID(User),
        !          1680:                                        Client_AccountName(User)))
        !          1681:                                return DISCONNECTED;
        !          1682:                }
        !          1683:
        !          1684:                if (Conn_GetCertFp(Client_Conn(User))) {
        !          1685:                        if (!IRC_WriteStrClientPrefix(Client, Prefix,
        !          1686:                                        "METADATA %s certfp :%s",
        !          1687:                                        Client_ID(User),
        !          1688:                                        Conn_GetCertFp(Client_Conn(User))))
        !          1689:                                return DISCONNECTED;
        !          1690:                }
        !          1691:        }
        !          1692:
        !          1693:        return CONNECTED;
        !          1694: } /* Client_Announce */
        !          1695:
        !          1696:
        !          1697: #ifdef DEBUG
        !          1698:
        !          1699: GLOBAL void
        !          1700: Client_DebugDump(void)
        !          1701: {
        !          1702:        CLIENT *c;
        !          1703:
        !          1704:        Log(LOG_DEBUG, "Client status:");
        !          1705:        c = My_Clients;
        !          1706:        while (c) {
        !          1707:                Log(LOG_DEBUG,
        !          1708:                    " - %s: type=%d, host=%s, user=%s, conn=%d, start=%ld, flags=%s",
        !          1709:                    Client_ID(c), Client_Type(c), Client_Hostname(c),
        !          1710:                    Client_User(c), Client_Conn(c), Client_StartTime(c),
        !          1711:                    Client_Flags(c));
        !          1712:                c = (CLIENT *)c->next;
        !          1713:        }
        !          1714: } /* Client_DumpClients */
        !          1715:
        !          1716: #endif
        !          1717:
        !          1718:
        !          1719: /* -eof- */

CVSweb