]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/usermanager.cpp
d518b790efa1c06046ea0f2765426523a2996d78
[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         New->SetSockAddr(socketfamily, ipaddr, port);
53
54         New->SetFd(socket);
55
56         /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
57         for (const char* temp = New->GetIPString(); *temp && j < 64; temp++, j++)
58                 New->dhost[j] = New->host[j] = *temp;
59         New->dhost[j] = New->host[j] = 0;
60
61         Instance->Users->AddLocalClone(New);
62         Instance->Users->AddGlobalClone(New);
63
64         /*
65          * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
66          * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
67          */
68         ConnectClass* i = New->SetClass();
69
70         if (!i)
71         {
72                 User::QuitUser(Instance, New, "Access denied by configuration");
73                 return;
74         }
75
76         /*
77          * Check connect class settings and initialise settings into User.
78          * This will be done again after DNS resolution. -- w00t
79          */
80         New->CheckClass();
81
82         Instance->local_users.push_back(New);
83
84         if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS))
85         {
86                 Instance->WriteOpers("*** Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);
87                 User::QuitUser(Instance, New,"No more connections allowed");
88                 return;
89         }
90
91         /*
92          * XXX -
93          * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
94          * its a pretty big but for the moment valid assumption:
95          * file descriptors are handed out starting at 0, and are recycled as theyre freed.
96          * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
97          * irc server at once (or the irc server otherwise initiating this many connections, files etc)
98          * which for the time being is a physical impossibility (even the largest networks dont have more
99          * than about 10,000 users on ONE server!)
100          */
101 #ifndef WINDOWS
102         if ((unsigned int)socket >= MAX_DESCRIPTORS)
103         {
104                 User::QuitUser(Instance, New, "Server is full");
105                 return;
106         }
107 #endif
108         /*
109          * even with bancache, we still have to keep User::exempt current.
110          * besides that, if we get a positive bancache hit, we still won't fuck
111          * them over if they are exempt. -- w00t
112          */
113         New->exempt = (Instance->XLines->MatchesLine("E",New) != NULL);
114
115         if (BanCacheHit *b = Instance->BanCache->GetHit(New->GetIPString()))
116         {
117                 if (!b->Type.empty() && !New->exempt)
118                 {
119                         /* user banned */
120                         Instance->Log(DEBUG, std::string("BanCache: Positive hit for ") + New->GetIPString());
121                         if (*Instance->Config->MoronBanner)
122                                 New->WriteServ("NOTICE %s :*** %s", New->nick, Instance->Config->MoronBanner);
123                         User::QuitUser(Instance, New, b->Reason);
124                         return;
125                 }
126                 else
127                 {
128                         Instance->Log(DEBUG, std::string("BanCache: Negative hit for ") + New->GetIPString());
129                 }
130         }
131         else
132         {
133                 if (!New->exempt)
134                 {
135                         XLine* r = Instance->XLines->MatchesLine("Z",New);
136
137                         if (r)
138                         {
139                                 r->Apply(New);
140                                 return;
141                         }
142                 }
143         }
144
145         if (socket > -1)
146         {
147                 if (!Instance->SE->AddFd(New))
148                 {
149                         Instance->Log(DEBUG,"Internal error on new connection");
150                         User::QuitUser(Instance, New, "Internal error handling connection");
151                 }
152         }
153
154         /* NOTE: even if dns lookups are *off*, we still need to display this.
155          * BOPM and other stuff requires it.
156          */
157         New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
158
159         if (Instance->Config->NoUserDns)
160         {
161                 New->dns_done = true;
162         }
163         else
164         {
165                 New->StartDNSLookup();
166         }
167 }
168
169 void UserManager::AddLocalClone(User *user)
170 {
171         clonemap::iterator x = local_clones.find(user->GetIPString());
172         if (x != local_clones.end())
173                 x->second++;
174         else
175                 local_clones[user->GetIPString()] = 1;
176 }
177
178 void UserManager::AddGlobalClone(User *user)
179 {
180         clonemap::iterator y = global_clones.find(user->GetIPString());
181         if (y != global_clones.end())
182                 y->second++;
183         else
184                 global_clones[user->GetIPString()] = 1;
185 }
186
187 void UserManager::RemoveCloneCounts(User *user)
188 {
189         clonemap::iterator x = local_clones.find(user->GetIPString());
190         if (x != local_clones.end())
191         {
192                 x->second--;
193                 if (!x->second)
194                 {
195                         local_clones.erase(x);
196                 }
197         }
198         
199         clonemap::iterator y = global_clones.find(user->GetIPString());
200         if (y != global_clones.end())
201         {
202                 y->second--;
203                 if (!y->second)
204                 {
205                         global_clones.erase(y);
206                 }
207         }
208 }
209
210 unsigned long UserManager::GlobalCloneCount(User *user)
211 {
212         clonemap::iterator x = global_clones.find(user->GetIPString());
213         if (x != global_clones.end())
214                 return x->second;
215         else
216                 return 0;
217 }
218
219 unsigned long UserManager::LocalCloneCount(User *user)
220 {
221         clonemap::iterator x = local_clones.find(user->GetIPString());
222         if (x != local_clones.end())
223                 return x->second;
224         else
225                 return 0;
226 }