]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/usermanager.cpp
Fix user->host not being assigned correctly for new connections
[user/henk/code/inspircd.git] / src / usermanager.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDusermanager */
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, int socketfamily, sockaddr* 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         char ipaddr[MAXBUF];
39 #ifdef IPV6
40         if (socketfamily == AF_INET6)
41                 inet_ntop(AF_INET6, &((const sockaddr_in6*)ip)->sin6_addr, ipaddr, sizeof(ipaddr));
42         else
43 #endif
44                 inet_ntop(AF_INET, &((const sockaddr_in*)ip)->sin_addr, ipaddr, sizeof(ipaddr));
45
46         New->SetFd(socket);
47         New->SetSockAddr(socketfamily, ipaddr, port);
48
49         /* Give each of the modules an attempt to hook the user for I/O */
50         FOREACH_MOD_I(Instance, I_OnHookUserIO, OnHookUserIO(New, targetip));
51
52         if (New->io)
53         {
54                 try
55                 {
56                         New->io->OnRawSocketAccept(socket, ipaddr, port);
57                 }
58                 catch (CoreException& modexcept)
59                 {
60                         ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
61                 }
62         }
63
64         Instance->Logs->Log("USERS", DEBUG,"New user fd: %d", socket);
65
66         this->unregistered_count++;
67
68         (*(this->clientlist))[New->uuid] = New;
69
70         /* The users default nick is their UUID */
71         New->nick.assign(New->uuid, 0, NICKMAX - 1);
72
73         New->server = Instance->FindServerNamePtr(Instance->Config->ServerName);
74         New->ident.assign("unknown");
75
76         New->registered = REG_NONE;
77         New->signon = Instance->Time() + Instance->Config->dns_timeout;
78         New->lastping = 1;
79
80         /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
81         New->dhost.assign(New->host.assign(New->GetIPString(), 64));
82
83         Instance->Users->AddLocalClone(New);
84         Instance->Users->AddGlobalClone(New);
85
86         /*
87          * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
88          * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
89          */
90         ConnectClass* i = New->SetClass();
91
92         if (!i)
93         {
94                 this->QuitUser(New, "Access denied by configuration");
95                 return;
96         }
97
98         /*
99          * Check connect class settings and initialise settings into User.
100          * This will be done again after DNS resolution. -- w00t
101          */
102         New->CheckClass();
103
104         this->local_users.push_back(New);
105
106         if ((this->local_users.size() > Instance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)Instance->SE->GetMaxFds()))
107         {
108                 Instance->SNO->WriteToSnoMask('A', "Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);
109                 this->QuitUser(New,"No more connections allowed");
110                 return;
111         }
112
113         /*
114          * XXX -
115          * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
116          * its a pretty big but for the moment valid assumption:
117          * file descriptors are handed out starting at 0, and are recycled as theyre freed.
118          * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
119          * irc server at once (or the irc server otherwise initiating this many connections, files etc)
120          * which for the time being is a physical impossibility (even the largest networks dont have more
121          * than about 10,000 users on ONE server!)
122          */
123         if (socket >= Instance->SE->GetMaxFds())
124         {
125                 this->QuitUser(New, "Server is full");
126                 return;
127         }
128
129         /*
130          * even with bancache, we still have to keep User::exempt current.
131          * besides that, if we get a positive bancache hit, we still won't fuck
132          * them over if they are exempt. -- w00t
133          */
134         New->exempt = (Instance->XLines->MatchesLine("E",New) != NULL);
135
136         if (BanCacheHit *b = Instance->BanCache->GetHit(New->GetIPString()))
137         {
138                 if (!b->Type.empty() && !New->exempt)
139                 {
140                         /* user banned */
141                         Instance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Positive hit for ") + New->GetIPString());
142                         if (*Instance->Config->MoronBanner)
143                                 New->WriteServ("NOTICE %s :*** %s", New->nick.c_str(), Instance->Config->MoronBanner);
144                         this->QuitUser(New, b->Reason);
145                         return;
146                 }
147                 else
148                 {
149                         Instance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Negative hit for ") + New->GetIPString());
150                 }
151         }
152         else
153         {
154                 if (!New->exempt)
155                 {
156                         XLine* r = Instance->XLines->MatchesLine("Z",New);
157
158                         if (r)
159                         {
160                                 r->Apply(New);
161                                 return;
162                         }
163                 }
164         }
165
166         if (!Instance->SE->AddFd(New))
167         {
168                 Instance->Logs->Log("USERS", DEBUG,"Internal error on new connection");
169                 this->QuitUser(New, "Internal error handling connection");
170         }
171
172         /* NOTE: even if dns lookups are *off*, we still need to display this.
173          * BOPM and other stuff requires it.
174          */
175         New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
176
177         if (Instance->Config->NoUserDns)
178         {
179                 New->WriteServ("NOTICE %s :*** Skipping host resolution (disabled by server administrator)", New->nick.c_str());
180                 New->dns_done = true;
181         }
182         else
183         {
184                 New->StartDNSLookup();
185         }
186 }
187
188 void UserManager::QuitUser(User *user, const std::string &quitreason, const char* operreason)
189 {
190         ServerInstance->Logs->Log("USERS", DEBUG,"QuitUser: %s '%s'", user->nick.c_str(), quitreason.c_str());
191         user->Write("ERROR :Closing link (%s@%s) [%s]", user->ident.c_str(), user->host.c_str(), *operreason ? operreason : quitreason.c_str());
192         user->quietquit = false;
193         user->quitmsg = quitreason;
194
195         if (!*operreason)
196                 user->operquitmsg = quitreason;
197         else
198                 user->operquitmsg = operreason;
199
200         ServerInstance->GlobalCulls.AddItem(user);
201 }
202
203
204 void UserManager::AddLocalClone(User *user)
205 {
206         clonemap::iterator x = local_clones.find(user->GetIPString());
207         if (x != local_clones.end())
208                 x->second++;
209         else
210                 local_clones[user->GetIPString()] = 1;
211 }
212
213 void UserManager::AddGlobalClone(User *user)
214 {
215         clonemap::iterator y = global_clones.find(user->GetIPString());
216         if (y != global_clones.end())
217                 y->second++;
218         else
219                 global_clones[user->GetIPString()] = 1;
220 }
221
222 void UserManager::RemoveCloneCounts(User *user)
223 {
224         clonemap::iterator x = local_clones.find(user->GetIPString());
225         if (x != local_clones.end())
226         {
227                 x->second--;
228                 if (!x->second)
229                 {
230                         local_clones.erase(x);
231                 }
232         }
233         
234         clonemap::iterator y = global_clones.find(user->GetIPString());
235         if (y != global_clones.end())
236         {
237                 y->second--;
238                 if (!y->second)
239                 {
240                         global_clones.erase(y);
241                 }
242         }
243 }
244
245 unsigned long UserManager::GlobalCloneCount(User *user)
246 {
247         clonemap::iterator x = global_clones.find(user->GetIPString());
248         if (x != global_clones.end())
249                 return x->second;
250         else
251                 return 0;
252 }
253
254 unsigned long UserManager::LocalCloneCount(User *user)
255 {
256         clonemap::iterator x = local_clones.find(user->GetIPString());
257         if (x != local_clones.end())
258                 return x->second;
259         else
260                 return 0;
261 }
262
263 /* this function counts all users connected, wether they are registered or NOT. */
264 unsigned int UserManager::UserCount()
265 {
266         /*
267          * XXX: Todo:
268          *  As part of this restructuring, move clientlist/etc fields into usermanager.
269          *      -- w00t
270          */
271         return this->clientlist->size();
272 }
273
274 /* this counts only registered users, so that the percentages in /MAP don't mess up */
275 unsigned int UserManager::RegisteredUserCount()
276 {
277         return this->clientlist->size() - this->UnregisteredUserCount();
278 }
279
280 /* return how many users are opered */
281 unsigned int UserManager::OperCount()
282 {
283         return this->all_opers.size();
284 }
285
286 /* return how many users are unregistered */
287 unsigned int UserManager::UnregisteredUserCount()
288 {
289         return this->unregistered_count;
290 }
291
292 /* return how many local registered users there are */
293 unsigned int UserManager::LocalUserCount()
294 {
295         /* Doesnt count unregistered clients */
296         return (this->local_users.size() - this->UnregisteredUserCount());
297 }
298
299 void UserManager::ServerNoticeAll(const char* text, ...)
300 {
301         if (!text)
302                 return;
303
304         char textbuffer[MAXBUF];
305         char formatbuffer[MAXBUF];
306         va_list argsPtr;
307         va_start (argsPtr, text);
308         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
309         va_end(argsPtr);
310
311         snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s", ServerInstance->Config->ServerName, textbuffer);
312
313         for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
314         {
315                 User* t = *i;
316                 t->WriteServ(std::string(formatbuffer));
317         }
318 }
319
320 void UserManager::ServerPrivmsgAll(const char* text, ...)
321 {
322         if (!text)
323                 return;
324
325         char textbuffer[MAXBUF];
326         char formatbuffer[MAXBUF];
327         va_list argsPtr;
328         va_start (argsPtr, text);
329         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
330         va_end(argsPtr);
331
332         snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s", ServerInstance->Config->ServerName, textbuffer);
333
334         for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
335         {
336                 User* t = *i;
337                 t->WriteServ(std::string(formatbuffer));
338         }
339 }
340
341 void UserManager::WriteMode(const char* modes, int flags, const char* text, ...)
342 {
343         char textbuffer[MAXBUF];
344         int modelen;
345         va_list argsPtr;
346
347         if (!text || !modes || !flags)
348         {
349                 ServerInstance->Logs->Log("USERS", DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
350                 return;
351         }
352
353         va_start(argsPtr, text);
354         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
355         va_end(argsPtr);
356         modelen = strlen(modes);
357
358         if (flags == WM_AND)
359         {
360                 for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
361                 {
362                         User* t = *i;
363                         bool send_to_user = true;
364
365                         for (int n = 0; n < modelen; n++)
366                         {
367                                 if (!t->IsModeSet(modes[n]))
368                                 {
369                                         send_to_user = false;
370                                         break;
371                                 }
372                         }
373                         if (send_to_user)
374                         {
375                                 t->WriteServ("NOTICE %s :%s", t->nick.c_str(), textbuffer);
376                         }
377                 }
378         }
379         else if (flags == WM_OR)
380         {
381                 for (std::vector<User*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
382                 {
383                         User* t = *i;
384                         bool send_to_user = false;
385
386                         for (int n = 0; n < modelen; n++)
387                         {
388                                 if (t->IsModeSet(modes[n]))
389                                 {
390                                         send_to_user = true;
391                                         break;
392                                 }
393                         }
394
395                         if (send_to_user)
396                         {
397                                 t->WriteServ("NOTICE %s :%s", t->nick.c_str(), textbuffer);
398                         }
399                 }
400         }
401 }
402
403 /* return how many users have a given mode e.g. 'a' */
404 int UserManager::ModeCount(const char mode)
405 {
406         ModeHandler* mh = this->ServerInstance->Modes->FindMode(mode, MODETYPE_USER);
407
408         if (mh)
409                 return mh->GetCount();
410         else
411                 return 0;
412 }
413
414
415