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
Client_Init(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
Client_Exit(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 *
Client_ThisServer(void)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 *
Client_NewLocal(CONN_ID Idx,const char * Hostname,int Type,bool Idented)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 *
Client_NewRemoteServer(CLIENT * Introducer,const char * Hostname,CLIENT * TopServer,int Hops,int Token,const char * Info,bool Idented)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 *
Client_NewRemoteUser(CLIENT * Introducer,const char * Nick,int Hops,const char * User,const char * Hostname,int Token,const char * Modes,const char * Info,bool Idented)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 *
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)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
Client_Destroy(CLIENT * Client,const char * LogMsg,const char * FwdMsg,bool SendQuit)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
Client_SetHostname(CLIENT * Client,const char * Hostname)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
Client_SetIPAText(CLIENT * Client,const char * IPAText)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
Client_SetID(CLIENT * Client,const char * ID)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
Client_SetUser(CLIENT * Client,const char * User,bool Idented)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
Client_SetOrigUser(CLIENT UNUSED * Client,const char UNUSED * User)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
Client_SetInfo(CLIENT * Client,const char * Info)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
Client_SetModes(CLIENT * Client,const char * Modes)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
Client_SetFlags(CLIENT * Client,const char * Flags)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
Client_SetAccountName(CLIENT * Client,const char * AccountName)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
Client_SetAway(CLIENT * Client,const char * Txt)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
Client_SetType(CLIENT * Client,int Type)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
Client_SetHops(CLIENT * Client,int Hops)520 Client_SetHops( CLIENT *Client, int Hops )
521 {
522 assert( Client != NULL );
523 Client->hops = Hops;
524 } /* Client_SetHops */
525
526
527 GLOBAL void
Client_SetToken(CLIENT * Client,int Token)528 Client_SetToken( CLIENT *Client, int Token )
529 {
530 assert( Client != NULL );
531 Client->token = Token;
532 } /* Client_SetToken */
533
534
535 GLOBAL void
Client_SetIntroducer(CLIENT * Client,CLIENT * Introducer)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
Client_ModeAdd(CLIENT * Client,char Mode)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
Client_ModeDel(CLIENT * Client,char Mode)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 *
Client_Search(const char * Nick)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 *
Client_SearchServer(const char * Mask)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 *
Client_GetFromToken(CLIENT * Client,int Token)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
Client_Type(CLIENT * Client)681 Client_Type( CLIENT *Client )
682 {
683 assert( Client != NULL );
684 return Client->type;
685 } /* Client_Type */
686
687
688 GLOBAL CONN_ID
Client_Conn(CLIENT * Client)689 Client_Conn( CLIENT *Client )
690 {
691 assert( Client != NULL );
692 return Client->conn_id;
693 } /* Client_Conn */
694
695
696 GLOBAL char *
Client_ID(CLIENT * Client)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 *
Client_Info(CLIENT * Client)712 Client_Info( CLIENT *Client )
713 {
714 assert( Client != NULL );
715 return Client->info;
716 } /* Client_Info */
717
718
719 GLOBAL char *
Client_User(CLIENT * Client)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 *
Client_OrigUser(CLIENT * Client)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 *
Client_Hostname(CLIENT * Client)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 *
Client_HostnameCloaked(CLIENT * Client)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 *
Client_HostnameDisplayed(CLIENT * Client)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 *
Client_IPAText(CLIENT * Client)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
Client_UpdateCloakedHostname(CLIENT * Client,CLIENT * Origin,const char * Hostname)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 *
Client_Modes(CLIENT * Client)857 Client_Modes( CLIENT *Client )
858 {
859 assert( Client != NULL );
860 return Client->modes;
861 } /* Client_Modes */
862
863
864 GLOBAL char *
Client_Flags(CLIENT * Client)865 Client_Flags( CLIENT *Client )
866 {
867 assert( Client != NULL );
868 return Client->flags;
869 } /* Client_Flags */
870
871
872 GLOBAL int
Client_Hops(CLIENT * Client)873 Client_Hops( CLIENT *Client )
874 {
875 assert( Client != NULL );
876 return Client->hops;
877 } /* Client_Hops */
878
879
880 GLOBAL int
Client_Token(CLIENT * Client)881 Client_Token( CLIENT *Client )
882 {
883 assert( Client != NULL );
884 return Client->token;
885 } /* Client_Token */
886
887
888 GLOBAL int
Client_MyToken(CLIENT * Client)889 Client_MyToken( CLIENT *Client )
890 {
891 assert( Client != NULL );
892 return Client->mytoken;
893 } /* Client_MyToken */
894
895
896 GLOBAL CLIENT *
Client_NextHop(CLIENT * 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 *
Client_Mask(CLIENT * Client)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 *
Client_MaskCloaked(CLIENT * Client)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 *
Client_Introducer(CLIENT * Client)966 Client_Introducer( CLIENT *Client )
967 {
968 assert( Client != NULL );
969 return Client->introducer;
970 } /* Client_Introducer */
971
972
973 GLOBAL CLIENT *
Client_TopServer(CLIENT * Client)974 Client_TopServer( CLIENT *Client )
975 {
976 assert( Client != NULL );
977 return Client->topserver;
978 } /* Client_TopServer */
979
980
981 GLOBAL bool
Client_HasMode(CLIENT * Client,char Mode)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
Client_HasFlag(CLIENT * Client,char Flag)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 *
Client_Away(CLIENT * Client)998 Client_Away( CLIENT *Client )
999 {
1000 assert( Client != NULL );
1001 return Client->away;
1002 } /* Client_Away */
1003
1004
1005 GLOBAL char *
Client_AccountName(CLIENT * Client)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
Client_CheckNick(CLIENT * Client,char * Nick)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
Client_CheckID(CLIENT * Client,char * ID)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 *
Client_First(void)1098 Client_First( void )
1099 {
1100 return My_Clients;
1101 } /* Client_First */
1102
1103
1104 GLOBAL CLIENT *
Client_Next(CLIENT * c)1105 Client_Next( CLIENT *c )
1106 {
1107 assert( c != NULL );
1108 return (CLIENT *)c->next;
1109 } /* Client_Next */
1110
1111
1112 GLOBAL long
Client_UserCount(void)1113 Client_UserCount( void )
1114 {
1115 return Count( CLIENT_USER );
1116 } /* Client_UserCount */
1117
1118
1119 GLOBAL long
Client_ServiceCount(void)1120 Client_ServiceCount( void )
1121 {
1122 return Count( CLIENT_SERVICE );;
1123 } /* Client_ServiceCount */
1124
1125
1126 GLOBAL long
Client_ServerCount(void)1127 Client_ServerCount( void )
1128 {
1129 return Count( CLIENT_SERVER );
1130 } /* Client_ServerCount */
1131
1132
1133 GLOBAL long
Client_MyUserCount(void)1134 Client_MyUserCount( void )
1135 {
1136 return MyCount( CLIENT_USER );
1137 } /* Client_MyUserCount */
1138
1139
1140 GLOBAL long
Client_MyServiceCount(void)1141 Client_MyServiceCount( void )
1142 {
1143 return MyCount( CLIENT_SERVICE );
1144 } /* Client_MyServiceCount */
1145
1146
1147 GLOBAL unsigned long
Client_MyServerCount(void)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
Client_OperCount(void)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
Client_UnknownCount(void)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
Client_MaxUserCount(void)1198 Client_MaxUserCount( void )
1199 {
1200 return Max_Users;
1201 } /* Client_MaxUserCount */
1202
1203
1204 GLOBAL long
Client_MyMaxUserCount(void)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
Client_IsValidNick(const char * Nick)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 *
Client_GetWhowas(void)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
Client_GetLastWhowasIndex(void)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
Client_StartTime(CLIENT * Client)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
Client_Reject(CLIENT * Client,const char * Reason,bool InformClient)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
Client_Introduce(CLIENT * From,CLIENT * Client,int Type)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
Count(CLIENT_TYPE Type)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
MyCount(CLIENT_TYPE Type)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 *
New_Client_Struct(void)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
Free_Client(CLIENT ** Client)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
Generate_MyToken(CLIENT * Client)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
Adjust_Counters(CLIENT * Client)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
Client_RegisterWhowas(CLIENT * Client)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 *
Client_TypeText(CLIENT * Client)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
Destroy_UserOrService(CLIENT * Client,const char * Txt,const char * FwdMsg,bool SendQuit)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
cb_introduceClient(CLIENT * To,CLIENT * Prefix,void * data)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
Client_Announce(CLIENT * Client,CLIENT * Prefix,CLIENT * User)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
Client_DebugDump(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- */
1720