X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fusers.cpp;h=35a0e716fe50ecb88639e4078a25a61a65dc9227;hb=2b3394855d5adddb16285b905503d9ffe5a1d963;hp=196be89e98d8d6bf334c306fba0f207eea243699;hpb=c34dd1e50faa413e35d75191afa2d93aab1e7c76;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/users.cpp b/src/users.cpp index 196be89e9..35a0e716f 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -12,9 +12,6 @@ */ #include "inspircd.h" -#include "configreader.h" -#include "channels.h" -#include "users.h" #include #include "socketengine.h" #include "wildcard.h" @@ -164,8 +161,12 @@ UserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_res this->bound_fd = user->GetFd(); } -void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) +void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum) { + /* We are only interested in the first matching result */ + if (resultnum) + return; + if ((!this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user)) { this->bound_user->stored_host = result; @@ -198,7 +199,7 @@ void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, else if ((this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user)) { /* Both lookups completed */ - std::string result2 = "0::ffff:"; + std::string result2("0::ffff:"); result2.append(result); if (this->bound_user->GetIPString() == result || this->bound_user->GetIPString() == result2) { @@ -210,7 +211,7 @@ void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, { /* Hostnames starting with : are not a good thing (tm) */ if (*(hostname.c_str()) == ':') - hostname = "0" + hostname; + hostname.insert(0, "0"); this->bound_user->WriteServ("NOTICE Auth :*** Found your hostname (%s)%s", hostname.c_str(), (cached ? " -- cached" : "")); this->bound_user->dns_done = true; @@ -319,10 +320,9 @@ void userrec::DecrementModes() } } -userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance) +userrec::userrec(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance) { - // the PROPER way to do it, AVOID bzero at *ALL* costs - *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = 0; + *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = *uuid = 0; server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName); reset_due = ServerInstance->Time(); age = ServerInstance->Time(true); @@ -330,9 +330,9 @@ userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance) ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0; muted = exempt = haspassed = dns_done = false; fd = -1; - recvq = ""; - sendq = ""; - WriteError = ""; + recvq.clear(); + sendq.clear(); + WriteError.clear(); res_forward = res_reverse = NULL; Visibility = NULL; ip = NULL; @@ -342,6 +342,42 @@ userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance) memset(snomasks,0,sizeof(snomasks)); /* Invalidate cache */ operquit = cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL; + + if (uid.empty()) + strlcpy(uuid, Instance->GetUID().c_str(), UUID_LENGTH); + else + strlcpy(uuid, uid.c_str(), UUID_LENGTH); + + ServerInstance->Log(DEBUG,"New UUID for user: %s (%s)", uuid, uid.empty() ? "allocated new" : "used remote"); + + user_hash::iterator finduuid = Instance->uuidlist->find(uuid); + if (finduuid == Instance->uuidlist->end()) + (*Instance->uuidlist)[uuid] = this; + else + throw CoreException("Duplicate UUID "+std::string(uuid)+" in userrec constructor"); +} + +void userrec::RemoveCloneCounts() +{ + clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString()); + if (x != ServerInstance->local_clones.end()) + { + x->second--; + if (!x->second) + { + ServerInstance->local_clones.erase(x); + } + } + + clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString()); + if (y != ServerInstance->global_clones.end()) + { + y->second--; + if (!y->second) + { + ServerInstance->global_clones.erase(y); + } + } } userrec::~userrec() @@ -352,25 +388,7 @@ userrec::~userrec() free(operquit); if (ip) { - clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString()); - if (x != ServerInstance->local_clones.end()) - { - x->second--; - if (!x->second) - { - ServerInstance->local_clones.erase(x); - } - } - - clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString()); - if (y != ServerInstance->global_clones.end()) - { - y->second--; - if (!y->second) - { - ServerInstance->global_clones.erase(y); - } - } + this->RemoveCloneCounts(); if (this->GetProtocolFamily() == AF_INET) { @@ -383,6 +401,8 @@ userrec::~userrec() } #endif } + + ServerInstance->uuidlist->erase(uuid); } char* userrec::MakeHost() @@ -427,8 +447,8 @@ char* userrec::MakeHostIP() void userrec::CloseSocket() { - shutdown(this->fd,2); - close(this->fd); + ServerInstance->SE->Shutdown(this, 2); + ServerInstance->SE->Close(this); } char* userrec::GetFullHost() @@ -632,7 +652,7 @@ bool userrec::BufferIsReady() void userrec::ClearBuffer() { - recvq = ""; + recvq.clear(); } std::string userrec::GetBuffer() @@ -713,16 +733,13 @@ void userrec::FlushWriteBuf() { if ((this->fd == FD_MAGIC_NUMBER) || (*this->GetWriteError())) { - sendq = ""; + sendq.clear(); } if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER)) { int old_sendq_length = sendq.length(); -#ifndef WIN32 - int n_sent = write(this->fd, this->sendq.data(), this->sendq.length()); -#else - int n_sent = send(this->fd, (const char*)this->sendq.data(), this->sendq.length(), 0); -#endif + int n_sent = ServerInstance->SE->Send(this, this->sendq.data(), this->sendq.length(), 0); + if (n_sent == -1) { if (errno == EAGAIN) @@ -736,7 +753,7 @@ void userrec::FlushWriteBuf() { /* Fatal error, set write error and bail */ - this->SetWriteError(strerror(errno)); + this->SetWriteError(errno ? strerror(errno) : "EOF from client"); return; } } @@ -853,8 +870,14 @@ void userrec::AddToWhoWas() /* add a client connection to the sockets list */ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, int socketfamily, sockaddr* ip) { - std::string tempnick = ConvToStr(socket) + "-unknown"; - user_hash::iterator iter = Instance->clientlist->find(tempnick); + /* NOTE: Calling this one parameter constructor for userrec automatically + * allocates a new UUID and places it in the hash_map. + */ + userrec* New = new userrec(Instance); + int j = 0; + + Instance->unregistered_count++; + char ipaddr[MAXBUF]; #ifdef IPV6 if (socketfamily == AF_INET6) @@ -862,31 +885,12 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, else #endif inet_ntop(AF_INET, &((const sockaddr_in*)ip)->sin_addr, ipaddr, sizeof(ipaddr)); - userrec* New; - int j = 0; - Instance->unregistered_count++; + (*(Instance->clientlist))[New->uuid] = New; + New->SetFd(socket); - /* - * fix by brain. - * as these nicknames are 'RFC impossible', we can be sure nobody is going to be - * using one as a registered connection. As they are per fd, we can also safely assume - * that we wont have collisions. Therefore, if the nick exists in the list, its only - * used by a dead socket, erase the iterator so that the new client may reclaim it. - * this was probably the cause of 'server ignores me when i hammer it with reconnects' - * issue in earlier alphas/betas - */ - if (iter != Instance->clientlist->end()) - { - userrec* goner = iter->second; - DELETE(goner); - Instance->clientlist->erase(iter); - } - - New = new userrec(Instance); - (*(Instance->clientlist))[tempnick] = New; - New->fd = socket; - strlcpy(New->nick,tempnick.c_str(),NICKMAX-1); + /* The users default nick is their UUID */ + strlcpy(New->nick, New->uuid, NICKMAX - 1); New->server = Instance->FindServerNamePtr(Instance->Config->ServerName); /* We don't need range checking here, we KNOW 'unknown\0' will fit into the ident field. */ @@ -918,16 +922,12 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, return; } + /* + * Check connect class settings and initialise settings into userrec. + * This will be done again after DNS resolution. -- w00t + */ New->CheckClass(); - New->pingmax = i->GetPingTime(); - New->nping = Instance->Time() + i->GetPingTime() + Instance->Config->dns_timeout; - New->timeout = Instance->Time() + i->GetRegTimeout(); - New->flood = i->GetFlood(); - New->threshold = i->GetThreshold(); - New->sendqmax = i->GetSendqMax(); - New->recvqmax = i->GetRecvqMax(); - Instance->local_users.push_back(New); if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS)) @@ -962,6 +962,8 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, if (r) { char reason[MAXBUF]; + if (*Instance->Config->MoronBanner) + New->WriteServ("NOTICE %s :*** %s", New->nick, Instance->Config->MoronBanner); snprintf(reason,MAXBUF,"Z-Lined: %s",r->reason); userrec::QuitUser(Instance, New, reason); return; @@ -1004,20 +1006,15 @@ unsigned long userrec::LocalCloneCount() /* * Check class restrictions */ -void userrec::CheckClass() +void userrec::CheckClass(const std::string &explicit_class) { - ConnectClass* a = this->GetClass(); + ConnectClass* a = this->GetClass(explicit_class); if ((!a) || (a->GetType() == CC_DENY)) { userrec::QuitUser(ServerInstance, this, "Unauthorised connection"); return; } - else if ((!a->GetPass().empty()) && (!this->haspassed)) - { - userrec::QuitUser(ServerInstance, this, "Invalid password"); - return; - } else if ((a->GetMaxLocal()) && (this->LocalCloneCount() > a->GetMaxLocal())) { userrec::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (local)"); @@ -1030,6 +1027,15 @@ void userrec::CheckClass() ServerInstance->WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString()); return; } + + this->pingmax = a->GetPingTime(); + this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout; + this->timeout = ServerInstance->Time() + a->GetRegTimeout(); + this->flood = a->GetFlood(); + this->threshold = a->GetThreshold(); + this->sendqmax = a->GetSendqMax(); + this->recvqmax = a->GetRecvqMax(); + this->MaxChans = a->GetMaxChans(); } void userrec::FullConnect() @@ -1044,7 +1050,16 @@ void userrec::FullConnect() * Don't remove this! -- w00t */ this->CheckClass(); - + + /* Check the password, if one is required by the user's connect class. + * This CANNOT be in CheckClass(), because that is called prior to PASS as well! + */ + if ((!this->GetClass()->GetPass().empty()) && (!this->haspassed)) + { + userrec::QuitUser(ServerInstance, this, "Invalid password"); + return; + } + if (!this->exempt) { GLine* r = ServerInstance->XLines->matches_gline(this); @@ -1053,8 +1068,10 @@ void userrec::FullConnect() { this->muted = true; char reason[MAXBUF]; + if (*ServerInstance->Config->MoronBanner) + this->WriteServ("NOTICE %s :*** %s", this->nick, ServerInstance->Config->MoronBanner); snprintf(reason,MAXBUF,"G-Lined: %s",r->reason); - ServerInstance->GlobalCulls.AddItem(this, reason); + userrec::QuitUser(ServerInstance, this, reason); return; } @@ -1064,11 +1081,12 @@ void userrec::FullConnect() { this->muted = true; char reason[MAXBUF]; + if (*ServerInstance->Config->MoronBanner) + this->WriteServ("NOTICE %s :*** %s", this, ServerInstance->Config->MoronBanner); snprintf(reason,MAXBUF,"K-Lined: %s",n->reason); - ServerInstance->GlobalCulls.AddItem(this, reason); + userrec::QuitUser(ServerInstance, this, reason); return; } - } this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network); @@ -1079,6 +1097,9 @@ void userrec::FullConnect() ServerInstance->Config->Send005(this); + this->WriteServ("042 %s %s :your unique ID", this->nick, this->uuid); + + this->ShowMOTD(); /* Now registered */ @@ -1172,10 +1193,15 @@ bool userrec::ForceNickChange(const char* newnick) if (this->registered == REG_ALL) { - const char* pars[1]; - pars[0] = newnick; - std::string cmd = "NICK"; - return (ServerInstance->Parser->CallHandler(cmd, pars, 1, this) == CMD_SUCCESS); + std::deque dummy; + command_t* nickhandler = ServerInstance->Parser->GetHandler("NICK"); + if (nickhandler) + { + nickhandler->HandleInternal(1, dummy); + bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS); + nickhandler->HandleInternal(0, dummy); + return result; + } } return false; } @@ -1343,11 +1369,7 @@ const char* userrec::GetIPString(char* buf) */ void userrec::Write(std::string text) { -#ifdef WINDOWS - if ((this->fd < 0) || (this->m_internalFd > MAX_DESCRIPTORS)) -#else - if ((this->fd < 0) || (this->fd > MAX_DESCRIPTORS)) -#endif + if (!ServerInstance->SE->BoundsCheckFd(this)) return; try @@ -1369,6 +1391,9 @@ void userrec::Write(std::string text) { try { + /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to + * implement their own buffering mechanisms + */ ServerInstance->Config->GetIOHook(this->GetPort())->OnRawSocketWrite(this->fd, text.data(), text.length()); } catch (CoreException& modexcept) @@ -1611,12 +1636,13 @@ void userrec::WriteWallOps(const std::string &text) if (!IS_OPER(this) && IS_LOCAL(this)) return; - std::string wallop = "WALLOPS :" + text; + std::string wallop("WALLOPS :"); + wallop.append(text); for (std::vector::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++) { userrec* t = *i; - if (t->modes[UM_WALLOPS]) + if (t->IsModeSet('w')) this->WriteTo(t,wallop); } } @@ -1775,7 +1801,7 @@ std::string userrec::ChannelList(userrec* source) * If the channel is NOT private/secret OR the user shares a common channel * If the user is an oper, and the option is set. */ - if ((source == this) || (IS_OPER(source) && ServerInstance->Config->OperSpyWhois) || (((!i->first->modes[CM_PRIVATE]) && (!i->first->modes[CM_SECRET])) || (i->first->HasUser(source)))) + if ((source == this) || (IS_OPER(source) && ServerInstance->Config->OperSpyWhois) || (((!i->first->IsModeSet('p')) && (!i->first->IsModeSet('s'))) || (i->first->HasUser(source)))) { list.append(i->first->GetPrefixChar(this)).append(i->first->name).append(" "); } @@ -1834,27 +1860,42 @@ void userrec::SplitChanList(userrec* dest, const std::string &cl) } } +unsigned int userrec::GetMaxChans() +{ + return this->MaxChans; +} /* looks up a users password for their connection class (/ tags) * NOTE: If the or tag specifies an ip, and this user resolves, * then their ip will be taken as 'priority' anyway, so for example, * will match joe!bloggs@localhost */ -ConnectClass* userrec::GetClass() +ConnectClass* userrec::GetClass(const std::string &explicit_name) { - for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) + if (!explicit_name.empty()) + { + for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) + { + if (explicit_name == i->GetName()) + return &(*i); + } + } + else { - if (((match(this->GetIPString(),i->GetHost().c_str(),true)) || (match(this->host,i->GetHost().c_str())))) + for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) { - if (i->GetPort()) + if (((match(this->GetIPString(),i->GetHost().c_str(),true)) || (match(this->host,i->GetHost().c_str())))) { - if (this->GetPort() == i->GetPort()) - return &(*i); + if (i->GetPort()) + { + if (this->GetPort() == i->GetPort()) + return &(*i); + else + continue; + } else - continue; + return &(*i); } - else - return &(*i); } } return NULL; @@ -1917,15 +1958,16 @@ void userrec::ShowRULES() { if (!ServerInstance->Config->RULES.size()) { - this->WriteServ("NOTICE %s :Rules file is missing.",this->nick); + this->WriteServ("434 %s :RULES File is missing",this->nick); return; } - this->WriteServ("NOTICE %s :%s rules",this->nick,ServerInstance->Config->ServerName); + + this->WriteServ("308 %s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName); for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++) - this->WriteServ("NOTICE %s :%s",this->nick,i->c_str()); + this->WriteServ("232 %s :- %s",this->nick,i->c_str()); - this->WriteServ("NOTICE %s :End of %s rules.",this->nick,ServerInstance->Config->ServerName); + this->WriteServ("309 %s :End of RULES command.",this->nick); } void userrec::HandleEvent(EventType et, int errornum)