client.c 38 KB

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