]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_ident.cpp
a92249f84bb8104ef7edf7d85c7f3379705095a4
[user/henk/code/inspircd.git] / src / modules / m_ident.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include <stdio.h>
20 #include <string>
21 #include "users.h"
22 #include "channels.h"
23 #include "modules.h"
24 #include "inspircd.h"
25
26 /* $ModDesc: Provides support for RFC 1413 ident lookups */
27
28 // Version 1.5.0.0 - Updated to use InspSocket, faster and neater.
29
30 class RFC1413 : public InspSocket
31 {
32  protected:
33                          // Server* class used for core communications
34         insp_sockaddr sock_us;   // our port number
35         insp_sockaddr sock_them; // their port number
36         socklen_t uslen;         // length of our port number
37         socklen_t themlen;       // length of their port number
38         char ident_request[128]; // buffer used to make up the request string
39  public:
40
41         userrec* u;              // user record that the lookup is associated with
42         int ufd;
43
44         RFC1413(InspIRCd* SI, userrec* user, int maxtime) : InspSocket(SI, user->GetIPString(), 113, false, maxtime), u(user)
45         {
46                 ufd = user->GetFd();
47         }
48
49         virtual void OnTimeout()
50         {
51                 // When we timeout, the connection failed within the allowed timeframe,
52                 // so we just display a notice, and tidy off the ident_data.
53                 if (u && (Instance->SE->GetRef(ufd) == u))
54                 {
55             char *newident;
56             
57                         u->Shrink("ident_data");
58                         u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using ~"+std::string(u->ident)+" instead.");
59                     strcpy(newident,"~");
60             strlcat(newident,u->ident,IDENTMAX);
61             strlcpy(u->ident,newident,IDENTMAX);
62         }
63         }
64
65         virtual bool OnDataReady()
66         {
67                 char* ibuf = this->Read();
68                 if (ibuf)
69                 {
70                         char* savept;
71                         char* section = strtok_r(ibuf,":",&savept);
72                         while (section)
73                         {
74                                 if (strstr(section,"USERID"))
75                                 {
76                                         section = strtok_r(NULL,":",&savept);
77                                         if (section)
78                                         {
79                                                 // ID type, usually UNIX or OTHER... we dont want it, so read the next token
80                                                 section = strtok_r(NULL,":",&savept);
81                                                 if (section)
82                                                 {
83                                                         while (*section == ' ') section++; // strip leading spaces
84                                                         for (char* j = section; *j; j++)
85                                                         if ((*j < 33) || (*j > 126))
86                                                                 *j = '\0'; // truncate at invalid chars
87                                                         if (*section)
88                                                         {
89                                                                 if (u && (Instance->SE->GetRef(ufd) == u))
90                                                                 {
91                                                                         if (this->Instance->IsIdent(section))
92                                                                         {
93                                                                                 strlcpy(u->ident,section,IDENTMAX);
94                                                                                 Instance->Log(DEBUG,"IDENT SET: "+std::string(u->ident));
95                                                                                 u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident));
96                                                                         }
97                                                                 }
98                                                         }
99                                                         return false;
100                                                 }
101                                         }
102                                 }
103                                 section = strtok_r(NULL,":",&savept);
104                         }
105                 }
106                 return false;
107         }
108
109         virtual void OnClose()
110         {
111                 // tidy up after ourselves when the connection is done.
112                 // We receive this event straight after a timeout, too.
113                 //
114                 //
115                 // OK, now listen up. The weird looking check here is
116                 // REQUIRED. Don't try and optimize it away.
117                 //
118                 // When a socket is closed, it is not immediately removed
119                 // from the socket list, there can be a short delay
120                 // before it is culled from the list. This means that
121                 // without this check, there is a chance that a user
122                 // may not exist when we come to ::Shrink them, which
123                 // results in a segfault. The value of "u" may not
124                 // always be NULL at this point, so, what we do is
125                 // check against the fd_ref_table, to see if (1) the user
126                 // exists, and (2) its the SAME user, on the same file
127                 // descriptor that they were when the lookup began.
128                 //
129                 // Fixes issue reported by webs, 7 Jun 2006
130                 if (u && (Instance->SE->GetRef(ufd) == u))
131                 {
132                         u->Shrink("ident_data");
133                 }
134         }
135
136         virtual void OnError(InspSocketError e)
137         {
138                 if (u && (Instance->SE->GetRef(ufd) == u))
139                 {
140                         u->Shrink("ident_data");
141                 }
142         }
143
144         virtual bool OnConnected()
145         {
146                 Instance->Log(DEBUG,"Ident: connected");
147                 if (u && (Instance->SE->GetRef(ufd) == u))
148                 {
149                         uslen = sizeof(sock_us);
150                         themlen = sizeof(sock_them);
151                         if ((getsockname(this->u->GetFd(),(sockaddr*)&sock_us,&uslen) || getpeername(this->u->GetFd(), (sockaddr*)&sock_them, &themlen)))
152                         {
153                                 Instance->Log(DEBUG,"Ident: failed to get socket names, bailing");
154                                 return false;
155                         }
156                         else
157                         {
158                                 // send the request in the following format: theirsocket,oursocket
159 #ifdef IPV6
160                                 snprintf(ident_request,127,"%d,%d\r\n",ntohs(sock_them.sin6_port),ntohs(sock_us.sin6_port));
161 #else
162                                 snprintf(ident_request,127,"%d,%d\r\n",ntohs(sock_them.sin_port),ntohs(sock_us.sin_port));
163 #endif
164                                 this->Write(ident_request);
165                                 Instance->Log(DEBUG,"Sent ident request, waiting for reply");
166                                 return true;
167                         }
168                 }
169                 else
170                 {
171                         return true;
172                 }
173         }
174 };
175
176 class ModuleIdent : public Module
177 {
178
179         ConfigReader* Conf;
180         
181         int IdentTimeout;
182
183  public:
184         void ReadSettings()
185         {
186                 Conf = new ConfigReader(ServerInstance);
187                 IdentTimeout = Conf->ReadInteger("ident","timeout",0,true);
188                 if (!IdentTimeout)
189                         IdentTimeout = 1;
190                 DELETE(Conf);
191         }
192
193         ModuleIdent(InspIRCd* Me)
194                 : Module::Module(Me)
195         {
196                 
197                 ReadSettings();
198         }
199
200         void Implements(char* List)
201         {
202                 List[I_OnCleanup] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;
203         }
204
205         virtual void OnRehash(const std::string &parameter)
206         {
207                 ReadSettings();
208         }
209
210         virtual void OnUserRegister(userrec* user)
211         {
212                 /*
213                  * when the new user connects, before they authenticate with USER/NICK/PASS, we do
214                  * their ident lookup. We do this by instantiating an object of type RFC1413, which
215                  * is derived from InspSocket, and inserting it into the socket engine using the
216                  * Server::AddSocket() call.
217                  */
218                 user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Looking up your ident...");
219                 RFC1413* ident = new RFC1413(ServerInstance, user, IdentTimeout);
220                 if ((ident->GetState() == I_CONNECTING) || (ident->GetState() == I_CONNECTED))
221                 {
222                         user->Extend("ident_data", (char*)ident);
223                 }
224                 else
225                         delete ident;
226         }
227
228         virtual bool OnCheckReady(userrec* user)
229         {
230                 /*
231                  * The socket engine will clean up their ident request for us when it completes,
232                  * either due to timeout or due to closing, so, we just hold them until they dont
233                  * have an ident field any more.
234                  */
235                 RFC1413* ident;
236                 return (!user->GetExt("ident_data", ident));
237         }
238
239         virtual void OnCleanup(int target_type, void* item)
240         {
241                 if (target_type == TYPE_USER)
242                 {
243                         userrec* user = (userrec*)item;
244                         RFC1413* ident;
245                         if (user->GetExt("ident_data", ident))
246                         {
247                                 // FIX: If the user record is deleted, the socket wont be removed
248                                 // immediately so there is chance of the socket trying to write to
249                                 // a user which has now vanished! To prevent this, set ident::u
250                                 // to NULL and check it so that we dont write users who have gone away.
251                                 ident->u = NULL;
252                         }
253                 }
254         }
255
256         virtual void OnUserDisconnect(userrec* user)
257         {
258                 /*
259                  * when the user quits tidy up any ident lookup they have pending to keep things tidy.
260                  * When we call RemoveSocket, the abstractions tied into the system evnetually work their
261                  * way to RFC1459::OnClose(), which shrinks off the ident_data for us, so we dont need
262                  * to do it here. If we don't tidy this up, there may still be lingering idents for users
263                  * who have quit, as class RFC1459 is only loosely bound to userrec* via a pair of pointers
264                  * and this would leave at least one of the invalid ;)
265                  */
266                 RFC1413* ident;
267                 if (user->GetExt("ident_data", ident))
268                 {
269                         ident->u = NULL;
270                 }
271         }
272         
273         virtual ~ModuleIdent()
274         {
275         }
276         
277         virtual Version GetVersion()
278         {
279                 return Version(1,5,0,0,VF_VENDOR,API_VERSION);
280         }
281         
282 };
283
284 class ModuleIdentFactory : public ModuleFactory
285 {
286  public:
287         ModuleIdentFactory()
288         {
289         }
290         
291         ~ModuleIdentFactory()
292         {
293         }
294         
295         virtual Module * CreateModule(InspIRCd* Me)
296         {
297                 return new ModuleIdent(Me);
298         }
299         
300 };
301
302
303 extern "C" void * init_module( void )
304 {
305         return new ModuleIdentFactory;
306 }
307