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