client.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
  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. * Client management.
  12. */
  13. #define __client_c__
  14. #include "portab.h"
  15. #include "imp.h"
  16. #include <assert.h>
  17. #include <unistd.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <strings.h>
  22. #include <netdb.h>
  23. #include "defines.h"
  24. #include "conn.h"
  25. #include "exp.h"
  26. #include "client.h"
  27. #include <imp.h>
  28. #include "ngircd.h"
  29. #include "channel.h"
  30. #include "conf.h"
  31. #include "hash.h"
  32. #include "irc-write.h"
  33. #include "log.h"
  34. #include "messages.h"
  35. #include <exp.h>
  36. #define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
  37. static CLIENT *This_Server, *My_Clients;
  38. static WHOWAS My_Whowas[MAX_WHOWAS];
  39. static int Last_Whowas = -1;
  40. static long Max_Users, My_Max_Users;
  41. static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
  42. static unsigned long MyCount PARAMS(( CLIENT_TYPE Type ));
  43. static CLIENT *New_Client_Struct PARAMS(( void ));
  44. static void Generate_MyToken PARAMS(( CLIENT *Client ));
  45. static void Adjust_Counters 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. GLOBAL void
  54. Client_Init( void )
  55. {
  56. struct hostent *h;
  57. This_Server = New_Client_Struct( );
  58. if( ! This_Server )
  59. {
  60. Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
  61. Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
  62. exit( 1 );
  63. }
  64. /* Client-Struktur dieses Servers */
  65. This_Server->next = NULL;
  66. This_Server->type = CLIENT_SERVER;
  67. This_Server->conn_id = NONE;
  68. This_Server->introducer = This_Server;
  69. This_Server->mytoken = 1;
  70. This_Server->hops = 0;
  71. gethostname( This_Server->host, CLIENT_HOST_LEN );
  72. if (!Conf_NoDNS) {
  73. h = gethostbyname( This_Server->host );
  74. if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
  75. }
  76. Client_SetID( This_Server, Conf_ServerName );
  77. Client_SetInfo( This_Server, Conf_ServerInfo );
  78. My_Clients = This_Server;
  79. memset( &My_Whowas, 0, sizeof( My_Whowas ));
  80. } /* Client_Init */
  81. GLOBAL void
  82. Client_Exit( void )
  83. {
  84. CLIENT *c, *next;
  85. int cnt;
  86. if( NGIRCd_SignalRestart ) Client_Destroy( This_Server, "Server going down (restarting).", NULL, false );
  87. else Client_Destroy( This_Server, "Server going down.", NULL, false );
  88. cnt = 0;
  89. c = My_Clients;
  90. while( c )
  91. {
  92. cnt++;
  93. next = (CLIENT *)c->next;
  94. free( c );
  95. c = next;
  96. }
  97. if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
  98. } /* Client_Exit */
  99. GLOBAL CLIENT *
  100. Client_ThisServer( void )
  101. {
  102. return This_Server;
  103. } /* Client_ThisServer */
  104. /**
  105. * Initialize new local client; wrapper function for Init_New_Client().
  106. * @return New CLIENT structure.
  107. */
  108. GLOBAL CLIENT *
  109. Client_NewLocal(CONN_ID Idx, const char *Hostname, int Type, bool Idented)
  110. {
  111. return Init_New_Client(Idx, This_Server, NULL, Type, NULL, NULL,
  112. Hostname, NULL, 0, 0, NULL, Idented);
  113. } /* Client_NewLocal */
  114. /**
  115. * Initialize new remote server; wrapper function for Init_New_Client().
  116. * @return New CLIENT structure.
  117. */
  118. GLOBAL CLIENT *
  119. Client_NewRemoteServer(CLIENT *Introducer, const char *Hostname, CLIENT *TopServer,
  120. int Hops, int Token, const char *Info, bool Idented)
  121. {
  122. return Init_New_Client(NONE, Introducer, TopServer, CLIENT_SERVER,
  123. Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented);
  124. } /* Client_NewRemoteServer */
  125. /**
  126. * Initialize new remote client; wrapper function for Init_New_Client().
  127. * @return New CLIENT structure.
  128. */
  129. GLOBAL CLIENT *
  130. Client_NewRemoteUser(CLIENT *Introducer, const char *Nick, int Hops, const char *User,
  131. const char *Hostname, int Token, const char *Modes, const char *Info, bool Idented)
  132. {
  133. return Init_New_Client(NONE, Introducer, NULL, CLIENT_USER, Nick,
  134. User, Hostname, Info, Hops, Token, Modes, Idented);
  135. } /* Client_NewRemoteUser */
  136. /**
  137. * Initialize new client and set up the given parameters like client type,
  138. * user name, host name, introducing server etc. ...
  139. * @return New CLIENT structure.
  140. */
  141. static CLIENT *
  142. Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
  143. int Type, const char *ID, const char *User, const char *Hostname,
  144. const char *Info, int Hops, int Token, const char *Modes, bool Idented)
  145. {
  146. CLIENT *client;
  147. assert(Idx >= NONE);
  148. assert(Introducer != NULL);
  149. assert(Hostname != NULL);
  150. client = New_Client_Struct();
  151. if (!client)
  152. return NULL;
  153. client->starttime = time(NULL);
  154. client->conn_id = Idx;
  155. client->introducer = Introducer;
  156. client->topserver = TopServer;
  157. client->type = Type;
  158. if (ID)
  159. Client_SetID(client, ID);
  160. if (User) {
  161. Client_SetUser(client, User, Idented);
  162. Client_SetOrigUser(client, User);
  163. }
  164. if (Hostname)
  165. Client_SetHostname(client, Hostname);
  166. if (Info)
  167. Client_SetInfo(client, Info);
  168. client->hops = Hops;
  169. client->token = Token;
  170. if (Modes)
  171. Client_SetModes(client, Modes);
  172. if (Type == CLIENT_SERVER)
  173. Generate_MyToken(client);
  174. if (strchr(client->modes, 'a'))
  175. strlcpy(client->away, DEFAULT_AWAY_MSG, sizeof(client->away));
  176. client->next = (POINTER *)My_Clients;
  177. My_Clients = client;
  178. Adjust_Counters(client);
  179. return client;
  180. } /* Init_New_Client */
  181. GLOBAL void
  182. Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool SendQuit )
  183. {
  184. /* remove a client */
  185. CLIENT *last, *c;
  186. char msg[LINE_LEN];
  187. const char *txt;
  188. assert( Client != NULL );
  189. if( LogMsg ) txt = LogMsg;
  190. else txt = FwdMsg;
  191. if( ! txt ) txt = "Reason unknown.";
  192. /* netsplit message */
  193. if( Client->type == CLIENT_SERVER ) {
  194. strlcpy(msg, This_Server->id, sizeof (msg));
  195. strlcat(msg, " ", sizeof (msg));
  196. strlcat(msg, Client->id, sizeof (msg));
  197. }
  198. last = NULL;
  199. c = My_Clients;
  200. while( c )
  201. {
  202. if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
  203. {
  204. /*
  205. * The client that is about to be removed is a server,
  206. * the client we are checking right now is a child of that
  207. * server and thus has to be removed, too.
  208. *
  209. * Call Client_Destroy() recursively with the server as the
  210. * new "object to be removed". This starts the cycle again, until
  211. * all servers that are linked via the original server have been
  212. * removed.
  213. */
  214. Client_Destroy( c, NULL, msg, false );
  215. last = NULL;
  216. c = My_Clients;
  217. continue;
  218. }
  219. if( c == Client )
  220. {
  221. /* found the client: remove it */
  222. if( last ) last->next = c->next;
  223. else My_Clients = (CLIENT *)c->next;
  224. if(c->type == CLIENT_USER || c->type == CLIENT_SERVICE)
  225. Destroy_UserOrService(c, txt, FwdMsg, SendQuit);
  226. else if( c->type == CLIENT_SERVER )
  227. {
  228. if( c != This_Server )
  229. {
  230. if( c->conn_id != NONE ) Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
  231. else Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered: %s", c->id, txt );
  232. }
  233. /* inform other servers */
  234. if( ! NGIRCd_SignalQuit )
  235. {
  236. if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
  237. else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
  238. }
  239. }
  240. else
  241. {
  242. if( c->conn_id != NONE )
  243. {
  244. if( c->id[0] ) Log( LOG_NOTICE, "Client \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
  245. else Log( LOG_NOTICE, "Client unregistered (connection %d): %s", c->conn_id, txt );
  246. } else {
  247. Log(LOG_WARNING, "Unregistered unknown client \"%s\": %s",
  248. c->id[0] ? c->id : "(No Nick)", txt );
  249. }
  250. }
  251. free( c );
  252. break;
  253. }
  254. last = c;
  255. c = (CLIENT *)c->next;
  256. }
  257. } /* Client_Destroy */
  258. GLOBAL void
  259. Client_SetHostname( CLIENT *Client, const char *Hostname )
  260. {
  261. assert( Client != NULL );
  262. assert( Hostname != NULL );
  263. strlcpy( Client->host, Hostname, sizeof( Client->host ));
  264. } /* Client_SetHostname */
  265. GLOBAL void
  266. Client_SetID( CLIENT *Client, const char *ID )
  267. {
  268. assert( Client != NULL );
  269. assert( ID != NULL );
  270. strlcpy( Client->id, ID, sizeof( Client->id ));
  271. /* Hash */
  272. Client->hash = Hash( Client->id );
  273. } /* Client_SetID */
  274. GLOBAL void
  275. Client_SetUser( CLIENT *Client, const char *User, bool Idented )
  276. {
  277. /* set clients username */
  278. assert( Client != NULL );
  279. assert( User != NULL );
  280. if (Idented) {
  281. strlcpy(Client->user, User, sizeof(Client->user));
  282. } else {
  283. Client->user[0] = '~';
  284. strlcpy(Client->user + 1, User, sizeof(Client->user) - 1);
  285. }
  286. } /* Client_SetUser */
  287. /**
  288. * Set "original" user name of a client.
  289. * This function saves the "original" user name, the user name specified by
  290. * the peer using the USER command, into the CLIENT structure. This user
  291. * name may be used for authentication, for example.
  292. * @param Client The client.
  293. * @param User User name to set.
  294. */
  295. GLOBAL void
  296. Client_SetOrigUser(CLIENT UNUSED *Client, const char UNUSED *User)
  297. {
  298. assert(Client != NULL);
  299. assert(User != NULL);
  300. #if defined(PAM) && defined(IDENTAUTH)
  301. strlcpy(Client->orig_user, User, sizeof(Client->orig_user));
  302. #endif
  303. } /* Client_SetOrigUser */
  304. GLOBAL void
  305. Client_SetInfo( CLIENT *Client, const char *Info )
  306. {
  307. /* set client hostname */
  308. assert( Client != NULL );
  309. assert( Info != NULL );
  310. strlcpy(Client->info, Info, sizeof(Client->info));
  311. } /* Client_SetInfo */
  312. GLOBAL void
  313. Client_SetModes( CLIENT *Client, const char *Modes )
  314. {
  315. assert( Client != NULL );
  316. assert( Modes != NULL );
  317. strlcpy(Client->modes, Modes, sizeof( Client->modes ));
  318. } /* Client_SetModes */
  319. GLOBAL void
  320. Client_SetFlags( CLIENT *Client, const char *Flags )
  321. {
  322. assert( Client != NULL );
  323. assert( Flags != NULL );
  324. strlcpy(Client->flags, Flags, sizeof(Client->flags));
  325. } /* Client_SetFlags */
  326. GLOBAL void
  327. Client_SetPassword( CLIENT *Client, const char *Pwd )
  328. {
  329. /* set password sent by client */
  330. assert( Client != NULL );
  331. assert( Pwd != NULL );
  332. strlcpy(Client->pwd, Pwd, sizeof(Client->pwd));
  333. } /* Client_SetPassword */
  334. GLOBAL void
  335. Client_SetAway( CLIENT *Client, const char *Txt )
  336. {
  337. /* Set AWAY reason of client */
  338. assert( Client != NULL );
  339. assert( Txt != NULL );
  340. strlcpy( Client->away, Txt, sizeof( Client->away ));
  341. LogDebug("%s \"%s\" is away: %s", Client_TypeText(Client),
  342. Client_Mask(Client), Txt);
  343. } /* Client_SetAway */
  344. GLOBAL void
  345. Client_SetType( CLIENT *Client, int Type )
  346. {
  347. assert( Client != NULL );
  348. Client->type = Type;
  349. if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
  350. Adjust_Counters( Client );
  351. } /* Client_SetType */
  352. GLOBAL void
  353. Client_SetHops( CLIENT *Client, int Hops )
  354. {
  355. assert( Client != NULL );
  356. Client->hops = Hops;
  357. } /* Client_SetHops */
  358. GLOBAL void
  359. Client_SetToken( CLIENT *Client, int Token )
  360. {
  361. assert( Client != NULL );
  362. Client->token = Token;
  363. } /* Client_SetToken */
  364. GLOBAL void
  365. Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
  366. {
  367. assert( Client != NULL );
  368. assert( Introducer != NULL );
  369. Client->introducer = Introducer;
  370. } /* Client_SetIntroducer */
  371. GLOBAL void
  372. Client_SetOperByMe( CLIENT *Client, bool OperByMe )
  373. {
  374. assert( Client != NULL );
  375. Client->oper_by_me = OperByMe;
  376. } /* Client_SetOperByMe */
  377. GLOBAL bool
  378. Client_ModeAdd( CLIENT *Client, char Mode )
  379. {
  380. /* Set Mode.
  381. * If Client already alread had Mode, return false.
  382. * If the Mode was newly set, return true.
  383. */
  384. char x[2];
  385. assert( Client != NULL );
  386. x[0] = Mode; x[1] = '\0';
  387. if (!strchr( Client->modes, x[0])) {
  388. strlcat( Client->modes, x, sizeof( Client->modes ));
  389. return true;
  390. }
  391. else return false;
  392. } /* Client_ModeAdd */
  393. GLOBAL bool
  394. Client_ModeDel( CLIENT *Client, char Mode )
  395. {
  396. /* Delete Mode.
  397. * If Mode was removed, return true.
  398. * If Client did not have Mode, return false.
  399. */
  400. char x[2], *p;
  401. assert( Client != NULL );
  402. x[0] = Mode; x[1] = '\0';
  403. p = strchr( Client->modes, x[0] );
  404. if( ! p ) return false;
  405. /* Client has Mode -> delete */
  406. while( *p )
  407. {
  408. *p = *(p + 1);
  409. p++;
  410. }
  411. return true;
  412. } /* Client_ModeDel */
  413. GLOBAL CLIENT *
  414. Client_Search( const char *Nick )
  415. {
  416. /* return Client-Structure that has the corresponding Nick.
  417. * If none is found, return NULL.
  418. */
  419. char search_id[CLIENT_ID_LEN], *ptr;
  420. CLIENT *c = NULL;
  421. UINT32 search_hash;
  422. assert( Nick != NULL );
  423. /* copy Nick and truncate hostmask if necessary */
  424. strlcpy( search_id, Nick, sizeof( search_id ));
  425. ptr = strchr( search_id, '!' );
  426. if( ptr ) *ptr = '\0';
  427. search_hash = Hash(search_id);
  428. c = My_Clients;
  429. while (c) {
  430. if (c->hash == search_hash && strcasecmp(c->id, search_id) == 0)
  431. return c;
  432. c = (CLIENT *)c->next;
  433. }
  434. return NULL;
  435. } /* Client_Search */
  436. GLOBAL CLIENT *
  437. Client_GetFromToken( CLIENT *Client, int Token )
  438. {
  439. /* Client-Struktur, die den entsprechenden Introducer (=Client)
  440. * und das gegebene Token hat, liefern. Wird keine gefunden,
  441. * so wird NULL geliefert. */
  442. CLIENT *c;
  443. assert( Client != NULL );
  444. assert( Token > 0 );
  445. c = My_Clients;
  446. while (c) {
  447. if ((c->type == CLIENT_SERVER) && (c->introducer == Client) &&
  448. (c->token == Token))
  449. return c;
  450. c = (CLIENT *)c->next;
  451. }
  452. return NULL;
  453. } /* Client_GetFromToken */
  454. GLOBAL int
  455. Client_Type( CLIENT *Client )
  456. {
  457. assert( Client != NULL );
  458. return Client->type;
  459. } /* Client_Type */
  460. GLOBAL CONN_ID
  461. Client_Conn( CLIENT *Client )
  462. {
  463. assert( Client != NULL );
  464. return Client->conn_id;
  465. } /* Client_Conn */
  466. GLOBAL char *
  467. Client_ID( CLIENT *Client )
  468. {
  469. assert( Client != NULL );
  470. #ifdef DEBUG
  471. if(Client->type == CLIENT_USER)
  472. assert(strlen(Client->id) < Conf_MaxNickLength);
  473. #endif
  474. if( Client->id[0] ) return Client->id;
  475. else return "*";
  476. } /* Client_ID */
  477. GLOBAL char *
  478. Client_Info( CLIENT *Client )
  479. {
  480. assert( Client != NULL );
  481. return Client->info;
  482. } /* Client_Info */
  483. GLOBAL char *
  484. Client_User( CLIENT *Client )
  485. {
  486. assert( Client != NULL );
  487. return Client->user[0] ? Client->user : "~";
  488. } /* Client_User */
  489. #ifdef PAM
  490. /**
  491. * Get the "original" user name as supplied by the USER command.
  492. * The user name as given by the client is used for authentication instead
  493. * of the one detected using IDENT requests.
  494. * @param Client The client.
  495. * @return Original user name.
  496. */
  497. GLOBAL char *
  498. Client_OrigUser(CLIENT *Client) {
  499. #ifndef IDENTAUTH
  500. char *user = Client->user;
  501. if (user[0] == '~')
  502. user++;
  503. return user;
  504. #else
  505. return Client->orig_user;
  506. #endif
  507. } /* Client_OrigUser */
  508. #endif
  509. /**
  510. * Return the hostname of a client.
  511. * @param Client Pointer to client structure
  512. * @return Pointer to client hostname
  513. */
  514. GLOBAL char *
  515. Client_Hostname(CLIENT *Client)
  516. {
  517. assert (Client != NULL);
  518. return Client->host;
  519. } /* Client_Hostname */
  520. /**
  521. * Get potentially cloaked hostname of a client.
  522. * If the client has not enabled cloaking, the real hostname is used.
  523. * @param Client Pointer to client structure
  524. * @return Pointer to client hostname
  525. */
  526. GLOBAL char *
  527. Client_HostnameCloaked(CLIENT *Client)
  528. {
  529. assert(Client != NULL);
  530. if (Client_HasMode(Client, 'x'))
  531. return Client_ID(Client->introducer);
  532. else
  533. return Client_Hostname(Client);
  534. } /* Client_HostnameCloaked */
  535. GLOBAL char *
  536. Client_Password( CLIENT *Client )
  537. {
  538. assert( Client != NULL );
  539. return Client->pwd;
  540. } /* Client_Password */
  541. GLOBAL char *
  542. Client_Modes( CLIENT *Client )
  543. {
  544. assert( Client != NULL );
  545. return Client->modes;
  546. } /* Client_Modes */
  547. GLOBAL char *
  548. Client_Flags( CLIENT *Client )
  549. {
  550. assert( Client != NULL );
  551. return Client->flags;
  552. } /* Client_Flags */
  553. GLOBAL bool
  554. Client_OperByMe( CLIENT *Client )
  555. {
  556. assert( Client != NULL );
  557. return Client->oper_by_me;
  558. } /* Client_OperByMe */
  559. GLOBAL int
  560. Client_Hops( CLIENT *Client )
  561. {
  562. assert( Client != NULL );
  563. return Client->hops;
  564. } /* Client_Hops */
  565. GLOBAL int
  566. Client_Token( CLIENT *Client )
  567. {
  568. assert( Client != NULL );
  569. return Client->token;
  570. } /* Client_Token */
  571. GLOBAL int
  572. Client_MyToken( CLIENT *Client )
  573. {
  574. assert( Client != NULL );
  575. return Client->mytoken;
  576. } /* Client_MyToken */
  577. GLOBAL CLIENT *
  578. Client_NextHop( CLIENT *Client )
  579. {
  580. CLIENT *c;
  581. assert( Client != NULL );
  582. c = Client;
  583. while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server ))
  584. c = c->introducer;
  585. return c;
  586. } /* Client_NextHop */
  587. /**
  588. * Return ID of a client: "client!user@host"
  589. * This client ID is used for IRC prefixes, for example.
  590. * Please note that this function uses a global static buffer, so you can't
  591. * nest invocations without overwriting erlier results!
  592. * @param Client Pointer to client structure
  593. * @return Pointer to global buffer containing the client ID
  594. */
  595. GLOBAL char *
  596. Client_Mask( CLIENT *Client )
  597. {
  598. static char Mask_Buffer[GETID_LEN];
  599. assert (Client != NULL);
  600. /* Servers: return name only, there is no "mask" */
  601. if (Client->type == CLIENT_SERVER)
  602. return Client->id;
  603. snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
  604. Client->id, Client->user, Client->host);
  605. return Mask_Buffer;
  606. } /* Client_Mask */
  607. /**
  608. * Return ID of a client with cloaked hostname: "client!user@server-name"
  609. * This client ID is used for IRC prefixes, for example.
  610. * Please note that this function uses a global static buffer, so you can't
  611. * nest invocations without overwriting erlier results!
  612. * If the client has not enabled cloaking, the real hostname is used.
  613. * @param Client Pointer to client structure
  614. * @return Pointer to global buffer containing the client ID
  615. */
  616. GLOBAL char *
  617. Client_MaskCloaked(CLIENT *Client)
  618. {
  619. static char Mask_Buffer[GETID_LEN];
  620. assert (Client != NULL);
  621. /* Is the client using cloaking at all? */
  622. if (!Client_HasMode(Client, 'x'))
  623. return Client_Mask(Client);
  624. snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
  625. Client->id, Client->user, Client_ID(Client->introducer));
  626. return Mask_Buffer;
  627. } /* Client_MaskCloaked */
  628. GLOBAL CLIENT *
  629. Client_Introducer( CLIENT *Client )
  630. {
  631. assert( Client != NULL );
  632. return Client->introducer;
  633. } /* Client_Introducer */
  634. GLOBAL CLIENT *
  635. Client_TopServer( CLIENT *Client )
  636. {
  637. assert( Client != NULL );
  638. return Client->topserver;
  639. } /* Client_TopServer */
  640. GLOBAL bool
  641. Client_HasMode( CLIENT *Client, char Mode )
  642. {
  643. assert( Client != NULL );
  644. return strchr( Client->modes, Mode ) != NULL;
  645. } /* Client_HasMode */
  646. GLOBAL char *
  647. Client_Away( CLIENT *Client )
  648. {
  649. assert( Client != NULL );
  650. return Client->away;
  651. } /* Client_Away */
  652. GLOBAL bool
  653. Client_CheckNick( CLIENT *Client, char *Nick )
  654. {
  655. assert( Client != NULL );
  656. assert( Nick != NULL );
  657. if (! Client_IsValidNick( Nick ))
  658. {
  659. IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
  660. return false;
  661. }
  662. /* Nick bereits vergeben? */
  663. if( Client_Search( Nick ))
  664. {
  665. /* den Nick gibt es bereits */
  666. IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
  667. return false;
  668. }
  669. return true;
  670. } /* Client_CheckNick */
  671. GLOBAL bool
  672. Client_CheckID( CLIENT *Client, char *ID )
  673. {
  674. char str[COMMAND_LEN];
  675. CLIENT *c;
  676. assert( Client != NULL );
  677. assert( Client->conn_id > NONE );
  678. assert( ID != NULL );
  679. /* ID too long? */
  680. if (strlen(ID) > CLIENT_ID_LEN) {
  681. IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), ID);
  682. return false;
  683. }
  684. /* ID already in use? */
  685. c = My_Clients;
  686. while (c) {
  687. if (strcasecmp(c->id, ID) == 0) {
  688. snprintf(str, sizeof(str), "ID \"%s\" already registered", ID);
  689. if (c->conn_id != NONE)
  690. Log(LOG_ERR, "%s (on connection %d)!", str, c->conn_id);
  691. else
  692. Log(LOG_ERR, "%s (via network)!", str);
  693. Conn_Close(Client->conn_id, str, str, true);
  694. return false;
  695. }
  696. c = (CLIENT *)c->next;
  697. }
  698. return true;
  699. } /* Client_CheckID */
  700. GLOBAL CLIENT *
  701. Client_First( void )
  702. {
  703. return My_Clients;
  704. } /* Client_First */
  705. GLOBAL CLIENT *
  706. Client_Next( CLIENT *c )
  707. {
  708. assert( c != NULL );
  709. return (CLIENT *)c->next;
  710. } /* Client_Next */
  711. GLOBAL long
  712. Client_UserCount( void )
  713. {
  714. return Count( CLIENT_USER );
  715. } /* Client_UserCount */
  716. GLOBAL long
  717. Client_ServiceCount( void )
  718. {
  719. return Count( CLIENT_SERVICE );;
  720. } /* Client_ServiceCount */
  721. GLOBAL long
  722. Client_ServerCount( void )
  723. {
  724. return Count( CLIENT_SERVER );
  725. } /* Client_ServerCount */
  726. GLOBAL long
  727. Client_MyUserCount( void )
  728. {
  729. return MyCount( CLIENT_USER );
  730. } /* Client_MyUserCount */
  731. GLOBAL long
  732. Client_MyServiceCount( void )
  733. {
  734. return MyCount( CLIENT_SERVICE );
  735. } /* Client_MyServiceCount */
  736. GLOBAL unsigned long
  737. Client_MyServerCount( void )
  738. {
  739. CLIENT *c;
  740. unsigned long cnt = 0;
  741. c = My_Clients;
  742. while( c )
  743. {
  744. if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
  745. c = (CLIENT *)c->next;
  746. }
  747. return cnt;
  748. } /* Client_MyServerCount */
  749. GLOBAL unsigned long
  750. Client_OperCount( void )
  751. {
  752. CLIENT *c;
  753. unsigned long cnt = 0;
  754. c = My_Clients;
  755. while( c )
  756. {
  757. if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
  758. c = (CLIENT *)c->next;
  759. }
  760. return cnt;
  761. } /* Client_OperCount */
  762. GLOBAL unsigned long
  763. Client_UnknownCount( void )
  764. {
  765. CLIENT *c;
  766. unsigned long cnt = 0;
  767. c = My_Clients;
  768. while( c )
  769. {
  770. if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
  771. c = (CLIENT *)c->next;
  772. }
  773. return cnt;
  774. } /* Client_UnknownCount */
  775. GLOBAL long
  776. Client_MaxUserCount( void )
  777. {
  778. return Max_Users;
  779. } /* Client_MaxUserCount */
  780. GLOBAL long
  781. Client_MyMaxUserCount( void )
  782. {
  783. return My_Max_Users;
  784. } /* Client_MyMaxUserCount */
  785. GLOBAL bool
  786. Client_IsValidNick( const char *Nick )
  787. {
  788. const char *ptr;
  789. static const char goodchars[] = ";0123456789-";
  790. assert( Nick != NULL );
  791. if( Nick[0] == '#' ) return false;
  792. if( strchr( goodchars, Nick[0] )) return false;
  793. if( strlen( Nick ) >= Conf_MaxNickLength) return false;
  794. ptr = Nick;
  795. while( *ptr )
  796. {
  797. if (( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
  798. if ( *ptr > '}' ) return false;
  799. ptr++;
  800. }
  801. return true;
  802. } /* Client_IsValidNick */
  803. /**
  804. * Return pointer to "My_Whowas" structure.
  805. */
  806. GLOBAL WHOWAS *
  807. Client_GetWhowas( void )
  808. {
  809. return My_Whowas;
  810. } /* Client_GetWhowas */
  811. /**
  812. * Return the index of the last used WHOWAS entry.
  813. */
  814. GLOBAL int
  815. Client_GetLastWhowasIndex( void )
  816. {
  817. return Last_Whowas;
  818. } /* Client_GetLastWhowasIndex */
  819. /**
  820. * Get the start time of this client.
  821. * The result is the start time in seconds since 1970-01-01, as reported
  822. * by the C function time(NULL).
  823. */
  824. GLOBAL time_t
  825. Client_StartTime(CLIENT *Client)
  826. {
  827. assert( Client != NULL );
  828. return Client->starttime;
  829. } /* Client_Uptime */
  830. static unsigned long
  831. Count( CLIENT_TYPE Type )
  832. {
  833. CLIENT *c;
  834. unsigned long cnt = 0;
  835. c = My_Clients;
  836. while( c )
  837. {
  838. if( c->type == Type ) cnt++;
  839. c = (CLIENT *)c->next;
  840. }
  841. return cnt;
  842. } /* Count */
  843. static unsigned long
  844. MyCount( CLIENT_TYPE Type )
  845. {
  846. CLIENT *c;
  847. unsigned long cnt = 0;
  848. c = My_Clients;
  849. while( c )
  850. {
  851. if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
  852. c = (CLIENT *)c->next;
  853. }
  854. return cnt;
  855. } /* MyCount */
  856. static CLIENT *
  857. New_Client_Struct( void )
  858. {
  859. /* Neue CLIENT-Struktur pre-initialisieren */
  860. CLIENT *c;
  861. c = (CLIENT *)malloc( sizeof( CLIENT ));
  862. if( ! c )
  863. {
  864. Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
  865. return NULL;
  866. }
  867. memset( c, 0, sizeof ( CLIENT ));
  868. c->type = CLIENT_UNKNOWN;
  869. c->conn_id = NONE;
  870. c->oper_by_me = false;
  871. c->hops = -1;
  872. c->token = -1;
  873. c->mytoken = -1;
  874. return c;
  875. } /* New_Client */
  876. static void
  877. Generate_MyToken( CLIENT *Client )
  878. {
  879. CLIENT *c;
  880. int token;
  881. c = My_Clients;
  882. token = 2;
  883. while( c )
  884. {
  885. if( c->mytoken == token )
  886. {
  887. /* Das Token wurde bereits vergeben */
  888. token++;
  889. c = My_Clients;
  890. continue;
  891. }
  892. else c = (CLIENT *)c->next;
  893. }
  894. Client->mytoken = token;
  895. LogDebug("Assigned token %d to server \"%s\".", token, Client->id);
  896. } /* Generate_MyToken */
  897. static void
  898. Adjust_Counters( CLIENT *Client )
  899. {
  900. long count;
  901. assert( Client != NULL );
  902. if( Client->type != CLIENT_USER ) return;
  903. if( Client->conn_id != NONE )
  904. {
  905. /* Local connection */
  906. count = Client_MyUserCount( );
  907. if( count > My_Max_Users ) My_Max_Users = count;
  908. }
  909. count = Client_UserCount( );
  910. if( count > Max_Users ) Max_Users = count;
  911. } /* Adjust_Counters */
  912. /**
  913. * Register client in My_Whowas structure for further recall by WHOWAS.
  914. * Note: Only clients that have been connected at least 30 seconds will be
  915. * registered to prevent automated IRC bots to "destroy" a nice server
  916. * history database.
  917. */
  918. GLOBAL void
  919. Client_RegisterWhowas( CLIENT *Client )
  920. {
  921. int slot;
  922. time_t now;
  923. assert( Client != NULL );
  924. now = time(NULL);
  925. /* Don't register clients that were connected less than 30 seconds. */
  926. if( now - Client->starttime < 30 )
  927. return;
  928. slot = Last_Whowas + 1;
  929. if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
  930. #ifdef DEBUG
  931. Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
  932. #endif
  933. My_Whowas[slot].time = now;
  934. strlcpy( My_Whowas[slot].id, Client_ID( Client ),
  935. sizeof( My_Whowas[slot].id ));
  936. strlcpy( My_Whowas[slot].user, Client_User( Client ),
  937. sizeof( My_Whowas[slot].user ));
  938. strlcpy( My_Whowas[slot].host, Client_HostnameCloaked( Client ),
  939. sizeof( My_Whowas[slot].host ));
  940. strlcpy( My_Whowas[slot].info, Client_Info( Client ),
  941. sizeof( My_Whowas[slot].info ));
  942. strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
  943. sizeof( My_Whowas[slot].server ));
  944. Last_Whowas = slot;
  945. } /* Client_RegisterWhowas */
  946. GLOBAL const char *
  947. Client_TypeText(CLIENT *Client)
  948. {
  949. assert(Client != NULL);
  950. switch (Client_Type(Client)) {
  951. case CLIENT_USER:
  952. return "User";
  953. break;
  954. case CLIENT_SERVICE:
  955. return "Service";
  956. break;
  957. case CLIENT_SERVER:
  958. return "Server";
  959. break;
  960. default:
  961. return "Client";
  962. }
  963. } /* Client_TypeText */
  964. /**
  965. * Destroy user or service client.
  966. */
  967. static void
  968. Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool SendQuit)
  969. {
  970. if(Client->conn_id != NONE) {
  971. /* Local (directly connected) client */
  972. Log(LOG_NOTICE,
  973. "%s \"%s\" unregistered (connection %d): %s",
  974. Client_TypeText(Client), Client_Mask(Client),
  975. Client->conn_id, Txt);
  976. Log_ServerNotice('c', "Client exiting: %s (%s@%s) [%s]",
  977. Client_ID(Client), Client_User(Client),
  978. Client_Hostname(Client), Txt);
  979. if (SendQuit) {
  980. /* Inforam all the other servers */
  981. if (FwdMsg)
  982. IRC_WriteStrServersPrefix(NULL,
  983. Client, "QUIT :%s", FwdMsg );
  984. else
  985. IRC_WriteStrServersPrefix(NULL,
  986. Client, "QUIT :");
  987. }
  988. } else {
  989. /* Remote client */
  990. LogDebug("%s \"%s\" unregistered: %s",
  991. Client_TypeText(Client), Client_Mask(Client), Txt);
  992. if(SendQuit) {
  993. /* Inform all the other servers, but the ones in the
  994. * direction we got the QUIT from */
  995. if(FwdMsg)
  996. IRC_WriteStrServersPrefix(Client_NextHop(Client),
  997. Client, "QUIT :%s", FwdMsg );
  998. else
  999. IRC_WriteStrServersPrefix(Client_NextHop(Client),
  1000. Client, "QUIT :" );
  1001. }
  1002. }
  1003. /* Unregister client from channels */
  1004. Channel_Quit(Client, FwdMsg ? FwdMsg : Client->id);
  1005. /* Register client in My_Whowas structure */
  1006. Client_RegisterWhowas(Client);
  1007. } /* Destroy_UserOrService */
  1008. #ifdef DEBUG
  1009. GLOBAL void
  1010. Client_DebugDump(void)
  1011. {
  1012. CLIENT *c;
  1013. Log(LOG_DEBUG, "Client status:");
  1014. c = My_Clients;
  1015. while (c) {
  1016. Log(LOG_DEBUG,
  1017. " - %s: type=%d, host=%s, user=%s, conn=%d, start=%ld, flags=%s",
  1018. Client_ID(c), Client_Type(c), Client_Hostname(c),
  1019. Client_User(c), Client_Conn(c), Client_StartTime(c),
  1020. Client_Flags(c));
  1021. c = (CLIENT *)c->next;
  1022. }
  1023. } /* Client_DumpClients */
  1024. #endif
  1025. /* -eof- */