00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 class IdentRequestSocket : public EventHandler
00075 {
00076 private:
00077 User *user;
00078 InspIRCd* ServerInstance;
00079 bool done;
00080 std::string result;
00081 public:
00082
00083 IdentRequestSocket(InspIRCd *Server, User* u, const std::string &bindip) : user(u), ServerInstance(Server), result(u->ident)
00084 {
00085 socklen_t size = 0;
00086 #ifdef IPV6
00087
00088 bool v6 = false;
00089 if ((bindip.empty()) || bindip.find(':') != std::string::npos)
00090 v6 = true;
00091
00092 if (v6)
00093 SetFd(socket(AF_INET6, SOCK_STREAM, 0));
00094 else
00095 #endif
00096 SetFd(socket(AF_INET, SOCK_STREAM, 0));
00097
00098 if (GetFd() == -1)
00099 throw ModuleException("Could not create socket");
00100
00101 done = false;
00102
00103
00104 sockaddr* s = new sockaddr[2];
00105 sockaddr* addr = new sockaddr[2];
00106
00107 #ifdef IPV6
00108
00109 if (v6)
00110 {
00111 in6_addr addy;
00112 in6_addr n;
00113 if (inet_pton(AF_INET6, user->GetIPString(), &addy) > 0)
00114 {
00115 ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
00116 memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
00117 ((sockaddr_in6*)addr)->sin6_port = htons(113);
00118 size = sizeof(sockaddr_in6);
00119 inet_pton(AF_INET6, bindip.c_str(), &n);
00120 memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(sockaddr_in6));
00121 ((sockaddr_in6*)s)->sin6_port = 0;
00122 ((sockaddr_in6*)s)->sin6_family = AF_INET6;
00123 }
00124 }
00125 else
00126 #endif
00127 {
00128 in_addr addy;
00129 in_addr n;
00130 if (inet_aton(user->GetIPString(), &addy) > 0)
00131 {
00132 ((sockaddr_in*)addr)->sin_family = AF_INET;
00133 ((sockaddr_in*)addr)->sin_addr = addy;
00134 ((sockaddr_in*)addr)->sin_port = htons(113);
00135 size = sizeof(sockaddr_in);
00136 inet_aton(bindip.c_str(), &n);
00137 ((sockaddr_in*)s)->sin_addr = n;
00138 ((sockaddr_in*)s)->sin_port = 0;
00139 ((sockaddr_in*)s)->sin_family = AF_INET;
00140 }
00141 }
00142
00143
00144 if (ServerInstance->SE->Bind(GetFd(), s, size) < 0)
00145 {
00146 this->Close();
00147 delete[] s;
00148 delete[] addr;
00149 throw ModuleException("failed to bind()");
00150 }
00151
00152 delete[] s;
00153 ServerInstance->SE->NonBlocking(GetFd());
00154
00155
00156 if (ServerInstance->SE->Connect(this, (sockaddr*)addr, size) == -1 && errno != EINPROGRESS)
00157 {
00158 this->Close();
00159 delete[] addr;
00160 throw ModuleException("connect() failed");
00161 }
00162
00163 delete[] addr;
00164
00165
00166 if (!ServerInstance->SE->AddFd(this))
00167 {
00168 this->Close();
00169 throw ModuleException("out of fds");
00170 }
00171
00172
00173
00174
00175 ServerInstance->SE->WantWrite(this);
00176 }
00177
00178 virtual void OnConnected()
00179 {
00180 ServerInstance->Logs->Log("m_ident",DEBUG,"OnConnected()");
00181
00182
00183
00184
00185 #ifndef IPV6
00186 sockaddr_in laddr, raddr;
00187 #else
00188 sockaddr_in6 laddr, raddr;
00189 #endif
00190
00191 socklen_t laddrsz = sizeof(laddr);
00192 socklen_t raddrsz = sizeof(raddr);
00193
00194 if ((getsockname(user->GetFd(), (sockaddr*) &laddr, &laddrsz) != 0) || (getpeername(user->GetFd(), (sockaddr*) &raddr, &raddrsz) != 0))
00195 {
00196 done = true;
00197 return;
00198 }
00199
00200 char req[32];
00201
00202
00203 #ifndef IPV6
00204 int req_size = snprintf(req, sizeof(req), "%d,%d\r\n", ntohs(raddr.sin_port), ntohs(laddr.sin_port));
00205 #else
00206 int req_size = snprintf(req, sizeof(req), "%d,%d\r\n", ntohs(raddr.sin6_port), ntohs(laddr.sin6_port));
00207 #endif
00208
00209
00210
00211
00212 if (ServerInstance->SE->Send(this, req, req_size, 0) < req_size)
00213 done = true;
00214 }
00215
00216 virtual void HandleEvent(EventType et, int errornum = 0)
00217 {
00218 switch (et)
00219 {
00220 case EVENT_READ:
00221
00222 ReadResponse();
00223 break;
00224 case EVENT_WRITE:
00225
00226 OnConnected();
00227 break;
00228 case EVENT_ERROR:
00229
00230 ServerInstance->Logs->Log("m_ident",DEBUG,"EVENT_ERROR");
00231
00232
00233
00234 Close();
00235 done = true;
00236 break;
00237 }
00238 }
00239
00240 void Close()
00241 {
00242
00243
00244
00245 if (GetFd() > -1)
00246 {
00247 ServerInstance->Logs->Log("m_ident",DEBUG,"Close ident socket %d", GetFd());
00248 ServerInstance->SE->DelFd(this);
00249 ServerInstance->SE->Close(GetFd());
00250 ServerInstance->SE->Shutdown(GetFd(), SHUT_WR);
00251 this->SetFd(-1);
00252 }
00253 }
00254
00255 bool HasResult()
00256 {
00257 return done;
00258 }
00259
00260
00261
00262
00263 const char* GetResult()
00264 {
00265 return result.c_str();
00266 }
00267
00268 void ReadResponse()
00269 {
00270
00271
00272
00273 char ibuf[MAXBUF];
00274 int recvresult = ServerInstance->SE->Recv(this, ibuf, MAXBUF-1, 0);
00275
00276
00277
00278
00279 if (recvresult < 3)
00280 {
00281 Close();
00282 done = true;
00283 return;
00284 }
00285
00286 ServerInstance->Logs->Log("m_ident",DEBUG,"ReadResponse()");
00287
00288 irc::sepstream sep(ibuf, ':');
00289 std::string token;
00290 for (int i = 0; sep.GetToken(token); i++)
00291 {
00292
00293 if (i < 3)
00294 continue;
00295
00296 std::string ident;
00297
00298
00299 size_t k = 0;
00300 for (const char *j = token.c_str(); *j && (k < ServerInstance->Config->Limits.IdentMax + 1); j++)
00301 {
00302 if (*j == ' ')
00303 continue;
00304
00305
00306 if (((*j >= 'A') && (*j <= '}')) || ((*j >= '0') && (*j <= '9')) || (*j == '-') || (*j == '.'))
00307 {
00308 ident += *j;
00309 continue;
00310 }
00311
00312 break;
00313 }
00314
00315
00316 if (!ident.empty() && ServerInstance->IsIdent(ident.c_str()))
00317 {
00318 result = ident;
00319 }
00320
00321 break;
00322 }
00323
00324
00325
00326
00327 Close();
00328 done = true;
00329 return;
00330 }
00331 };
00332
00333 class ModuleIdent : public Module
00334 {
00335 private:
00336 int RequestTimeout;
00337 ConfigReader *Conf;
00338 public:
00339 ModuleIdent(InspIRCd *Me) : Module(Me)
00340 {
00341 Conf = new ConfigReader(ServerInstance);
00342 OnRehash(NULL, "");
00343 Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnCheckReady, I_OnCleanup, I_OnUserDisconnect };
00344 ServerInstance->Modules->Attach(eventlist, this, 5);
00345 }
00346
00347 ~ModuleIdent()
00348 {
00349 delete Conf;
00350 }
00351
00352 virtual Version GetVersion()
00353 {
00354 return Version("$Id: m_ident.cpp 10622 2008-10-04 21:27:52Z brain $", VF_VENDOR, API_VERSION);
00355 }
00356
00357 virtual void OnRehash(User *user, const std::string ¶m)
00358 {
00359 delete Conf;
00360 Conf = new ConfigReader(ServerInstance);
00361
00362 RequestTimeout = Conf->ReadInteger("ident", "timeout", 0, true);
00363 if (!RequestTimeout)
00364 RequestTimeout = 5;
00365 }
00366
00367 virtual int OnUserRegister(User *user)
00368 {
00369 for (int j = 0; j < Conf->Enumerate("connect"); j++)
00370 {
00371 std::string hostn = Conf->ReadValue("connect","allow",j);
00372
00373 if ((InspIRCd::MatchCIDR(user->GetIPString(),hostn)) || (InspIRCd::Match(user->host,hostn)))
00374 {
00375 bool useident = Conf->ReadFlag("connect", "useident", j);
00376
00377 if (!useident)
00378 return 0;
00379 }
00380 }
00381
00382
00383
00384 if (user->ident.length() > ServerInstance->Config->Limits.IdentMax + 1)
00385 user->ident.assign(user->ident, 0, ServerInstance->Config->Limits.IdentMax);
00386 user->ident.insert(0, "~");
00387
00388 user->WriteServ("NOTICE Auth :*** Looking up your ident...");
00389
00390
00391 #ifndef IPV6
00392 sockaddr_in laddr;
00393 #else
00394 sockaddr_in6 laddr;
00395 #endif
00396 socklen_t laddrsz = sizeof(laddr);
00397
00398 if (getsockname(user->GetFd(), (sockaddr*) &laddr, &laddrsz) != 0)
00399 {
00400 user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident.c_str());
00401 return 0;
00402 }
00403
00404 #ifndef IPV6
00405 const char *ip = inet_ntoa(laddr.sin_addr);
00406 #else
00407 char ip[INET6_ADDRSTRLEN + 1];
00408 inet_ntop(laddr.sin6_family, &laddr.sin6_addr, ip, INET6_ADDRSTRLEN);
00409 #endif
00410
00411 IdentRequestSocket *isock = NULL;
00412 try
00413 {
00414 isock = new IdentRequestSocket(ServerInstance, user, ip);
00415 }
00416 catch (ModuleException &e)
00417 {
00418 ServerInstance->Logs->Log("m_ident",DEBUG,"Ident exception: %s", e.GetReason());
00419 return 0;
00420 }
00421
00422 user->Extend("ident_socket", isock);
00423 return 0;
00424 }
00425
00426
00427
00428
00429
00430 virtual bool OnCheckReady(User *user)
00431 {
00432
00433 IdentRequestSocket *isock = NULL;
00434 if (!user->GetExt("ident_socket", isock))
00435 {
00436 ServerInstance->Logs->Log("m_ident",DEBUG, "No ident socket :(");
00437 return true;
00438 }
00439
00440 ServerInstance->Logs->Log("m_ident",DEBUG, "Has ident_socket");
00441
00442 time_t compare = isock->age;
00443 compare += RequestTimeout;
00444
00445
00446 if (ServerInstance->Time() >= compare)
00447 {
00448
00449 user->WriteServ("NOTICE Auth :*** Ident request timed out.");
00450 ServerInstance->Logs->Log("m_ident",DEBUG, "Timeout");
00451
00452
00453
00454 OnUserDisconnect(user);
00455 return true;
00456 }
00457
00458
00459 if (!isock->HasResult())
00460 {
00461 ServerInstance->Logs->Log("m_ident",DEBUG, "No result yet");
00462 return false;
00463 }
00464
00465 ServerInstance->Logs->Log("m_ident",DEBUG, "Yay, result!");
00466
00467
00468 if (*(isock->GetResult()) != '~')
00469 user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", isock->GetResult());
00470 else
00471 user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", isock->GetResult());
00472
00473
00474 user->ident.assign(isock->GetResult(), 0, ServerInstance->Config->Limits.IdentMax + 1);
00475
00476
00477 OnUserDisconnect(user);
00478 return true;
00479 }
00480
00481 virtual void OnCleanup(int target_type, void *item)
00482 {
00483
00484 if (target_type == TYPE_USER)
00485 OnUserDisconnect((User*)item);
00486 }
00487
00488 virtual void OnUserDisconnect(User *user)
00489 {
00490
00491 IdentRequestSocket *isock = NULL;
00492 if (user->GetExt("ident_socket", isock))
00493 {
00494 isock->Close();
00495 delete isock;
00496 user->Shrink("ident_socket");
00497 }
00498 }
00499 };
00500
00501 MODULE_INIT(ModuleIdent)
00502