client.c 38 KB

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