]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/usermanager.cpp
Undo my constructor playing, I'm pretty sure it will break stuff. This will require...
[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->WriteOpers("*** WARNING *** Duplicate UUID allocated!");
35                 return;
36         }
37
38         Instance->Log(DEBUG,"New user fd: %d", socket);
39
40         int j = 0;
41
42         Instance->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         (*(Instance->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         Instance->local_users.push_back(New);
96
97         if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS))
98         {
99                 Instance->WriteOpers("*** 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 (socket > -1)
159         {
160                 if (!Instance->SE->AddFd(New))
161                 {
162                         Instance->Log(DEBUG,"Internal error on new connection");
163                         User::QuitUser(Instance, New, "Internal error handling connection");
164                 }
165         }
166
167         /* NOTE: even if dns lookups are *off*, we still need to display this.
168          * BOPM and other stuff requires it.
169          */
170         New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
171
172         if (Instance->Config->NoUserDns)
173         {
174                 New->dns_done = true;
175         }
176         else
177         {
178                 New->StartDNSLookup();
179         }
180 }
181
182 void UserManager::AddLocalClone(User *user)
183 {
184         clonemap::iterator x = local_clones.find(user->GetIPString());
185         if (x != local_clones.end())
186                 x->second++;
187         else
188                 local_clones[user->GetIPString()] = 1;
189 }
190
191 void UserManager::AddGlobalClone(User *user)
192 {
193         clonemap::iterator y = global_clones.find(user->GetIPString());
194         if (y != global_clones.end())
195                 y->second++;
196         else
197                 global_clones[user->GetIPString()] = 1;
198 }
199
200 void UserManager::RemoveCloneCounts(User *user)
201 {
202         clonemap::iterator x = local_clones.find(user->GetIPString());
203         if (x != local_clones.end())
204         {
205                 x->second--;
206                 if (!x->second)
207                 {
208                         local_clones.erase(x);
209                 }
210         }
211         
212         clonemap::iterator y = global_clones.find(user->GetIPString());
213         if (y != global_clones.end())
214         {
215                 y->second--;
216                 if (!y->second)
217                 {
218                         global_clones.erase(y);
219                 }
220         }
221 }
222
223 unsigned long UserManager::GlobalCloneCount(User *user)
224 {
225         clonemap::iterator x = global_clones.find(user->GetIPString());
226         if (x != global_clones.end())
227                 return x->second;
228         else
229                 return 0;
230 }
231
232 unsigned long UserManager::LocalCloneCount(User *user)
233 {
234         clonemap::iterator x = local_clones.find(user->GetIPString());
235         if (x != local_clones.end())
236                 return x->second;
237         else
238                 return 0;
239 }