]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/usermanager.cpp
Return server port in GetPort rather than the arbitrary client port
[user/henk/code/inspircd.git] / src / usermanager.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core */
15
16 #include "inspircd.h"
17 #include "xline.h"
18 #include "bancache.h"
19
20 /* add a client connection to the sockets list */
21 void UserManager::AddUser(InspIRCd* Instance, int socket, int port, bool iscached, irc::sockets::sockaddrs* ip, const std::string &targetip)
22 {
23         /* NOTE: Calling this one parameter constructor for User automatically
24          * allocates a new UUID and places it in the hash_map.
25          */
26         User* New = NULL;
27         try
28         {
29                 New = new User(Instance);
30         }
31         catch (...)
32         {
33                 Instance->Logs->Log("USERS", DEFAULT,"*** WTF *** Duplicated UUID! -- Crack smoking monkies have been unleashed.");
34                 Instance->SNO->WriteToSnoMask('a', "WARNING *** Duplicate UUID allocated!");
35                 return;
36         }
37
38         New->SetFd(socket);
39         memcpy(&New->ip, ip, sizeof(*ip));
40         // change the port number of their stored sockaddr to be the server port rather than the client port
41         if (New->ip.sa.sa_family == AF_INET6)
42                 New->ip.in6.sin6_port = port;
43         else
44                 New->ip.in4.sin_port = port;
45
46
47         /* Give each of the modules an attempt to hook the user for I/O */
48         FOREACH_MOD_I(Instance, I_OnHookUserIO, OnHookUserIO(New, targetip));
49
50         if (New->GetIOHook())
51         {
52                 try
53                 {
54                         New->GetIOHook()->OnRawSocketAccept(socket, New->GetIPString(), port);
55                 }
56                 catch (CoreException& modexcept)
57                 {
58                         ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
59                 }
60         }
61
62         Instance->Logs->Log("USERS", DEBUG,"New user fd: %d", socket);
63
64         this->unregistered_count++;
65
66         (*(this->clientlist))[New->uuid] = New;
67
68         /* The users default nick is their UUID */
69         New->nick.assign(New->uuid, 0, ServerInstance->Config->Limits.NickMax);
70
71         New->server = Instance->FindServerNamePtr(Instance->Config->ServerName);
72         New->ident.assign("unknown");
73
74         New->registered = REG_NONE;
75         New->signon = Instance->Time() + Instance->Config->dns_timeout;
76         New->lastping = 1;
77
78         /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
79         New->dhost.assign(New->GetIPString(), 0, 64);
80         New->host.assign(New->GetIPString(), 0, 64);
81
82         Instance->Users->AddLocalClone(New);
83         Instance->Users->AddGlobalClone(New);
84
85         /*
86          * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
87          * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
88          */
89         ConnectClass* i = New->SetClass();
90
91         if (!i)
92         {
93                 this->QuitUser(New, "Access denied by configuration");
94                 return;
95         }
96
97         /*
98          * Check connect class settings and initialise settings into User.
99          * This will be done again after DNS resolution. -- w00t
100          */
101         New->CheckClass();
102
103         this->local_users.push_back(New);
104
105         if ((this->local_users.size() > Instance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)Instance->SE->GetMaxFds()))
106         {
107                 Instance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);
108                 this->QuitUser(New,"No more connections allowed");
109                 return;
110         }
111
112         /*
113          * even with bancache, we still have to keep User::exempt current.
114          * besides that, if we get a positive bancache hit, we still won't fuck
115          * them over if they are exempt. -- w00t
116          */
117         New->exempt = (Instance->XLines->MatchesLine("E",New) != NULL);
118
119         if (BanCacheHit *b = Instance->BanCache->GetHit(New->GetIPString()))
120         {
121                 if (!b->Type.empty() && !New->exempt)
122                 {
123                         /* user banned */
124                         Instance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Positive hit for ") + New->GetIPString());
125                         if (*Instance->Config->MoronBanner)
126                                 New->WriteServ("NOTICE %s :*** %s", New->nick.c_str(), Instance->Config->MoronBanner);
127                         this->QuitUser(New, b->Reason);
128                         return;
129                 }
130                 else
131                 {
132                         Instance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Negative hit for ") + New->GetIPString());
133                 }
134         }
135         else
136         {
137                 if (!New->exempt)
138                 {
139                         XLine* r = Instance->XLines->MatchesLine("Z",New);
140
141                         if (r)
142                         {
143                                 r->Apply(New);
144                                 return;
145                         }
146                 }
147         }
148
149         if (!Instance->SE->AddFd(New))
150         {
151                 Instance->Logs->Log("USERS", DEBUG,"Internal error on new connection");
152                 this->QuitUser(New, "Internal error handling connection");
153         }
154
155         /* NOTE: even if dns lookups are *off*, we still need to display this.
156          * BOPM and other stuff requires it.
157          */
158         New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
159
160         if (Instance->Config->NoUserDns)
161         {
162                 New->WriteServ("NOTICE %s :*** Skipping host resolution (disabled by server administrator)", New->nick.c_str());
163                 New->dns_done = true;
164         }
165         else
166         {
167                 New->StartDNSLookup();
168         }
169 }
170
171 void UserManager::QuitUser(User *user, const std::string &quitreason, const char* operreason)
172 {
173         if (user->quitting)
174         {
175                 ServerInstance->Logs->Log("CULLLIST",DEBUG, "*** Warning *** - You tried to quit a user (%s) twice. Did your module call QuitUser twice?", user->nick.c_str());
176                 return;
177         }
178
179         user->quitting = true;
180
181         ServerInstance->Logs->Log("USERS", DEBUG, "QuitUser: %s '%s'", user->nick.c_str(), quitreason.c_str());
182         user->Write("ERROR :Closing link: (%s@%s) [%s]", user->ident.c_str(), user->host.c_str(), *operreason ? operreason : quitreason.c_str());
183
184         user->quietquit = false;
185         user->quitmsg = quitreason;
186
187         std::string reason;
188         std::string oper_reason;
189         reason.assign(quitreason, 0, ServerInstance->Config->Limits.MaxQuit);
190         if (!*operreason)
191         {
192                 user->operquitmsg = quitreason;
193                 oper_reason.assign(quitreason, 0, ServerInstance->Config->Limits.MaxQuit);
194         }
195         else
196         {
197                 user->operquitmsg = operreason;
198                 oper_reason.assign(operreason, 0, ServerInstance->Config->Limits.MaxQuit);
199         }
200
201         ServerInstance->GlobalCulls.AddItem(user);
202
203         if (user->registered == REG_ALL)
204         {
205                 FOREACH_MOD_I(ServerInstance,I_OnUserQuit,OnUserQuit(user, reason, oper_reason));
206                 user->PurgeEmptyChannels();
207                 user->WriteCommonQuit(reason, oper_reason);
208         }
209
210         FOREACH_MOD_I(ServerInstance,I_OnUserDisconnect,OnUserDisconnect(user));
211
212         // Move the user onto their UID, to allow nick to be reused immediately
213         user->UpdateNickHash(user->uuid.c_str());
214 }
215
216
217 void UserManager::AddLocalClone(User *user)
218 {
219         int range = 32;
220         clonemap::iterator x;
221         switch (user->ip.sa.sa_family)
222         {
223                 case AF_INET6:
224                         range = ServerInstance->Config->c_ipv6_range;
225                 break;
226                 case AF_INET:
227                         range = ServerInstance->Config->c_ipv4_range;
228                 break;
229         }
230
231         x = local_clones.find(user->GetCIDRMask(range));
232         if (x != local_clones.end())
233                 x->second++;
234         else
235                 local_clones[user->GetCIDRMask(range)] = 1;
236 }
237
238 void UserManager::AddGlobalClone(User *user)
239 {
240         int range = 32;
241         clonemap::iterator x;
242         switch (user->ip.sa.sa_family)
243         {
244                 case AF_INET6:
245                         range = ServerInstance->Config->c_ipv6_range;
246                 break;
247                 case AF_INET:
248                         range = ServerInstance->Config->c_ipv4_range;
249                 break;
250         }
251
252         x = global_clones.find(user->GetCIDRMask(range));
253         if (x != global_clones.end())
254                 x->second++;
255         else
256                 global_clones[user->GetCIDRMask(range)] = 1;
257 }
258
259 void UserManager::RemoveCloneCounts(User *user)
260 {
261         int range = 32;
262         switch (user->ip.sa.sa_family)
263         {
264                 case AF_INET6:
265                         range = ServerInstance->Config->c_ipv6_range;
266                 break;
267                 case AF_INET:
268                         range = ServerInstance->Config->c_ipv4_range;
269                 break;
270         }
271
272         clonemap::iterator x = local_clones.find(user->GetCIDRMask(range));
273         if (x != local_clones.end())
274         {
275                 x->second--;
276                 if (!x->second)
277                 {
278                         local_clones.erase(x);
279                 }
280         }
281
282         clonemap::iterator y = global_clones.find(user->GetCIDRMask(range));
283         if (y != global_clones.end())
284         {
285                 y->second--;
286                 if (!y->second)
287                 {
288                         global_clones.erase(y);
289                 }
290         }
291 }
292
293 unsigned long UserManager::GlobalCloneCount(User *user)
294 {
295         int range = 32;
296         switch (user->ip.sa.sa_family)
297         {
298                 case AF_INET6:
299                         range = ServerInstance->Config->c_ipv6_range;
300                 break;
301                 case AF_INET:
302                         range = ServerInstance->Config->c_ipv4_range;
303                 break;
304         }
305         clonemap::iterator x = global_clones.find(user->GetCIDRMask(range));
306         if (x != global_clones.end())
307                 return x->second;
308         else
309                 return 0;
310 }
311
312 unsigned long UserManager::LocalCloneCount(User *user)
313 {
314         int range = 32;
315         switch (user->ip.sa.sa_family)
316         {
317                 case AF_INET6:
318                         range = ServerInstance->Config->c_ipv6_range;
319                 break;
320                 case AF_INET:
321                         range = ServerInstance->Config->c_ipv4_range;
322                 break;
323         }
324         clonemap::iterator x = local_clones.find(user->GetCIDRMask(range));
325         if (x != local_clones.end())
326                 return x->second;
327         else
328                 return 0;
329 }
330
331 /* this function counts all users connected, wether they are registered or NOT. */
332 unsigned int UserManager::UserCount()
333 {
334         /*
335          * XXX: Todo:
336          *  As part of this restructuring, move clientlist/etc fields into usermanager.
337          *      -- w00t
338          */
339         return this->clientlist->size();
340 }
341
342 /* this counts only registered users, so that the percentages in /MAP don't mess up */
343 unsigned int UserManager::RegisteredUserCount()
344 {
345         return this->clientlist->size() - this->UnregisteredUserCount();
346 }
347
348 /* return how many users are opered */
349 unsigned int UserManager::OperCount()
350 {
351         return this->all_opers.size();
352 }
353
354 /* return how many users are unregistered */
355 unsigned int UserManager::UnregisteredUserCount()
356 {
357         return this->unregistered_count;
358 }
359
360 /* return how many local registered users there are */
361 unsigned int UserManager::LocalUserCount()
362 {
363         /* Doesnt count unregistered clients */
364         return (this->local_users.size() - this->UnregisteredUserCount());
365 }
366
367 void UserManager::ServerNoticeAll(const char* text, ...)
368 {
369         if (!text)
370                 return;
371
372         char textbuffer[MAXBUF];
373         char formatbuffer[MAXBUF];
374         va_list argsPtr;
375         va_start (argsPtr, text);
376         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
377         va_end(argsPtr);
378
379         snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s", ServerInstance->Config->ServerName, textbuffer);
380
381         for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
382         {
383                 User* t = *i;
384                 t->WriteServ(std::string(formatbuffer));
385         }
386 }
387
388 void UserManager::ServerPrivmsgAll(const char* text, ...)
389 {
390         if (!text)
391                 return;
392
393         char textbuffer[MAXBUF];
394         char formatbuffer[MAXBUF];
395         va_list argsPtr;
396         va_start (argsPtr, text);
397         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
398         va_end(argsPtr);
399
400         snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s", ServerInstance->Config->ServerName, textbuffer);
401
402         for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
403         {
404                 User* t = *i;
405                 t->WriteServ(std::string(formatbuffer));
406         }
407 }
408
409 void UserManager::WriteMode(const char* modes, int flags, const char* text, ...)
410 {
411         char textbuffer[MAXBUF];
412         int modelen;
413         va_list argsPtr;
414
415         if (!text || !modes || !flags)
416         {
417                 ServerInstance->Logs->Log("USERS", DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
418                 return;
419         }
420
421         va_start(argsPtr, text);
422         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
423         va_end(argsPtr);
424         modelen = strlen(modes);
425
426         if (flags == WM_AND)
427         {
428                 for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
429                 {
430                         User* t = *i;
431                         bool send_to_user = true;
432
433                         for (int n = 0; n < modelen; n++)
434                         {
435                                 if (!t->IsModeSet(modes[n]))
436                                 {
437                                         send_to_user = false;
438                                         break;
439                                 }
440                         }
441                         if (send_to_user)
442                         {
443                                 t->WriteServ("NOTICE %s :%s", t->nick.c_str(), textbuffer);
444                         }
445                 }
446         }
447         else if (flags == WM_OR)
448         {
449                 for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
450                 {
451                         User* t = *i;
452                         bool send_to_user = false;
453
454                         for (int n = 0; n < modelen; n++)
455                         {
456                                 if (t->IsModeSet(modes[n]))
457                                 {
458                                         send_to_user = true;
459                                         break;
460                                 }
461                         }
462
463                         if (send_to_user)
464                         {
465                                 t->WriteServ("NOTICE %s :%s", t->nick.c_str(), textbuffer);
466                         }
467                 }
468         }
469 }
470
471 /* return how many users have a given mode e.g. 'a' */
472 int UserManager::ModeCount(const char mode)
473 {
474         ModeHandler* mh = this->ServerInstance->Modes->FindMode(mode, MODETYPE_USER);
475
476         if (mh)
477                 return mh->GetCount();
478         else
479                 return 0;
480 }