/* * Someone else is attempting to connect to us if this is called. Validate their credentials etc. * -- w */ bool TreeSocket::Inbound_Server(parameterlist ¶ms) { if (params.size() < 5) { SendError("Protocol error - Missing SID"); return false; } irc::string servername = params[0].c_str(); std::string sname = params[0]; std::string password = params[1]; std::string sid = params[3]; std::string description = params[4]; this->SendCapabilities(2); if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return false; } for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; if (x->Name != servername && x->Name != "*") // open link allowance continue; if (!ComparePass(*x, password)) { ServerInstance->SNO->WriteToSnoMask('l',"Invalid password on link: %s", x->Name.c_str()); continue; } if (!CheckDuplicate(sname, sid)) return false; ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection " + linkID + " ("+description+")"); this->SendCapabilities(2); // Save these for later, so when they accept our credentials (indicated by BURST) we remember them this->capab->hidden = x->Hidden; this->capab->sid = sid; this->capab->description = description; this->capab->name = sname; // Send our details: Our server name and description and hopcount of 0, // along with the sendpass from this block. this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); // move to the next state, we are now waiting for THEM. this->LinkState = WAIT_AUTH_2; return true; } this->SendError("Invalid credentials"); ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); return false; }
Link* TreeSocket::AuthRemote(const parameterlist& params) { if (params.size() < 5) { SendError("Protocol error - Not enough parameters for SERVER command"); return NULL; } irc::string servername = params[0].c_str(); const std::string& sname = params[0]; const std::string& password = params[1]; const std::string& sid = params[3]; const std::string& description = params.back(); this->SendCapabilities(2); if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return NULL; } for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; if (x->Name != servername && x->Name != "*") // open link allowance continue; if (!ComparePass(*x, password)) { ServerInstance->SNO->WriteToSnoMask('l',"Invalid password on link: %s", x->Name.c_str()); continue; } if (!CheckDuplicate(sname, sid)) return NULL; ServerInstance->SNO->WriteToSnoMask('l',"Verified server connection " + linkID + " ("+description+")"); const SSLIOHook* const ssliohook = SSLIOHook::IsSSL(this); if (ssliohook) { std::string ciphersuite; ssliohook->GetCiphersuite(ciphersuite); ServerInstance->SNO->WriteToSnoMask('l', "Negotiated ciphersuite %s on link %s", ciphersuite.c_str(), x->Name.c_str()); } return x; } this->SendError("Mismatched server name or password (check the other server's snomask output for details - e.g. umode +s +Ll)"); ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials"); return NULL; }
void TreeSocket::ProcessLine(std::string &line) { std::string prefix; std::string command; parameterlist params; ServerInstance->Logs->Log(MODNAME, LOG_RAWIO, "S[%d] I %s", this->GetFd(), line.c_str()); Split(line, prefix, command, params); if (command.empty()) return; switch (this->LinkState) { case WAIT_AUTH_1: /* * State WAIT_AUTH_1: * Waiting for SERVER command from remote server. Server initiating * the connection sends the first SERVER command, listening server * replies with theirs if its happy, then if the initiator is happy, * it starts to send its net sync, which starts the merge, otherwise * it sends an ERROR. */ if (command == "PASS") { /* * Ignore this silently. Some services packages insist on sending PASS, even * when it is not required (i.e. by us). We have to ignore this here, otherwise * as it's an unknown command (effectively), it will cause the connection to be * closed, which probably isn't what people want. -- w00t */ } else if (command == "SERVER") { this->Inbound_Server(params); } else if (command == "ERROR") { this->Error(params); } else if (command == "USER") { this->SendError("Client connections to this port are prohibited."); } else if (command == "CAPAB") { this->Capab(params); } else { this->SendError("Invalid command in negotiation phase: " + command); } break; case WAIT_AUTH_2: /* * State WAIT_AUTH_2: * We have sent SERVER to the other side of the connection. Now we're waiting for them to start BURST. * The other option at this stage of things, of course, is for them to close our connection thanks * to invalid credentials.. -- w */ if (command == "SERVER") { /* * Connection is either attempting to re-auth itself (stupid) or sending netburst without sending BURST. * Both of these aren't allowable, so block them here. -- w */ this->SendError("You may not re-authenticate or commence netburst without sending BURST."); } else if (command == "BURST") { if (params.size()) { time_t them = ConvToInt(params[0]); time_t delta = them - ServerInstance->Time(); if ((delta < -600) || (delta > 600)) { ServerInstance->SNO->WriteGlobalSno('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs((long)delta)); SendError("Your clocks are out by "+ConvToStr(abs((long)delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!"); return; } else if ((delta < -30) || (delta > 30)) { ServerInstance->SNO->WriteGlobalSno('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs((long)delta)); } } // Check for duplicate server name/sid again, it's possible that a new // server was introduced while we were waiting for them to send BURST. // (we do not reserve their server name/sid when they send SERVER, we do it now) if (!CheckDuplicate(capab->name, capab->sid)) return; this->LinkState = CONNECTED; Utils->timeoutlist.erase(this); linkID = capab->name; MyRoot = new TreeServer(capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden); Utils->TreeRoot->AddChild(MyRoot); MyRoot->bursting = true; this->DoBurst(MyRoot); parameterlist sparams; sparams.push_back(MyRoot->GetName()); sparams.push_back("*"); sparams.push_back("0"); sparams.push_back(MyRoot->GetID()); sparams.push_back(":" + MyRoot->GetDesc()); Utils->DoOneToAllButSender(ServerInstance->Config->GetSID(), "SERVER", sparams, MyRoot); Utils->DoOneToAllButSender(MyRoot->GetID(), "BURST", params, MyRoot); } else if (command == "ERROR") { this->Error(params); } else if (command == "CAPAB") { this->Capab(params); } break; case CONNECTING: /* * State CONNECTING: * We're connecting (OUTGOING) to another server. They are in state WAIT_AUTH_1 until they verify * our credentials, when they proceed into WAIT_AUTH_2 and send SERVER to us. We then send BURST * + our netburst, which will put them into CONNECTED state. -- w */ if (command == "SERVER") { // Our credentials have been accepted, send netburst. (this puts US into the CONNECTED state) this->Outbound_Reply_Server(params); } else if (command == "ERROR") { this->Error(params); } else if (command == "CAPAB") { this->Capab(params); } break; case CONNECTED: /* * State CONNECTED: * Credentials have been exchanged, we've gotten their 'BURST' (or sent ours). * Anything from here on should be accepted a little more reasonably. */ this->ProcessConnectedLine(prefix, command, params); break; case DYING: break; } }
HRESULT CAssemblyDownload::KickOffDownload(BOOL bFirstDownload) { HRESULT hr = S_OK; LPWSTR pwzUrl = NULL; WCHAR wzFilePath[MAX_PATH]; BOOL bIsFileUrl = FALSE; CCriticalSection cs(&_cs); CCriticalSection csDownload(&g_csDownload); wzFilePath[0] = L'\0'; // If we're aborted, or done, we can't do anything here hr = cs.Lock(); if (FAILED(hr)) { goto Exit; } if (_state == ADLSTATE_DONE) { hr = S_FALSE; goto Exit; } // Dupe detection. If we end up hitting a dupe, then the CClientBinding // that was keeping a refcount on us, releases us, and adds itself as // a client to the duped download. In this case, we'll come back, and // this download object could be destroyed--that's why we AddRef/Release // around the dupe checking code. if (bFirstDownload) { // This is a top-level download (ie. not a probe download called from // DownloadNextCodebase AddRef(); hr = CheckDuplicate(); if (hr == E_PENDING) { cs.Unlock(); Release(); goto Exit; } Release(); // Not a duplicate. Add ourselves to the global download list. hr = csDownload.Lock(); if (FAILED(hr)) { goto Exit; } AddRef(); g_pDownloadList->AddTail(this); csDownload.Unlock(); } // Careful! PrepNextDownload/CompleteAll call the client back! cs.Unlock(); hr = GetNextCodebase(&bIsFileUrl, wzFilePath, MAX_PATH); if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) { // This must have been a case where all remaining probing URLs were file://, // and none of them existed. That is, we never get here (KickOffDownload) // unless the codebase list is non-empty, so this return result // from GetNextCodebase could only have resulted because we rejected // all remaining URLs. hr = DownloadComplete(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), NULL, NULL, FALSE); // Not really pending, just tell client the result is reported via // bind sink. if (SUCCEEDED(hr)) { hr = E_PENDING; } goto Exit; } else if (FAILED(hr)) { DEBUGOUT1(_pdbglog, 1, ID_FUSLOG_CODEBASE_RETRIEVE_FAILURE, hr); goto Exit; } DEBUGOUT1(_pdbglog, 0, ID_FUSLOG_ATTEMPT_NEW_DOWNLOAD, _pwzUrl); if (bIsFileUrl) { hr = DownloadComplete(S_OK, wzFilePath, NULL, FALSE); // We're not really pending, but E_PENDING means that the client // will get the IAssembly via the bind sink (not the ppv returned // in the call to BindToObject). if (SUCCEEDED(hr)) { hr = E_PENDING; } goto Exit; } else { hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto Exit; } Exit: SAFEDELETEARRAY(pwzUrl); if (FAILED(hr) && hr != E_PENDING) { LISTNODE listnode; CCriticalSection cs(&g_csDownload); // Fatal error! // If we added ourselves to the download list, we should remove // ourselves immediately! HRESULT hrLock = cs.Lock(); if (FAILED(hrLock)) { return hrLock; } listnode = g_pDownloadList->Find(this); if (listnode) { g_pDownloadList->RemoveAt(listnode); // release ourselves since we are removing from the global dl list Release(); } cs.Unlock(); } return hr; }