Example #1
0
/*
 * Someone else is attempting to connect to us if this is called. Validate their credentials etc.
 *		-- w
 */
bool TreeSocket::Inbound_Server(parameterlist &params)
{
	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;
}
Example #2
0
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;
}
Example #3
0
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;
	}
}
Example #4
0
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;
}