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