Пример #1
0
static unsigned __stdcall NetlibBindAcceptThread(void* param)
{
    SOCKET s;
    SOCKADDR_IN sin;
    int sinLen;
    struct NetlibConnection *nlc;
    struct NetlibBoundPort *nlbp = (NetlibBoundPort*)param;

    NetlibLogf(nlbp->nlu, "(%u) Port %u opened for incoming connections", nlbp->s, nlbp->wPort);
    for(;;)
    {
        sinLen = sizeof(sin);
        s = accept(nlbp->s, (struct sockaddr*)&sin, &sinLen);
        if (s == INVALID_SOCKET) break;
        NetlibLogf(nlbp->nlu, "New incoming connection on port %u from %s (%d)", nlbp->wPort, inet_ntoa(sin.sin_addr), s);
        nlc = (NetlibConnection*)mir_calloc(sizeof(NetlibConnection));
        nlc->handleType = NLH_CONNECTION;
        nlc->nlu = nlbp->nlu;
        nlc->s = s;
        nlc->s2 = INVALID_SOCKET;
        InitializeCriticalSection(&nlc->csHttpSequenceNums);
        nlc->hOkToCloseEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
        nlc->dontCloseNow = 0;
        NetlibInitializeNestedCS(&nlc->ncsSend);
        NetlibInitializeNestedCS(&nlc->ncsRecv);
        nlbp->pfnNewConnectionV2((HANDLE)nlc,ntohl(sin.sin_addr.S_un.S_addr), nlbp->pExtra);
    }
    NetlibUPnPDeletePortMapping(nlbp->wExPort, "TCP");
    return 0;
}
Пример #2
0
	char* Execute(NetlibConnection *nlc, char *szHost, const char *szProvider, const char *szChallenge, unsigned &complete)
	{
		char *szAuthHdr = NULL;
		bool justCreated = false;
		NetlibUser *nlu = nlc->nlu;

		if (m_hNtlmSecurity) {
			bool newAuth = !m_szProvider || !szProvider || _stricmp(m_szProvider, szProvider);
			newAuth = newAuth || (m_szHost != szHost && (!m_szHost || !szHost || _stricmp(m_szHost, szHost)));
			if (newAuth)
				Destroy();
		}

		if (m_hNtlmSecurity == NULL) {
			char szSpnStr[256] = "";
			if (szHost && _stricmp(szProvider, "Basic")) {
				unsigned long ip = inet_addr(szHost);
				PHOSTENT host = (ip == INADDR_NONE) ? gethostbyname(szHost) : gethostbyaddr((char*)&ip, 4, AF_INET);
				mir_snprintf(szSpnStr, "HTTP/%s", host && host->h_name ? host->h_name : szHost);
				_strlwr(szSpnStr + 5);
				NetlibLogf(nlu, "Host SPN: %s", szSpnStr);
			}
			m_hNtlmSecurity = NetlibInitSecurityProvider(szProvider, szSpnStr[0] ? szSpnStr : NULL);
			if (m_hNtlmSecurity) {
				m_szProvider = mir_strdup(szProvider);
				m_szHost = mir_strdup(szHost);
				justCreated = true;
			}
		}

		if (m_hNtlmSecurity) {
			TCHAR *szLogin = NULL, *szPassw = NULL;

			if (nlu->settings.useProxyAuth) {
				mir_cslock lck(csNetlibUser);
				szLogin = mir_a2t(nlu->settings.szProxyAuthUser);
				szPassw = mir_a2t(nlu->settings.szProxyAuthPassword);
			}

			szAuthHdr = NtlmCreateResponseFromChallenge(m_hNtlmSecurity,
				szChallenge, szLogin, szPassw, true, complete);

			if (!szAuthHdr) {
				NetlibLogf(NULL, "Security login %s failed, user: %S pssw: %S",
					szProvider, szLogin ? szLogin : _T("(no user)"), szPassw ? _T("(exist)") : _T("(no psw)"));
			}
			else if (justCreated)
				proxyAuthList.add(m_szHost, m_szProvider);

			mir_free(szLogin);
			mir_free(szPassw);
		}
		else complete = 1;

		return szAuthHdr;
	}
Пример #3
0
static int NetlibInitSocks4Connection(NetlibConnection *nlc, NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
{	
	//	http://www.socks.nec.com/protocol/socks4.protocol and http://www.socks.nec.com/protocol/socks4a.protocol
	if (!nloc->szHost || !nloc->szHost[0]) return 0;

	size_t nHostLen = strlen(nloc->szHost) + 1;
	size_t nUserLen = nlu->settings.szProxyAuthUser ? strlen(nlu->settings.szProxyAuthUser) + 1 : 1;
	size_t len = 8 + nUserLen;

	char* pInit = (char*)alloca(len + nHostLen);
	pInit[0] = 4;	// SOCKS4
	pInit[1] = 1;	//connect
	*(PWORD)&pInit[2] = htons(nloc->wPort);

	if (nUserLen <= 1) pInit[8] = 0;
	else memcpy(&pInit[8], nlu->settings.szProxyAuthUser, nUserLen);

	//if cannot resolve host, try resolving through proxy (requires SOCKS4a)  
	DWORD ip = DnsLookup(nlu, nloc->szHost);
	*(PDWORD)&pInit[4] = ip ? ip : 0x01000000; 	
	if (!ip) 
	{
		memcpy(&pInit[len], nloc->szHost, nHostLen);
		len += nHostLen;
	}

	if (NLSend(nlc, pInit, (int)len, MSG_DUMPPROXY) == SOCKET_ERROR) 
	{
		NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
		return 0;
	}

	char reply[8];
	if (!RecvUntilTimeout(nlc, reply, sizeof(reply), MSG_DUMPPROXY, RECV_DEFAULT_TIMEOUT)) 
	{
		NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
		return 0;
	}

	switch ((BYTE)reply[1]) 
	{
	case 90: return 1;
	case 91: SetLastError(ERROR_ACCESS_DENIED); break;
	case 92: SetLastError(ERROR_CONNECTION_UNAVAIL); break;
	case 93: SetLastError(ERROR_INVALID_ACCESS); break;
	default: SetLastError(ERROR_INVALID_DATA); break;
	}
	NetlibLogf(nlu,"%s %d: Proxy connection failed (%x %u)",__FILE__,__LINE__, (BYTE)reply[1], GetLastError());
	return 0;
}
Пример #4
0
static int NetlibHttpFallbackToDirect(NetlibConnection *nlc, NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
{
	NetlibDoClose(nlc, true);

	NetlibLogf(nlu, "Fallback to direct connection");

	nlc->proxyAuthNeeded = false;
	nlc->proxyType = 0;
	mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;
	if (!my_connect(nlc, nloc)) {
		NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
		return false;
	}
	return true;
}
Пример #5
0
INT_PTR NetlibStartSsl(WPARAM wParam, LPARAM lParam)
{
	NetlibConnection *nlc = (NetlibConnection*)wParam;
	if (nlc == NULL) return 0;

	NETLIBSSL *sp = (NETLIBSSL*)lParam;
	const char *szHost = sp ? sp->host : nlc->nloc.szHost;

	NetlibLogf(nlc->nlu, "(%d %s) Starting SSL negotiation", nlc->s, szHost);
	nlc->hSsl = si.connect(nlc->s, szHost, nlc->nlu->settings.validateSSL);

	if (nlc->hSsl == NULL)
		NetlibLogf(nlc->nlu,"(%d %s) Failure to negotiate SSL connection", nlc->s, szHost);
	else
		NetlibLogf(nlc->nlu, "(%d %s) SSL negotiation successful", nlc->s, szHost);

	return nlc->hSsl != NULL;
}
Пример #6
0
int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
{
    closesocket(nlbp->s);
    WaitForSingleObject(nlbp->hThread,INFINITE);
    CloseHandle(nlbp->hThread);
    NetlibLogf(nlbp->nlu, "(%u) Port %u closed for incoming connections", nlbp->s, nlbp->wPort);
    mir_free(nlbp);
    return 1;
}
Пример #7
0
static void ReportSecError(SECURITY_STATUS scRet, int line)
{
	char szMsgBuf[256];
	FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, scRet, LANG_USER_DEFAULT, szMsgBuf, SIZEOF(szMsgBuf), NULL);

	char *p = strchr(szMsgBuf, 13); if (p) *p = 0;

	NetlibLogf(NULL, "Security error 0x%x on line %u (%s)", scRet, line, szMsgBuf);
}
Пример #8
0
static int NetlibHttpFallbackToDirect(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
{
	NetlibDoClose(nlc, true);

	NetlibLogf(nlu,"Fallback to direct connection");
	NetlibLogf(nlu,"(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort);

	nlc->proxyAuthNeeded = false;
	nlc->proxyType = 0;
	mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;
	nlc->sinProxy.sin_family = AF_INET;
	nlc->sinProxy.sin_port = htons(nloc->wPort);
	nlc->sinProxy.sin_addr.S_un.S_addr = DnsLookup(nlu, nloc->szHost);
	if (nlc->sinProxy.sin_addr.S_un.S_addr == 0 || my_connect(nlc, nloc) == SOCKET_ERROR) 
	{
		if (nlc->sinProxy.sin_addr.S_un.S_addr)
			NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
		return false;
	}
	return true;
}
Пример #9
0
void NetlibDoClose(NetlibConnection *nlc, bool noShutdown)
{
	NetlibLogf(nlc->nlu, "(%p:%u) Connection closed internal", nlc, nlc->s);
	if (nlc->hSsl)
	{
		if (!noShutdown) si.shutdown(nlc->hSsl);
		si.sfree(nlc->hSsl);
		nlc->hSsl = NULL;
	}
	if (nlc->s != INVALID_SOCKET) closesocket(nlc->s);
	nlc->s = INVALID_SOCKET;
}
Пример #10
0
INT_PTR NetlibOpenConnection(WPARAM wParam,LPARAM lParam)
{
	NETLIBOPENCONNECTION *nloc = (NETLIBOPENCONNECTION*)lParam;
	struct NetlibUser *nlu = (struct NetlibUser*)wParam;
	struct NetlibConnection *nlc;

	NetlibLogf(nlu,"Connection request to %s:%d (Flags %x)....", nloc->szHost, nloc->wPort, nloc->flags);

	if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_OUTGOING) || nloc == NULL ||
		(nloc->cbSize != NETLIBOPENCONNECTION_V1_SIZE && nloc->cbSize != sizeof(NETLIBOPENCONNECTION)) || 
		nloc->szHost == NULL || nloc->wPort == 0)
	{
		SetLastError(ERROR_INVALID_PARAMETER);
		return 0;
	}
	nlc = (struct NetlibConnection*)mir_calloc(sizeof(struct NetlibConnection));
	nlc->handleType = NLH_CONNECTION;
	nlc->nlu = nlu;
	nlc->nloc = *nloc;
	nlc->nloc.szHost = mir_strdup(nloc->szHost);
	nlc->s = INVALID_SOCKET;
	nlc->s2 = INVALID_SOCKET;
	nlc->dnsThroughProxy = nlu->settings.dnsThroughProxy != 0;

	InitializeCriticalSection(&nlc->csHttpSequenceNums);
	nlc->hOkToCloseEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
	nlc->dontCloseNow = 0;
	NetlibInitializeNestedCS(&nlc->ncsSend);
	NetlibInitializeNestedCS(&nlc->ncsRecv);

	if (!NetlibDoConnect(nlc))
	{
		FreePartiallyInitedConnection(nlc);		
		return 0;
	}

	if (iUPnPCleanup == 0)
	{
		EnterCriticalSection(&csNetlibUser);
		if (iUPnPCleanup == 0) 
		{
			iUPnPCleanup = 1;
			forkthread(NetlibUPnPCleanup, 0, NULL);
		}
		LeaveCriticalSection(&csNetlibUser);
	}

	return (INT_PTR)nlc;
}
Пример #11
0
static bool NetlibInitHttpsConnection(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
{	//rfc2817
	NETLIBHTTPREQUEST nlhrSend = {0}, *nlhrReply;
	char szUrl[512];

	nlhrSend.cbSize = sizeof(nlhrSend);
	nlhrSend.requestType = REQUEST_CONNECT;
	nlhrSend.flags = NLHRF_GENERATEHOST | NLHRF_DUMPPROXY | NLHRF_SMARTAUTHHEADER | NLHRF_HTTP11 | NLHRF_NOPROXY | NLHRF_REDIRECT;
	if (nlc->dnsThroughProxy) 
	{
		mir_snprintf(szUrl, SIZEOF(szUrl), "%s:%u", nloc->szHost, nloc->wPort);
	}
	else 
	{
		DWORD ip = DnsLookup(nlu, nloc->szHost);
		if (ip == 0) return false;
		mir_snprintf(szUrl, SIZEOF(szUrl), "%s:%u", inet_ntoa(*(PIN_ADDR)&ip), nloc->wPort);
	}
	nlhrSend.szUrl = szUrl;

	nlc->usingHttpGateway = true;

	if (NetlibHttpSendRequest((WPARAM)nlc, (LPARAM)&nlhrSend) == SOCKET_ERROR)
	{
		nlc->usingHttpGateway = false;
		return 0;
	}
	nlhrReply = NetlibHttpRecv(nlc, MSG_DUMPPROXY | MSG_RAW, MSG_DUMPPROXY | MSG_RAW, true);
	nlc->usingHttpGateway = false;
	if (nlhrReply == NULL) return false;
	if (nlhrReply->resultCode < 200 || nlhrReply->resultCode >= 300)
	{
		if (nlhrReply->resultCode == 403 && nlc->dnsThroughProxy) 
		{
			NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
			nlc->dnsThroughProxy = 0;
			return NetlibInitHttpsConnection(nlc, nlu, nloc);
		}

		NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
		NetlibLogf(nlu,"%s %d: %s request failed (%u %s)",__FILE__,__LINE__,nlu->settings.proxyType==PROXYTYPE_HTTP?"HTTP":"HTTPS",nlhrReply->resultCode,nlhrReply->szResultDescr);
		NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
		return 0;
	}
	NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
	//connected
	return true;
}
Пример #12
0
//returns in network byte order
DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost)
{
	HOSTENT* host;
	DWORD ip = inet_addr(szHost);
	if (ip != INADDR_NONE)
		return ip;

	__try 
	{
		host = gethostbyname(szHost);
		if ( host )
			return *(u_long*)host->h_addr_list[0];

		NetlibLogf(nlu,"%s %d: %s() for host %s failed (%u)",__FILE__,__LINE__,"gethostbyname", szHost, WSAGetLastError());
	}
	__except(EXCEPTION_EXECUTE_HANDLER) {}

	return 0;
}
Пример #13
0
static bool findUPnPGateway(void)
{
	if ((time(NULL) - lastDiscTime) >= expireTime) {
		WaitForSingleObject(portListMutex, INFINITE);

		time_t curTime = time(NULL);

		if ((curTime - lastDiscTime) >= expireTime) {
			gatewayFound = false;

			discoverUPnP();
			lastDiscTime = curTime;

			NetlibLogf(NULL, "UPnP Gateway detected %d, Control URL: %s", gatewayFound, szCtlUrl);
		}

		ReleaseMutex(portListMutex);
	}

	return gatewayFound;
}
Пример #14
0
INT_PTR NetlibPacketRecverGetMore(WPARAM wParam, LPARAM lParam)
{
	struct NetlibPacketRecver *nlpr = (struct NetlibPacketRecver*)wParam;
	NETLIBPACKETRECVER *nlprParam = (NETLIBPACKETRECVER*)lParam;

	if (GetNetlibHandleType(nlpr) != NLH_PACKETRECVER || nlprParam == NULL || nlprParam->cbSize != sizeof(NETLIBPACKETRECVER) || nlprParam->bytesUsed > nlpr->packetRecver.bytesAvailable) {
		SetLastError(ERROR_INVALID_PARAMETER);
		return SOCKET_ERROR;
	}
	if (Miranda_Terminated()) { /* HACK: Lame, break while loops of protocols that can't kill their while loops, (cough, ICQ, cough) */
		SetLastError(ERROR_TIMEOUT);
		return SOCKET_ERROR;
	}
	nlpr->packetRecver.dwTimeout = nlprParam->dwTimeout;
	if (nlprParam->bytesUsed == 0) {
		if (nlpr->packetRecver.bytesAvailable == nlpr->packetRecver.bufferSize) {
			nlpr->packetRecver.bytesAvailable = 0;
			NetlibLogf(nlpr->nlc->nlu, "Packet recver: packet overflowed buffer, ditching");
		}
	}
	else {
		MoveMemory(nlpr->packetRecver.buffer, nlpr->packetRecver.buffer + nlprParam->bytesUsed, nlpr->packetRecver.bytesAvailable - nlprParam->bytesUsed);
		nlpr->packetRecver.bytesAvailable -= nlprParam->bytesUsed;
	}
	
	if (nlprParam->dwTimeout != INFINITE) {
		if (!si.pending(nlpr->nlc->hSsl) && WaitUntilReadable(nlpr->nlc->s, nlprParam->dwTimeout) <= 0) {
			*nlprParam = nlpr->packetRecver;
			return SOCKET_ERROR;
		}
	}
	
	INT_PTR recvResult = NLRecv(nlpr->nlc, (char*)nlpr->packetRecver.buffer + nlpr->packetRecver.bytesAvailable, nlpr->packetRecver.bufferSize - nlpr->packetRecver.bytesAvailable, 0);
	if (recvResult > 0)
		nlpr->packetRecver.bytesAvailable += recvResult;
	*nlprParam = nlpr->packetRecver;
	return recvResult;
}
Пример #15
0
bool NetlibReconnect(NetlibConnection *nlc)
{
	char buf[4];
	bool opened;  

	switch (WaitUntilReadable(nlc->s, 0, true))
	{
	case SOCKET_ERROR:
		opened = false;
		break;

	case 0:
		opened = true;
		break;

	case 1:
		opened = recv(nlc->s, buf, 1, MSG_PEEK) > 0;
		break;
	}

	if (!opened)
	{
		NetlibDoClose(nlc, true);

		if (Miranda_Terminated()) return false;

		if (nlc->usingHttpGateway)
		{
			nlc->proxyAuthNeeded = true;
			NetlibLogf(nlc->nlu,"(%p) Connecting....", nlc);
			return my_connect(nlc, &nlc->nloc) == 0;
		}
		else
			return NetlibDoConnect(nlc);
	}
	return true;
}
Пример #16
0
static int httpTransact(char* szUrl, char* szResult, int resSize, char* szActionName, ReqType reqtype)
{
	// Parse URL
	char szHost[256], szPath[256], szRes[16];
	int sz = 0, res = 0;
	unsigned short sPort;
	bool needClose = false;

	const char* szPostHdr = soap_post_hdr;
	char* szData = (char*)mir_alloc(4096);
	char* szReq = NULL;

	parseURL(szUrl, szHost, &sPort, szPath);

	if (sPort != sConnPort || _stricmp(szHost, szConnHost))
		closeRouterConnection();
	else
		validateSocket();

	while (true) {
		retryCount = 0;
		switch (reqtype) {
		case DeviceGetReq:
			sz = mir_snprintf(szData, 4096, xml_get_hdr, szPath, szHost, sPort);
			break;

		case ControlAction:
		{
			char szData1[1024];

			szReq = mir_strdup(szResult);
			sz = mir_snprintf(szData1, _countof(szData1),
				soap_action, szActionName, szDev, szReq, szActionName);

			sz = mir_snprintf(szData, 4096,
				szPostHdr, szPath, szHost, sPort,
				sz, szDev, szActionName, szData1);
		}
		break;

		case ControlQuery:
		{
			char szData1[1024];

			sz = mir_snprintf(szData1, _countof(szData1),
				soap_query, szActionName);

			sz = mir_snprintf(szData, 4096,
				szPostHdr, szPath, szHost, sPort,
				sz, "urn:schemas-upnp-org:control-1-0", "QueryStateVariable", szData1);
		}
		break;
		}
		szResult[0] = 0;
		{
			static const TIMEVAL tv = { 6, 0 };
			static unsigned ttl = 4;
			static u_long mode = 1;
			fd_set rfd, wfd, efd;
			SOCKADDR_IN enetaddr;

retrycon:
			if (sock == INVALID_SOCKET) {
				sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

				enetaddr.sin_family = AF_INET;
				enetaddr.sin_port = htons(sPort);
				enetaddr.sin_addr.s_addr = inet_addr(szHost);

				// Resolve host name if needed
				if (enetaddr.sin_addr.s_addr == INADDR_NONE) {
					PHOSTENT he = gethostbyname(szHost);
					if (he)
						enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0];
				}

				NetlibLogf(NULL, "UPnP HTTP connection Host: %s Port: %u", szHost, sPort);

				FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd);
				FD_SET(sock, &rfd); FD_SET(sock, &wfd); FD_SET(sock, &efd);

				// Limit the scope of the connection (does not work for
				setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned));

				// Put socket into non-blocking mode for timeout on connect
				ioctlsocket(sock, FIONBIO, &mode);

				// Connect to the remote host
				if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == SOCKET_ERROR) {
					int err = WSAGetLastError();

					// Socket connection failed
					if (err != WSAEWOULDBLOCK) {
						closeRouterConnection();
						NetlibLogf(NULL, "UPnP connect failed %d", err);
						break;
					}
					// Wait for socket to connect
					else if (select(1, &rfd, &wfd, &efd, &tv) != 1) {
						closeRouterConnection();
						NetlibLogf(NULL, "UPnP connect timeout");
						break;
					}
					else if (!FD_ISSET(sock, &wfd)) {
						closeRouterConnection();
						NetlibLogf(NULL, "UPnP connect failed");
						break;
					}
				}
				strncpy_s(szConnHost, szHost, _TRUNCATE);
				sConnPort = sPort;
			}

			if (send(sock, szData, sz, 0) != SOCKET_ERROR) {
				char *hdrend = NULL;
				int acksz = 0, pktsz = 0;

				if (szActionName == NULL) {
					int len = sizeof(locIP);
					getsockname(sock, (SOCKADDR*)&locIP, &len);
					if (locIP.sin_addr.S_un.S_addr == 0x0100007f) {
						struct hostent *he;

						gethostname(szPath, sizeof(szPath));
						he = gethostbyname(szPath);
						if (he != NULL)
							locIP.sin_addr.S_un.S_addr = *(PDWORD)he->h_addr_list[0];
					}
				}

				LongLog(szData);
				sz = 0;
				while (true) {
					int bytesRecv;

					FD_ZERO(&rfd);
					FD_SET(sock, &rfd);

					// Wait for the next packet
					if (select(1, &rfd, NULL, NULL, &tv) != 1) {
						closeRouterConnection();
						NetlibLogf(NULL, "UPnP recieve timeout");
						break;
					}

					//
					bytesRecv = recv(sock, &szResult[sz], resSize - sz, 0);

					// Connection closed or aborted, all data received
					if (bytesRecv == 0 || bytesRecv == SOCKET_ERROR) {
						closeRouterConnection();
						if ((bytesRecv == SOCKET_ERROR || sz == 0) && retryCount < 2) {
							++retryCount;
							goto retrycon;
						}
						break;
					}

					sz += bytesRecv;

					// Insert null terminator to use string functions
					if (sz >= (resSize - 1)) {
						szResult[resSize - 1] = 0;
						break;
					}
					else
						szResult[sz] = 0;

					// HTTP header found?
					if (hdrend == NULL) {
						// Find HTTP header end
						hdrend = strstr(szResult, "\r\n\r\n");
						if (hdrend == NULL) {
							hdrend = strstr(szResult, "\n\n");
							if (hdrend) hdrend += 2;
						}

						else
							hdrend += 4;

						if (hdrend != NULL) {
							// Get packet size if provided
							if (txtParseParam(szResult, NULL, "Content-Length:", "\n", szRes, sizeof(szRes)) ||
								txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\n", szRes, sizeof(szRes))) {
								// Add size of HTTP header to the packet size to compute full transmission size
								pktsz = atol(ltrimp(szRes)) + (hdrend - szResult);
							}
							// Get encoding type if provided
							else if (txtParseParam(szResult, NULL, "Transfer-Encoding:", "\n", szRes, sizeof(szRes))) {
								if (_stricmp(lrtrimp(szRes), "Chunked") == 0)
									acksz = hdrend - szResult;
							}
							if (txtParseParam(szResult, NULL, "Connection:", "\n", szRes, sizeof(szRes))) {
								needClose = (_stricmp(lrtrimp(szRes), "close") == 0);
							}
						}
					}

					// Content-Length bytes reached, all data received
					if (sz >= pktsz && pktsz != 0) {
						szResult[pktsz] = 0;
						break;
					}

					// Chunked encoding processing
					if (sz > acksz && acksz != 0) {
retry:
						// Parse out chunk size
						char* data = szResult + acksz;
						char* peol1 = data == hdrend ? data - 1 : strchr(data, '\n');
						if (peol1 != NULL) {
							char *peol2 = strchr(++peol1, '\n');
							if (peol2 != NULL) {
								// Get chunk size
								int chunkBytes = strtol(peol1, NULL, 16);
								acksz += chunkBytes;
								peol2++;

								memmove(data, peol2, mir_strlen(peol2) + 1);
								sz -= peol2 - data;

								// Last chunk, all data received
								if (chunkBytes == 0) break;
								if (sz > acksz) goto retry;
							}
						}
					}
				}
				LongLog(szResult);
			}
			else {
				if (retryCount < 2) {
					closeRouterConnection();
					++retryCount;
					goto retrycon;
				}
				else
					NetlibLogf(NULL, "UPnP send failed %d", WSAGetLastError());
			}
		}
		txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes));
		res = atol(szRes);
		if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr)
			szPostHdr = soap_post_hdr_m;
		else
			break;
	}

	if (needClose)
		closeRouterConnection();

	mir_free(szData);
	mir_free(szReq);
	return res;
}
Пример #17
0
char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw, 
									  bool http, unsigned& complete)
{
	SECURITY_STATUS sc;
	SecBufferDesc outputBufferDescriptor,inputBufferDescriptor;
	SecBuffer outputSecurityToken,inputSecurityToken;
	TimeStamp tokenExpiration;
	ULONG contextAttributes;
	NETLIBBASE64 nlb64 = { 0 };

	NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;

	if (hSecurity == NULL || ntlmCnt == 0) return NULL;

 	if (_tcsicmp(hNtlm->szProvider, _T("Basic")))
	{
		bool isGSSAPI = _tcsicmp(hNtlm->szProvider, _T("GSSAPI")) == 0;
		TCHAR *szProvider = isGSSAPI ? _T("Kerberos") : hNtlm->szProvider;
		bool hasChallenge = szChallenge != NULL && szChallenge[0] != '\0';
		if (hasChallenge) 
		{
			nlb64.cchEncoded = lstrlenA(szChallenge);
			nlb64.pszEncoded = (char*)szChallenge;
			nlb64.cbDecoded = Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
			nlb64.pbDecoded = (PBYTE)alloca(nlb64.cbDecoded);
			if (!NetlibBase64Decode(0, (LPARAM)&nlb64)) return NULL;

			if (isGSSAPI && complete)
				return CompleteGssapi(hSecurity, nlb64.pbDecoded, nlb64.cbDecoded);

			inputBufferDescriptor.cBuffers = 1;
			inputBufferDescriptor.pBuffers = &inputSecurityToken;
			inputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
			inputSecurityToken.BufferType = SECBUFFER_TOKEN;
			inputSecurityToken.cbBuffer = nlb64.cbDecoded;
			inputSecurityToken.pvBuffer = nlb64.pbDecoded;

			// try to decode the domain name from the NTLM challenge
			if (login != NULL && login[0] != '\0' && !hNtlm->hasDomain) 
			{
				NtlmType2packet* pkt = ( NtlmType2packet* )nlb64.pbDecoded;
				if (!strncmp(pkt->sign, "NTLMSSP", 8) && pkt->type == 2) 
				{
#ifdef UNICODE
					wchar_t* domainName = (wchar_t*)&nlb64.pbDecoded[pkt->targetName.offset];
					int domainLen = pkt->targetName.len;

					// Negotiate ANSI? if yes, convert the ANSI name to unicode
					if ((pkt->flags & 1) == 0) 
					{
						int bufsz = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, NULL, 0);
						wchar_t* buf = (wchar_t*)alloca(bufsz * sizeof(wchar_t));
						domainLen = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, buf, bufsz) - 1;
						domainName = buf;
					}
					else
						domainLen /= sizeof(wchar_t);
#else
					char* domainName = (char*)&nlb64.pbDecoded[pkt->targetName.offset];
					int domainLen = pkt->targetName.len;

					// Negotiate Unicode? if yes, convert the unicode name to ANSI
					if (pkt->flags & 1) 
					{
						int bufsz = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)domainName, domainLen, NULL, 0, NULL, NULL);
						char* buf = (char*)alloca(bufsz);
						domainLen = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)domainName, domainLen, buf, bufsz, NULL, NULL) - 1;
						domainName = buf;
					}
#endif

					if (domainLen) 
					{
						size_t newLoginLen = _tcslen(login) + domainLen + 1;
						TCHAR *newLogin = (TCHAR*)alloca(newLoginLen * sizeof(TCHAR));

						_tcsncpy(newLogin, domainName, domainLen);
						newLogin[domainLen] = '\\';
						_tcscpy(newLogin + domainLen + 1, login);

						char* szChl = NtlmCreateResponseFromChallenge(hSecurity, NULL, newLogin, psw, http, complete);
						mir_free(szChl);
					}
				}
			}
		}
		else 
		{
			if (SecIsValidHandle(&hNtlm->hClientContext)) g_pSSPI->DeleteSecurityContext(&hNtlm->hClientContext);
			if (SecIsValidHandle(&hNtlm->hClientCredential)) g_pSSPI->FreeCredentialsHandle(&hNtlm->hClientCredential);

			SEC_WINNT_AUTH_IDENTITY auth;

			if (login != NULL && login[0] != '\0') 
			{
				memset(&auth, 0, sizeof(auth));
#ifdef _UNICODE
				NetlibLogf(NULL, "Security login requested, user: %S pssw: %s", login, psw ? "(exist)" : "(no psw)");
#else
				NetlibLogf(NULL, "Security login requested, user: %s pssw: %s", login, psw ? "(exist)" : "(no psw)");
#endif

				const TCHAR* loginName = login;
				const TCHAR* domainName = _tcschr(login, '\\');
				int domainLen = 0;
				int loginLen = lstrlen(loginName);
				if (domainName != NULL) 
				{
					loginName = domainName + 1;
					loginLen = lstrlen(loginName);
					domainLen = domainName - login;
					domainName = login;
				}
				else if ((domainName = _tcschr(login, '@')) != NULL) 
				{
					loginName = login;
					loginLen = domainName - login;
					domainLen = lstrlen(++domainName);
				}

#ifdef UNICODE
				auth.User = (PWORD)loginName;
				auth.UserLength = loginLen;
				auth.Password = (PWORD)psw;
				auth.PasswordLength = lstrlen(psw);
				auth.Domain = (PWORD)domainName;
				auth.DomainLength = domainLen;
				auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
				auth.User = (PBYTE)loginName;
				auth.UserLength = loginLen;
				auth.Password = (PBYTE)psw;
				auth.PasswordLength = lstrlen(psw);
				auth.Domain = (PBYTE)domainName;
				auth.DomainLength = domainLen;
				auth.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif

				hNtlm->hasDomain = domainLen != 0;
			}

			sc = g_pSSPI->AcquireCredentialsHandle(NULL, szProvider, 
				SECPKG_CRED_OUTBOUND, NULL, hNtlm->hasDomain ? &auth : NULL, NULL, NULL, 
				&hNtlm->hClientCredential, &tokenExpiration);
			if (sc != SEC_E_OK) 
			{
				ReportSecError(sc, __LINE__);
				return NULL;
			}
		}

		outputBufferDescriptor.cBuffers = 1;
		outputBufferDescriptor.pBuffers = &outputSecurityToken;
		outputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
		outputSecurityToken.BufferType = SECBUFFER_TOKEN;
		outputSecurityToken.cbBuffer = hNtlm->cbMaxToken;
		outputSecurityToken.pvBuffer = alloca(outputSecurityToken.cbBuffer);

		sc = g_pSSPI->InitializeSecurityContext(&hNtlm->hClientCredential,
			hasChallenge ? &hNtlm->hClientContext : NULL,
			hNtlm->szPrincipal, isGSSAPI ? ISC_REQ_MUTUAL_AUTH | ISC_REQ_STREAM : 0, 0, SECURITY_NATIVE_DREP,
			hasChallenge ? &inputBufferDescriptor : NULL, 0, &hNtlm->hClientContext,
			&outputBufferDescriptor, &contextAttributes, &tokenExpiration);

		complete = (sc != SEC_I_COMPLETE_AND_CONTINUE && sc != SEC_I_CONTINUE_NEEDED);

		if (sc == SEC_I_COMPLETE_NEEDED || sc == SEC_I_COMPLETE_AND_CONTINUE)
		{
			sc = g_pSSPI->CompleteAuthToken(&hNtlm->hClientContext, &outputBufferDescriptor);
		}

		if (sc != SEC_E_OK && sc != SEC_I_CONTINUE_NEEDED)
		{
			ReportSecError(sc, __LINE__);
			return NULL;
		}

		nlb64.cbDecoded = outputSecurityToken.cbBuffer;
		nlb64.pbDecoded = (PBYTE)outputSecurityToken.pvBuffer;
	}
	else
	{
		if (!login || !psw) return NULL;

		char *szLogin = mir_t2a(login);
		char *szPassw = mir_t2a(psw);

		size_t authLen = strlen(szLogin) + strlen(szPassw) + 5;
		char *szAuth = (char*)alloca(authLen);
		
		nlb64.cbDecoded = mir_snprintf(szAuth, authLen,"%s:%s", szLogin, szPassw);
		nlb64.pbDecoded=(PBYTE)szAuth;
		complete = true;

		mir_free(szPassw);
		mir_free(szLogin);
	}

	nlb64.cchEncoded = Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
	nlb64.pszEncoded = (char*)alloca(nlb64.cchEncoded);
	if (!NetlibBase64Encode(0,(LPARAM)&nlb64)) return NULL;

	char* result;
	if (http)
	{
		char* szProvider = mir_t2a(hNtlm->szProvider);
		nlb64.cchEncoded += (int)strlen(szProvider) + 10;
		result = (char*)mir_alloc(nlb64.cchEncoded);
		mir_snprintf(result, nlb64.cchEncoded, "%s %s", szProvider, nlb64.pszEncoded);
		mir_free(szProvider);
	}
	else
		result = mir_strdup(nlb64.pszEncoded);

	return result;
}
Пример #18
0
INT_PTR NetlibHttpSendRequest(WPARAM wParam, LPARAM lParam)
{
	NetlibConnection *nlc = (struct NetlibConnection*)wParam;
	NETLIBHTTPREQUEST *nlhr = (NETLIBHTTPREQUEST*)lParam;
	NETLIBHTTPREQUEST *nlhrReply = NULL;
	HttpSecurityContext httpSecurity;

	struct ResizableCharBuffer httpRequest = { 0 };
	char *szHost = NULL, *szNewUrl = NULL;
	char *pszProxyAuthHdr = NULL, *pszAuthHdr = NULL;
	int i, doneHostHeader, doneContentLengthHeader, doneProxyAuthHeader, doneAuthHeader;
	int bytesSent = 0;
	bool lastFirstLineFail = false;

	if (nlhr == NULL || nlhr->cbSize != sizeof(NETLIBHTTPREQUEST) || nlhr->szUrl == NULL || nlhr->szUrl[0] == '\0') {
		SetLastError(ERROR_INVALID_PARAMETER);
		return SOCKET_ERROR;
	}

	NetlibUser *nlu = nlc->nlu;
	if (GetNetlibHandleType(nlu) != NLH_USER) {
		SetLastError(ERROR_INVALID_PARAMETER);
		return SOCKET_ERROR;
	}

	int hdrTimeout = (nlhr->timeout) ? nlhr->timeout : HTTPRECVHEADERSTIMEOUT;

	const char *pszRequest;
	switch (nlhr->requestType) {
	case REQUEST_GET:     pszRequest = "GET";     break;
	case REQUEST_POST:    pszRequest = "POST";    break;
	case REQUEST_CONNECT: pszRequest = "CONNECT"; break;
	case REQUEST_HEAD:    pszRequest = "HEAD";    break;
	case REQUEST_PUT:     pszRequest = "PUT";     break;
	case REQUEST_DELETE:  pszRequest = "DELETE";  break;
	default:
		SetLastError(ERROR_INVALID_PARAMETER);
		return SOCKET_ERROR;
	}

	if (!nlc->usingHttpGateway)
		if (!NetlibEnterNestedCS(nlc, NLNCS_SEND))
			return SOCKET_ERROR;

	const char *pszFullUrl = nlhr->szUrl;
	const char *pszUrl = NULL;

	unsigned complete = false;
	int count = 11;
	while (--count) {
		if (GetNetlibHandleType(nlc) != NLH_CONNECTION) {
			nlc = NULL;
			bytesSent = SOCKET_ERROR;
			break;
		}

		if (!NetlibReconnect(nlc)) {
			bytesSent = SOCKET_ERROR;
			break;
		}

		if (!pszUrl) {
			pszUrl = pszFullUrl;
			if (nlhr->flags & (NLHRF_SMARTREMOVEHOST | NLHRF_REMOVEHOST | NLHRF_GENERATEHOST)) {
				bool usingProxy = nlc->proxyType == PROXYTYPE_HTTP && !(nlhr->flags & NLHRF_SSL);

				mir_free(szHost);
				szHost = NULL;

				const char *ppath, *phost;
				phost = strstr(pszUrl, "://");
				if (phost == NULL) phost = pszUrl;
				else phost += 3;
				ppath = strchr(phost, '/');
				if (ppath == phost) phost = NULL;

				if (nlhr->flags & NLHRF_GENERATEHOST) {
					szHost = mir_strdup(phost);
					if (ppath && phost) szHost[ppath - phost] = 0;
				}

				if (nlhr->flags & NLHRF_REMOVEHOST || (nlhr->flags & NLHRF_SMARTREMOVEHOST && !usingProxy))
					pszUrl = ppath ? ppath : "/";

				if (usingProxy && phost && !nlc->dnsThroughProxy) {
					char* tszHost = mir_strdup(phost);
					if (ppath && phost) tszHost[ppath - phost] = 0;
					char* cln = strchr(tszHost, ':'); if (cln) *cln = 0;

					if (inet_addr(tszHost) == INADDR_NONE) {
						DWORD ip = DnsLookup(nlu, tszHost);
						if (ip && szHost) {
							mir_free(szHost);
							szHost = (char*)mir_alloc(64);
							if (cln) *cln = ':';
							mir_snprintf(szHost, 64, "%s%s", inet_ntoa(*(PIN_ADDR)&ip), cln ? cln : "");
						}
					}
					mir_free(tszHost);
				}
			}
		}

		if (nlc->proxyAuthNeeded && proxyAuthList.getCount()) {
			if (httpSecurity.m_szProvider == NULL && nlc->szProxyServer) {
				const char *szAuthMethodNlu = proxyAuthList.find(nlc->szProxyServer);
				if (szAuthMethodNlu) {
					mir_free(pszProxyAuthHdr);
					pszProxyAuthHdr = httpSecurity.Execute(nlc, nlc->szProxyServer, szAuthMethodNlu, "", complete);
				}
			}
		}
		nlc->proxyAuthNeeded = false;

		AppendToCharBuffer(&httpRequest, "%s %s HTTP/1.%d\r\n", pszRequest, pszUrl, (nlhr->flags & NLHRF_HTTP11) != 0);

		//HTTP headers
		doneHostHeader = doneContentLengthHeader = doneProxyAuthHeader = doneAuthHeader = 0;
		for (i=0; i < nlhr->headersCount; i++) {
			NETLIBHTTPHEADER &p = nlhr->headers[i];
			if (!mir_strcmpi(p.szName, "Host")) doneHostHeader = 1;
			else if (!mir_strcmpi(p.szName, "Content-Length")) doneContentLengthHeader = 1;
			else if (!mir_strcmpi(p.szName, "Proxy-Authorization")) doneProxyAuthHeader = 1;
			else if (!mir_strcmpi(p.szName, "Authorization")) doneAuthHeader = 1;
			else if (!mir_strcmpi(p.szName, "Connection")) continue;
			if (p.szValue == NULL) continue;
			AppendToCharBuffer(&httpRequest, "%s: %s\r\n", p.szName, p.szValue);
		}
		if (szHost && !doneHostHeader)
			AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Host", szHost);
		if (pszProxyAuthHdr && !doneProxyAuthHeader)
			AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Proxy-Authorization", pszProxyAuthHdr);
		if (pszAuthHdr && !doneAuthHeader)
			AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Authorization", pszAuthHdr);
		AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Connection", "Keep-Alive");
		AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Proxy-Connection", "Keep-Alive");

		// Add Sticky Headers
		if (nlu->szStickyHeaders != NULL)
			AppendToCharBuffer(&httpRequest, "%s\r\n", nlu->szStickyHeaders);

		//send it
		bytesSent = SendHttpRequestAndData(nlc, &httpRequest, nlhr, !doneContentLengthHeader);
		if (bytesSent == SOCKET_ERROR)
			break;

		//ntlm reply
		if (doneContentLengthHeader && nlhr->requestType != REQUEST_HEAD)
			break;

		DWORD fflags = MSG_PEEK | MSG_NODUMP | ((nlhr->flags & NLHRF_NOPROXY) ? MSG_RAW : 0);
		DWORD dwTimeOutTime = hdrTimeout < 0 ? -1 : GetTickCount() + hdrTimeout;
		if (!HttpPeekFirstResponseLine(nlc, dwTimeOutTime, fflags, &nlhr->resultCode, NULL, NULL)) {
			DWORD err = GetLastError();
			NetlibLogf(nlu, "%s %d: %s Failed (%u %u)", __FILE__, __LINE__, "HttpPeekFirstResponseLine", err, count);

			// connection died while we were waiting
			if (GetNetlibHandleType(nlc) != NLH_CONNECTION) {
				nlc = NULL;
				break;
			}

			if (err == ERROR_TIMEOUT || err == ERROR_BAD_FORMAT || err == ERROR_BUFFER_OVERFLOW || lastFirstLineFail || nlc->termRequested || nlhr->requestType == REQUEST_CONNECT) {
				bytesSent = SOCKET_ERROR;
				break;
			}

			lastFirstLineFail = true;
			continue;
		}

		int resultCode = nlhr->resultCode;
		lastFirstLineFail = false;

		DWORD hflags = (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPHEADERS | NLHRF_NODUMPSEND) ?
		MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
						 (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);

		DWORD dflags = (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPSEND) ? MSG_NODUMP : MSG_DUMPASTEXT | MSG_DUMPPROXY) |
			(nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0) | MSG_NODUMP;

		if (resultCode == 100)
			nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);

		else if (resultCode == 307 || ((resultCode == 301 || resultCode == 302) && (nlhr->flags & NLHRF_REDIRECT))) { // redirect
			pszUrl = NULL;

			if (nlhr->requestType == REQUEST_HEAD)
				nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
			else
				nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);

			if (nlhrReply) {
				char* tmpUrl = NetlibHttpFindHeader(nlhrReply, "Location");
				if (tmpUrl) {
					size_t rlen = 0;
					if (tmpUrl[0] == '/') {
						const char *ppath, *phost;
						phost = strstr(pszFullUrl, "://");
						phost = phost ? phost + 3 : pszFullUrl;
						ppath = strchr(phost, '/');
						rlen = ppath ? ppath - pszFullUrl : mir_strlen(pszFullUrl);
					}

					nlc->szNewUrl = (char*)mir_realloc(nlc->szNewUrl, rlen + mir_strlen(tmpUrl) * 3 + 1);

					strncpy(nlc->szNewUrl, pszFullUrl, rlen);
					mir_strcpy(nlc->szNewUrl + rlen, tmpUrl);
					pszFullUrl = nlc->szNewUrl;
					pszUrl = NULL;

					if (NetlibHttpProcessUrl(nlhr, nlu, nlc, pszFullUrl) == NULL) {
						bytesSent = SOCKET_ERROR;
						break;
					}
				}
				else {
					NetlibHttpSetLastErrorUsingHttpResult(resultCode);
					bytesSent = SOCKET_ERROR;
					break;
				}
			}
			else {
				NetlibHttpSetLastErrorUsingHttpResult(resultCode);
				bytesSent = SOCKET_ERROR;
				break;
			}
		}
		else if (resultCode == 401 && !doneAuthHeader) { //auth required
			if (nlhr->requestType == REQUEST_HEAD)
				nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
			else
				nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);

			mir_free(pszAuthHdr); pszAuthHdr = NULL;
			if (nlhrReply) {
				char *szAuthStr = NULL;
				if (!complete) {
					szAuthStr = NetlibHttpFindAuthHeader(nlhrReply, "WWW-Authenticate", httpSecurity.m_szProvider);
					if (szAuthStr) {
						char *szChallenge = strchr(szAuthStr, ' ');
						if (!szChallenge || !*lrtrimp(szChallenge))
							complete = true;
					}
				}
				if (complete && httpSecurity.m_hNtlmSecurity)
					szAuthStr = httpSecurity.TryBasic() ? NetlibHttpFindAuthHeader(nlhrReply, "WWW-Authenticate", "Basic") : NULL;

				if (szAuthStr) {
					char *szChallenge = strchr(szAuthStr, ' ');
					if (szChallenge) { *szChallenge = 0; szChallenge = lrtrimp(szChallenge + 1); }

					pszAuthHdr = httpSecurity.Execute(nlc, szHost, szAuthStr, szChallenge, complete);
				}
			}
			if (pszAuthHdr == NULL) {
				proxyAuthList.add(szHost, NULL);
				NetlibHttpSetLastErrorUsingHttpResult(resultCode);
				bytesSent = SOCKET_ERROR;
				break;
			}
		}
		else if (resultCode == 407 && !doneProxyAuthHeader) { //proxy auth required
			if (nlhr->requestType == REQUEST_HEAD)
				nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
			else
				nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);

			mir_free(pszProxyAuthHdr); pszProxyAuthHdr = NULL;
			if (nlhrReply) {
				char *szAuthStr = NULL;
				if (!complete) {
					szAuthStr = NetlibHttpFindAuthHeader(nlhrReply, "Proxy-Authenticate", httpSecurity.m_szProvider);
					if (szAuthStr) {
						char *szChallenge = strchr(szAuthStr, ' ');
						if (!szChallenge || !*lrtrimp(szChallenge + 1))
							complete = true;
					}
				}
				if (complete && httpSecurity.m_hNtlmSecurity)
					szAuthStr = httpSecurity.TryBasic() ? NetlibHttpFindAuthHeader(nlhrReply, "Proxy-Authenticate", "Basic") : NULL;

				if (szAuthStr) {
					char *szChallenge = strchr(szAuthStr, ' ');
					if (szChallenge) { *szChallenge = 0; szChallenge = lrtrimp(szChallenge + 1); }

					pszProxyAuthHdr = httpSecurity.Execute(nlc, nlc->szProxyServer, szAuthStr, szChallenge, complete);
				}
			}
			if (pszProxyAuthHdr == NULL) {
				proxyAuthList.add(nlc->szProxyServer, NULL);
				NetlibHttpSetLastErrorUsingHttpResult(resultCode);
				bytesSent = SOCKET_ERROR;
				break;
			}
		}
		else break;

		if (pszProxyAuthHdr && resultCode != 407 && !doneProxyAuthHeader)
			replaceStr(pszProxyAuthHdr, NULL);

		if (pszAuthHdr && resultCode != 401 && !doneAuthHeader)
			replaceStr(pszAuthHdr, NULL);

		if (nlhrReply) {
			NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
			nlhrReply = NULL;
		}
	}

	if (count == 0) bytesSent = SOCKET_ERROR;
	if (nlhrReply)
		NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);

	//clean up
	mir_free(pszProxyAuthHdr);
	mir_free(pszAuthHdr);
	mir_free(szHost);
	mir_free(szNewUrl);

	if (nlc && !nlc->usingHttpGateway)
		NetlibLeaveNestedCS(&nlc->ncsSend);

	return bytesSent;
}
Пример #19
0
INT_PTR NetlibCloseHandle(WPARAM wParam, LPARAM)
{
	switch(GetNetlibHandleType(wParam)) {
		case NLH_USER:
		{	struct NetlibUser *nlu=(struct NetlibUser*)wParam;
			int i;
			
			EnterCriticalSection(&csNetlibUser);
			i = netlibUser.getIndex(nlu);
			if (i >= 0) netlibUser.remove(i);
			LeaveCriticalSection(&csNetlibUser);

			NetlibFreeUserSettingsStruct(&nlu->settings);
			mir_free(nlu->user.szSettingsModule);
			mir_free(nlu->user.szDescriptiveName);
			mir_free(nlu->user.szHttpGatewayHello);
			mir_free(nlu->user.szHttpGatewayUserAgent);
			mir_free(nlu->szStickyHeaders);
			break;
		}
		case NLH_CONNECTION:
		{	struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
			HANDLE waitHandles[4];
			DWORD waitResult;

			WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
			if (nlc->usingHttpGateway)
			{
				HttpGatewayRemovePacket(nlc, -1);
			}
			else
			{
				if(nlc->s != INVALID_SOCKET) {
					NetlibDoClose(nlc);
				}
				if (nlc->s2 != INVALID_SOCKET) closesocket(nlc->s2);
				nlc->s2 = INVALID_SOCKET;
			}
			ReleaseMutex(hConnectionHeaderMutex);

			waitHandles[0]=hConnectionHeaderMutex;
			waitHandles[1]=nlc->hOkToCloseEvent;
			waitHandles[2]=nlc->ncsRecv.hMutex;
			waitHandles[3]=nlc->ncsSend.hMutex;
			waitResult=WaitForMultipleObjects( SIZEOF(waitHandles),waitHandles,TRUE,INFINITE);
			if(waitResult<WAIT_OBJECT_0 || waitResult >= WAIT_OBJECT_0 + SIZEOF(waitHandles)) {
				ReleaseMutex(hConnectionHeaderMutex);
				SetLastError(ERROR_INVALID_PARAMETER);	  //already been closed
				return 0;
			}
			nlc->handleType=0;
			mir_free(nlc->nlhpi.szHttpPostUrl);
			mir_free(nlc->nlhpi.szHttpGetUrl);
			mir_free(nlc->dataBuffer);
			mir_free((char*)nlc->nloc.szHost);
			mir_free(nlc->szNewUrl);
			mir_free(nlc->szProxyServer);
			NetlibDeleteNestedCS(&nlc->ncsRecv);
			NetlibDeleteNestedCS(&nlc->ncsSend);
			CloseHandle(nlc->hOkToCloseEvent);
			DeleteCriticalSection(&nlc->csHttpSequenceNums);
			ReleaseMutex(hConnectionHeaderMutex);
			NetlibLogf(nlc->nlu,"(%p:%u) Connection closed",nlc,nlc->s);
			break;
		}
		case NLH_BOUNDPORT:
			return NetlibFreeBoundPort((struct NetlibBoundPort*)wParam);
		case NLH_PACKETRECVER:
		{	struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
			mir_free(nlpr->packetRecver.buffer);
			break;
		}
		default:
			SetLastError(ERROR_INVALID_PARAMETER);
			return 0;
	}
	mir_free((void*)wParam);
	return 1;
}
Пример #20
0
char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw, bool http, unsigned& complete)
{
	if (hSecurity == NULL || ntlmCnt == 0)
		return NULL;

	SecBufferDesc outputBufferDescriptor, inputBufferDescriptor;
	SecBuffer outputSecurityToken, inputSecurityToken;
	TimeStamp tokenExpiration;
	ULONG contextAttributes;
	char *szOutputToken;

	NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;
	if (mir_tstrcmpi(hNtlm->szProvider, _T("Basic"))) {
		bool isGSSAPI = mir_tstrcmpi(hNtlm->szProvider, _T("GSSAPI")) == 0;
		TCHAR *szProvider = isGSSAPI ? (TCHAR*)_T("Kerberos") : hNtlm->szProvider;
		bool hasChallenge = szChallenge != NULL && szChallenge[0] != '\0';
		if (hasChallenge) {
			unsigned tokenLen;
			BYTE *token = (BYTE*)mir_base64_decode(szChallenge, &tokenLen);
			if (token == NULL)
				return NULL;

			if (isGSSAPI && complete)
				return CompleteGssapi(hSecurity, token, tokenLen);

			inputBufferDescriptor.cBuffers = 1;
			inputBufferDescriptor.pBuffers = &inputSecurityToken;
			inputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
			inputSecurityToken.BufferType = SECBUFFER_TOKEN;
			inputSecurityToken.cbBuffer = tokenLen;
			inputSecurityToken.pvBuffer = token;

			// try to decode the domain name from the NTLM challenge
			if (login != NULL && login[0] != '\0' && !hNtlm->hasDomain) {
				NtlmType2packet* pkt = (NtlmType2packet*)token;
				if (!strncmp(pkt->sign, "NTLMSSP", 8) && pkt->type == 2) {

					wchar_t* domainName = (wchar_t*)&token[pkt->targetName.offset];
					int domainLen = pkt->targetName.len;

					// Negotiate ANSI? if yes, convert the ANSI name to unicode
					if ((pkt->flags & 1) == 0) {
						int bufsz = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, NULL, 0);
						wchar_t* buf = (wchar_t*)alloca(bufsz * sizeof(wchar_t));
						domainLen = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, buf, bufsz) - 1;
						domainName = buf;
					}
					else domainLen /= sizeof(wchar_t);

					if (domainLen) {
						size_t newLoginLen = mir_tstrlen(login) + domainLen + 1;
						TCHAR *newLogin = (TCHAR*)alloca(newLoginLen * sizeof(TCHAR));

						_tcsncpy(newLogin, domainName, domainLen);
						newLogin[domainLen] = '\\';
						mir_tstrcpy(newLogin + domainLen + 1, login);

						char* szChl = NtlmCreateResponseFromChallenge(hSecurity, NULL, newLogin, psw, http, complete);
						mir_free(szChl);
					}
				}
			}
		}
		else {
			if (SecIsValidHandle(&hNtlm->hClientContext))
				DeleteSecurityContext(&hNtlm->hClientContext);
			if (SecIsValidHandle(&hNtlm->hClientCredential))
				FreeCredentialsHandle(&hNtlm->hClientCredential);

			SEC_WINNT_AUTH_IDENTITY auth;

			if (login != NULL && login[0] != '\0') {
				memset(&auth, 0, sizeof(auth));

				NetlibLogf(NULL, "Security login requested, user: %S pssw: %s", login, psw ? "(exist)" : "(no psw)");

				const TCHAR* loginName = login;
				const TCHAR* domainName = _tcschr(login, '\\');
				size_t domainLen = 0;
				size_t loginLen = mir_tstrlen(loginName);
				if (domainName != NULL) {
					loginName = domainName + 1;
					loginLen = mir_tstrlen(loginName);
					domainLen = domainName - login;
					domainName = login;
				}
				else if ((domainName = _tcschr(login, '@')) != NULL) {
					loginName = login;
					loginLen = domainName - login;
					domainLen = mir_tstrlen(++domainName);
				}

				auth.User = (PWORD)loginName;
				auth.UserLength = (ULONG)loginLen;
				auth.Password = (PWORD)psw;
				auth.PasswordLength = (ULONG)mir_tstrlen(psw);
				auth.Domain = (PWORD)domainName;
				auth.DomainLength = (ULONG)domainLen;
				auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

				hNtlm->hasDomain = domainLen != 0;
			}

			SECURITY_STATUS sc = AcquireCredentialsHandle(NULL, szProvider,
				SECPKG_CRED_OUTBOUND, NULL, hNtlm->hasDomain ? &auth : NULL, NULL, NULL,
				&hNtlm->hClientCredential, &tokenExpiration);
			if (sc != SEC_E_OK) {
				ReportSecError(sc, __LINE__);
				return NULL;
			}
		}

		outputBufferDescriptor.cBuffers = 1;
		outputBufferDescriptor.pBuffers = &outputSecurityToken;
		outputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
		outputSecurityToken.BufferType = SECBUFFER_TOKEN;
		outputSecurityToken.cbBuffer = hNtlm->cbMaxToken;
		outputSecurityToken.pvBuffer = alloca(outputSecurityToken.cbBuffer);

		SECURITY_STATUS sc = InitializeSecurityContext(&hNtlm->hClientCredential,
			hasChallenge ? &hNtlm->hClientContext : NULL,
			hNtlm->szPrincipal, isGSSAPI ? ISC_REQ_MUTUAL_AUTH | ISC_REQ_STREAM : 0, 0, SECURITY_NATIVE_DREP,
			hasChallenge ? &inputBufferDescriptor : NULL, 0, &hNtlm->hClientContext,
			&outputBufferDescriptor, &contextAttributes, &tokenExpiration);

		complete = (sc != SEC_I_COMPLETE_AND_CONTINUE && sc != SEC_I_CONTINUE_NEEDED);

		if (sc == SEC_I_COMPLETE_NEEDED || sc == SEC_I_COMPLETE_AND_CONTINUE)
			sc = CompleteAuthToken(&hNtlm->hClientContext, &outputBufferDescriptor);

		if (sc != SEC_E_OK && sc != SEC_I_CONTINUE_NEEDED) {
			ReportSecError(sc, __LINE__);
			return NULL;
		}

		szOutputToken = mir_base64_encode((PBYTE)outputSecurityToken.pvBuffer, outputSecurityToken.cbBuffer);
	}
	else {
		if (!login || !psw) return NULL;

		char *szLogin = mir_t2a(login);
		char *szPassw = mir_t2a(psw);

		size_t authLen = mir_strlen(szLogin) + mir_strlen(szPassw) + 5;
		char *szAuth = (char*)alloca(authLen);

		int len = mir_snprintf(szAuth, authLen, "%s:%s", szLogin, szPassw);
		szOutputToken = mir_base64_encode((BYTE*)szAuth, len);
		complete = true;

		mir_free(szPassw);
		mir_free(szLogin);
	}

	if (szOutputToken == NULL)
		return NULL;

	if (!http)
		return szOutputToken;

	ptrA szProvider(mir_t2a(hNtlm->szProvider));
	size_t resLen = mir_strlen(szOutputToken) + mir_strlen(szProvider) + 10;
	char *result = (char*)mir_alloc(resLen);
	mir_snprintf(result, resLen, "%s %s", szProvider, szOutputToken);
	mir_free(szOutputToken);
	return result;
}
Пример #21
0
INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam)
{
    NETLIBBIND *nlb = (NETLIBBIND*)lParam;
    struct NetlibUser *nlu = (struct NetlibUser*)wParam;
    struct NetlibBoundPort *nlbp;
    SOCKADDR_IN sin;
    int foundPort = 0;
    UINT dwThreadId;

    if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_INCOMING) ||
            nlb == NULL || nlb->pfnNewConnection == NULL)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    if (nlb->cbSize != sizeof(NETLIBBIND)   &&
            nlb->cbSize != NETLIBBIND_SIZEOF_V2 &&
            nlb->cbSize != NETLIBBIND_SIZEOF_V1)
    {
        return 0;
    }
    nlbp = (NetlibBoundPort*)mir_calloc(sizeof(NetlibBoundPort));
    nlbp->handleType = NLH_BOUNDPORT;
    nlbp->nlu = nlu;
    nlbp->pfnNewConnectionV2 = nlb->pfnNewConnectionV2;
    nlbp->s = socket(AF_INET, SOCK_STREAM, 0);
    nlbp->pExtra = (nlb->cbSize != NETLIBBIND_SIZEOF_V1) ? nlb->pExtra : NULL;
    if (nlbp->s == INVALID_SOCKET)
    {
        NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
        mir_free(nlbp);
        return 0;
    }
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = 0;

    /* if the netlib user wanted a free port given in the range, then
    they better have given wPort==0, let's hope so */
    if (nlu->settings.specifyIncomingPorts && nlu->settings.szIncomingPorts && nlb->wPort == 0)
    {
        if (!BindSocketToPort(nlu->settings.szIncomingPorts, nlbp->s, &nlu->outportnum))
        {
            NetlibLogf(nlu, "Netlib bind: Not enough ports for incoming connections specified");
            SetLastError(WSAEADDRINUSE);
        }
        else
            foundPort = 1;
    }
    else
    {
        /* if ->wPort==0 then they'll get any free port, otherwise they'll
        be asking for whatever was in nlb->wPort*/
        if (nlb->wPort != 0)
        {
            NetlibLogf(nlu,"%s %d: trying to bind port %d, this 'feature' can be abused, please be sure you want to allow it.",__FILE__,__LINE__,nlb->wPort);
            sin.sin_port = htons(nlb->wPort);
        }
        if (bind(nlbp->s, (PSOCKADDR)&sin, sizeof(sin)) == 0)
            foundPort = 1;
    }
    if (!foundPort)
    {
        NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"bind",WSAGetLastError());
        closesocket(nlbp->s);
        mir_free(nlbp);
        return 0;
    }

    if (listen(nlbp->s, 5))
    {
        NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
        closesocket(nlbp->s);
        mir_free(nlbp);
        return 0;
    }

    {   int len;
        DWORD extIP;

        ZeroMemory(&sin,sizeof(sin));
        len = sizeof(sin);
        if (getsockname(nlbp->s,(SOCKADDR *)&sin,&len))
        {
            NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"getsockname",WSAGetLastError());
            closesocket(nlbp->s);
            mir_free(nlbp);
            return 0;
        }
        nlb->wPort = ntohs(sin.sin_port);
        nlbp->wPort = nlb->wPort;
        nlb->dwInternalIP = ntohl(sin.sin_addr.S_un.S_addr);

        if (nlb->dwInternalIP == 0)
        {
            char hostname[64];
            struct hostent *he;

            gethostname(hostname, SIZEOF(hostname));
            he = gethostbyname(hostname);
            if (he && he->h_addr_list[0])
                nlb->dwInternalIP = ntohl(*(PDWORD)he->h_addr_list[0]);
        }
        if (nlu->settings.enableUPnP &&
                NetlibUPnPAddPortMapping(nlb->wPort, "TCP", &nlbp->wExPort, &extIP, nlb->cbSize > NETLIBBIND_SIZEOF_V2))
        {
            NetlibLogf(NULL, "UPnP port mapping succeeded. Internal Port: %u External Port: %u\n",
                       nlb->wPort, nlbp->wExPort);
            if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
            {
                nlb->wExPort = nlbp->wExPort;
                nlb->dwExternalIP = extIP;
            }
        }
        else
        {
            if (nlu->settings.enableUPnP)
                NetlibLogf(NULL, "UPnP port mapping failed. Internal Port: %u\n", nlb->wPort);
            else
                NetlibLogf(NULL, "UPnP disabled. Internal Port: %u\n", nlb->wPort);

            nlbp->wExPort = 0;
            if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
            {
                nlb->wExPort = nlb->wPort;
                nlb->dwExternalIP = nlb->dwInternalIP;
            }
        }
    }
    nlbp->hThread = (HANDLE)forkthreadex(NULL, 0, NetlibBindAcceptThread, 0, nlbp, &dwThreadId);
    return (INT_PTR)nlbp;
}
Пример #22
0
static bool my_connectIPv4(NetlibConnection *nlc, NETLIBOPENCONNECTION * nloc)
{
	int rc = 0, retrycnt = 0;
	u_long notblocking = 1;
	DWORD lasterr = 0;
	static const TIMEVAL tv = { 1, 0 };

	unsigned int dwTimeout = (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2) ? nloc->timeout : 0;
	// if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
	if (dwTimeout == 0) dwTimeout = 30;

	// this is for XP SP2 where there is a default connection attempt limit of 10/second
	if (connectionTimeout) {
		WaitForSingleObject(hConnectionOpenMutex, 10000);
		int waitdiff = GetTickCount() - g_LastConnectionTick;
		if (waitdiff < connectionTimeout) SleepEx(connectionTimeout, TRUE);
		g_LastConnectionTick = GetTickCount();
		ReleaseMutex(hConnectionOpenMutex);

		// might of died in between the wait
		if (Miranda_Terminated()) return false;
	}

	PHOSTENT he;
	SOCKADDR_IN sin = {0};
	sin.sin_family = AF_INET;

	if (nlc->proxyType) {
		if (!nlc->szProxyServer) return false;

		if (nloc)
			NetlibLogf(nlc->nlu, "(%p) Connecting to proxy %s:%d for %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort, nloc->szHost, nloc->wPort);
		else
			NetlibLogf(nlc->nlu, "(%p) Connecting to proxy %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort);

		sin.sin_port = htons(nlc->wProxyPort);
		he = gethostbyname(nlc->szProxyServer);
	}
	else {
		if (!nloc || !nloc->szHost || nloc->szHost[0] == '[' || strchr(nloc->szHost, ':')) return false;
		NetlibLogf(nlc->nlu, "(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort);

		sin.sin_port = htons(nloc->wPort);
		he = gethostbyname(nloc->szHost);
	}

	for (char** har = he->h_addr_list; *har && !Miranda_Terminated(); ++har) {
		sin.sin_addr.s_addr = *(u_long*)*har;

		char* szIp = NetlibAddressToString((SOCKADDR_INET_M*)&sin);
		NetlibLogf(nlc->nlu, "(%p) Connecting to ip %s ....", nlc, szIp);
		mir_free(szIp);

retry:
		nlc->s = socket(AF_INET, nloc->flags & NLOCF_UDP ? SOCK_DGRAM : SOCK_STREAM, 0);
		if (nlc->s == INVALID_SOCKET)
			return false;

		// return the socket to non blocking
		if (ioctlsocket(nlc->s, FIONBIO, &notblocking) != 0)
			return false;

		if (nlc->nlu->settings.specifyOutgoingPorts && nlc->nlu->settings.szOutgoingPorts  && nlc->nlu->settings.szOutgoingPorts[0]) {
			if (!BindSocketToPort(nlc->nlu->settings.szOutgoingPorts, nlc->s, INVALID_SOCKET, &nlc->nlu->inportnum))
				NetlibLogf(nlc->nlu, "Netlib connect: Not enough ports for outgoing connections specified");
		}

		// try a connect
		if (connect(nlc->s, (LPSOCKADDR)&sin, sizeof(sin)) == 0) {
			rc = 0;
			break;
		}

		// didn't work, was it cos of nonblocking?
		if (WSAGetLastError() != WSAEWOULDBLOCK) {
			rc = SOCKET_ERROR;
			closesocket(nlc->s);
			nlc->s = INVALID_SOCKET;
			continue;
		}

		while (true) {
			fd_set r, w, e;
			FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
			FD_SET(nlc->s, &r);
			FD_SET(nlc->s, &w);
			FD_SET(nlc->s, &e);
			if ((rc = select(0, &r, &w, &e, &tv)) == SOCKET_ERROR)
				break;

			if (rc > 0) {
				if (FD_ISSET(nlc->s, &w)){
					// connection was successful
					rc = 0;
				}
				if (FD_ISSET(nlc->s, &r)) {
					// connection was closed
					rc = SOCKET_ERROR;
					lasterr = WSAECONNRESET;
				}
				if (FD_ISSET(nlc->s, &e)) {
					// connection failed.
					int len = sizeof(lasterr);
					rc = SOCKET_ERROR;
					getsockopt(nlc->s, SOL_SOCKET, SO_ERROR, (char*)&lasterr, &len);
					if (lasterr == WSAEADDRINUSE && ++retrycnt <= 2) {
						closesocket(nlc->s);
						goto retry;
					}
				}
				break;
			}
			else if (Miranda_Terminated()) {
				rc = SOCKET_ERROR;
				lasterr = ERROR_TIMEOUT;
				break;
			}
			else if (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2 && nloc->waitcallback != NULL && nloc->waitcallback(&dwTimeout) == 0) {
				rc = SOCKET_ERROR;
				lasterr = ERROR_TIMEOUT;
				break;
			}
			if (--dwTimeout == 0) {
				rc = SOCKET_ERROR;
				lasterr = ERROR_TIMEOUT;
				break;
			}
		}

		if (rc == 0) break;

		closesocket(nlc->s);
		nlc->s = INVALID_SOCKET;
	}

	notblocking = 0;
	if (nlc->s != INVALID_SOCKET) ioctlsocket(nlc->s, FIONBIO, &notblocking);
	if (rc && lasterr) SetLastError(lasterr);
	return rc == 0;
}
Пример #23
0
static int NetlibInitSocks5Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
{	//rfc1928
	BYTE buf[258];

	buf[0]=5;  //yep, socks5
	buf[1]=1;  //one auth method
	buf[2]=nlu->settings.useProxyAuth?2:0;
	if(NLSend(nlc,(char*)buf,3,MSG_DUMPPROXY)==SOCKET_ERROR) {
		NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
		return 0;
	}

	//confirmation of auth method
	if (!RecvUntilTimeout(nlc,(char*)buf,2,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
		NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
		return 0;
	}
	if((buf[1]!=0 && buf[1]!=2)) {
		SetLastError(ERROR_INVALID_ID_AUTHORITY);
		NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
		return 0;
	}

	if(buf[1]==2) {		//rfc1929
		int nUserLen,nPassLen;
		PBYTE pAuthBuf;

		nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
		nPassLen=lstrlenA(nlu->settings.szProxyAuthPassword);
		pAuthBuf=(PBYTE)mir_alloc(3+nUserLen+nPassLen);
		pAuthBuf[0]=1;		//auth version
		pAuthBuf[1]=nUserLen;
		memcpy(pAuthBuf+2,nlu->settings.szProxyAuthUser,nUserLen);
		pAuthBuf[2+nUserLen]=nPassLen;
		memcpy(pAuthBuf+3+nUserLen,nlu->settings.szProxyAuthPassword,nPassLen);
		if(NLSend(nlc,(char*)pAuthBuf,3+nUserLen+nPassLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
			NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
			mir_free(pAuthBuf);
			return 0;
		}
		mir_free(pAuthBuf);

		if (!RecvUntilTimeout(nlc,(char*)buf,2,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
			NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
			return 0;
		}
		if(buf[1]) {
			SetLastError(ERROR_ACCESS_DENIED);
			NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
			return 0;
		}
	}

	{	
		PBYTE pInit;
		int nHostLen;
		DWORD hostIP;

		if(nlc->dnsThroughProxy) {
			if((hostIP=inet_addr(nloc->szHost))==INADDR_NONE)
				nHostLen=lstrlenA(nloc->szHost)+1;
			else nHostLen=4;
		}
		else {
			if((hostIP=DnsLookup(nlu,nloc->szHost))==0)
				return 0;
			nHostLen=4;
		}
		pInit=(PBYTE)mir_alloc(6+nHostLen);
		pInit[0]=5;   //SOCKS5
		pInit[1]= nloc->flags & NLOCF_UDP ? 3 : 1; //connect or UDP
		pInit[2]=0;   //reserved
		if(hostIP==INADDR_NONE) {		 //DNS lookup through proxy
			pInit[3]=3;
			pInit[4]=nHostLen-1;
			memcpy(pInit+5,nloc->szHost,nHostLen-1);
		}
		else {
			pInit[3]=1;
			*(PDWORD)(pInit+4)=hostIP;
		}
		*(PWORD)(pInit+4+nHostLen)=htons(nloc->wPort);
		if(NLSend(nlc,(char*)pInit,6+nHostLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
			NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
			mir_free(pInit);
			return 0;
		}
		mir_free(pInit);
	}

	if (!RecvUntilTimeout(nlc,(char*)buf,5,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
		NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
		return 0;
	}

	if ( buf[0]!=5 || buf[1] ) {
		const char* err = "Unknown response"; 
		if ( buf[0] != 5 )
			SetLastError(ERROR_BAD_FORMAT);
		else
		{
			switch(buf[1]) 
			{
			case 1: SetLastError(ERROR_GEN_FAILURE); err = "General failure"; break;
			case 2: SetLastError(ERROR_ACCESS_DENIED); err = "Connection not allowed by ruleset";  break;
			case 3: SetLastError(WSAENETUNREACH); err = "Network unreachable"; break;
			case 4: SetLastError(WSAEHOSTUNREACH); err = "Host unreachable"; break;
			case 5: SetLastError(WSAECONNREFUSED); err = "Connection refused by destination host"; break;
			case 6: SetLastError(WSAETIMEDOUT); err = "TTL expired"; break;
			case 7: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); err = "Command not supported / protocol error"; break;
			case 8: SetLastError(ERROR_INVALID_ADDRESS); err = "Address type not supported"; break;
			default: SetLastError(ERROR_INVALID_DATA); break;
			}
		}
		NetlibLogf(nlu,"%s %d: Proxy conection failed. %s.",__FILE__,__LINE__, err);
		return 0;
	}
	{
		int nRecvSize = 0;
		switch( buf[3] ) {
		case 1:// ipv4 addr
			nRecvSize = 5;
			break;
		case 3:// dns name addr
			nRecvSize = buf[4] + 2;
			break;
		case 4:// ipv6 addr
			nRecvSize = 17;
			break;
		default:
			NetlibLogf(nlu,"%s %d: %s() unknown address type (%u)",__FILE__,__LINE__,"NetlibInitSocks5Connection",(int)buf[3]);
			return 0;
		}
		if (!RecvUntilTimeout(nlc,(char*)buf,nRecvSize,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
			NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
			return 0;
		}	
	}

	//connected
	return 1;
}
Пример #24
0
int NetlibHttpGatewayRecv(NetlibConnection *nlc, char *buf, int len, int flags)
{
	bool peek = (flags & MSG_PEEK) != 0;

	if (nlc->dataBufferLen != 0 && (!peek || nlc->dataBufferLen >= len))
	{
		return HttpGatewayReadSetResult(nlc, buf, len, peek);
	}

	for (int retryCount = 0; retryCount < NETLIBHTTP_RETRYCOUNT;)
	{
		if (nlc->nlhpi.szHttpGetUrl == NULL && retryCount == 0)
		{
			if (nlc->pollingTimeout == 0) nlc->pollingTimeout = 30;

			/* We Need to sleep/wait for the data to send before we do receive */
			for (int pollCount = nlc->pollingTimeout; pollCount--;)
			{
				if (nlc->pHttpProxyPacketQueue != NULL && GetTickCount() - nlc->lastPost > 1000)
					break;

				if (nlc->termRequested || (SleepEx(1000, TRUE) && Miranda_Terminated()))
					return SOCKET_ERROR;
			}

			nlc->lastPost = GetTickCount();
			if (nlc->pHttpProxyPacketQueue == NULL && nlc->nlu->user.pfnHttpGatewayWrapSend != NULL)
			{
				if (nlc->nlu->user.pfnHttpGatewayWrapSend(nlc, (PBYTE)"", 0, MSG_NOHTTPGATEWAYWRAP, NetlibSend) == SOCKET_ERROR)
					return SOCKET_ERROR;
			}
		}

		int numPackets = 0;
		if (nlc->nlhpi.szHttpGetUrl)
		{
			if (!NetlibHttpGatewaySend(nlc, reqOldGet, NULL, 0))
			{
				if (GetLastError() == ERROR_ACCESS_DENIED || nlc->termRequested)
					break;

				++retryCount;
				continue;
			}
		}
		else
		{
			if (!NetlibHttpGatewayStdPost(nlc, numPackets))
			{
				if (GetLastError() == ERROR_ACCESS_DENIED || nlc->termRequested)
					break;

				++retryCount;
				continue;
			}
		}
		NETLIBHTTPREQUEST *nlhrReply = NetlibHttpRecv(nlc, flags | MSG_RAW | MSG_DUMPPROXY, MSG_RAW | MSG_DUMPPROXY);
		if (nlhrReply == NULL) return SOCKET_ERROR;

		if (nlc->nlu->user.pfnHttpGatewayUnwrapRecv && !(flags & MSG_NOHTTPGATEWAYWRAP))
		{
			nlhrReply->pData = (char*)nlc->nlu->user.pfnHttpGatewayUnwrapRecv(nlhrReply,
				(PBYTE)nlhrReply->pData, nlhrReply->dataLength, &nlhrReply->dataLength, mir_realloc);
		}

		if (nlhrReply->resultCode >= 300)
		{
			int resultCode = nlhrReply->resultCode;
			NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);

			if (nlc->nlhpi.szHttpGetUrl && resultCode != 404)
			{
				NetlibLogf(nlc->nlu, "Error received from proxy, retrying");
				continue;
			}
			else
			{
				NetlibLogf(nlc->nlu, "Error received from proxy, retry attempts exceeded (%u)", retryCount);
				SetLastError(ERROR_GEN_FAILURE);
				return SOCKET_ERROR;
			}
		}
		else
		{
			retryCount = 0;
			HttpGatewayRemovePacket(nlc, numPackets);
		}

		if (nlhrReply->dataLength)
		{
			if (peek)
			{
				int rbytes = nlc->dataBufferLen + nlhrReply->dataLength;

				nlc->dataBuffer = (PBYTE)mir_realloc(nlc->dataBuffer, rbytes);
				memcpy(nlc->dataBuffer + nlc->dataBufferLen, nlhrReply->pData, nlhrReply->dataLength);
				nlc->dataBufferLen = rbytes;

				NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);

				return HttpGatewayReadSetResult(nlc, buf, len, peek);
			}
			else
			{
				int bytes = min(len, nlhrReply->dataLength);
				int rbytes = nlhrReply->dataLength - bytes;

				memcpy(buf, nlhrReply->pData, bytes);

				nlc->dataBuffer = (PBYTE)mir_realloc(nlc->dataBuffer, rbytes);
				if (rbytes) memcpy(nlc->dataBuffer, nlhrReply->pData + bytes, rbytes);
				nlc->dataBufferLen = rbytes;

				NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
				return bytes;
			}
		}
		else
		{
			if ((peek && nlc->dataBufferLen != 0) || nlhrReply->pData)
			{
				NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
				return HttpGatewayReadSetResult(nlc, buf, len, peek);
			}
		}
		NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
	}

	SetLastError(ERROR_GEN_FAILURE);
	return SOCKET_ERROR;
}
Пример #25
0
bool NetlibDoConnect(NetlibConnection *nlc)
{
	NETLIBOPENCONNECTION *nloc = &nlc->nloc;
	NetlibUser *nlu = nlc->nlu;

	nlc->sinProxy.sin_family = AF_INET;
	mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;

	bool usingProxy = false, forceHttps = false;
	if (nlu->settings.useProxy)
	{
		if (nlu->settings.proxyType == PROXYTYPE_IE)
		{
			usingProxy = NetlibGetIeProxyConn(nlc, false);
		}
		else
		{
			if (nlu->settings.szProxyServer && nlu->settings.szProxyServer[0])
			{
				nlc->szProxyServer = mir_strdup(nlu->settings.szProxyServer);
				nlc->wProxyPort = nlu->settings.wProxyPort;
				nlc->proxyType = nlu->settings.proxyType;
				usingProxy = true;
			}
		}
	}

retry:
	if (usingProxy) 
	{
		NetlibLogf(nlu,"(%p) Resolving proxy %s:%d for %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort, nloc->szHost, nloc->wPort);
		nlc->sinProxy.sin_port = htons(nlc->wProxyPort);
		nlc->sinProxy.sin_addr.S_un.S_addr = DnsLookup(nlu, nlc->szProxyServer);
		if (nlc->sinProxy.sin_addr.S_un.S_addr == 0) 
		{
			usingProxy = false;
			nlc->proxyType = 0;
		}
	}
	if (!usingProxy)
	{
		NetlibLogf(nlu,"(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort);
		nlc->sinProxy.sin_port = htons(nloc->wPort);
		nlc->sinProxy.sin_addr.S_un.S_addr = DnsLookup(nlu, nloc->szHost);
	}
	else
		NetlibLogf(nlu,"(%p) Connecting to proxy %s:%d for %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort, nloc->szHost, nloc->wPort);

	if (nlc->sinProxy.sin_addr.S_un.S_addr == 0) return false;

	if (my_connect(nlc, nloc) == SOCKET_ERROR) 
	{
		if (usingProxy && (nlc->proxyType == PROXYTYPE_HTTPS || nlc->proxyType == PROXYTYPE_HTTP))
		{
			usingProxy = false;
			if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
			{
				NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
				return false;
			}
		}
		else
		{
			if (nlu->settings.useProxy && !usingProxy && nlu->settings.proxyType == PROXYTYPE_IE && !forceHttps)
			{
				forceHttps = true;
				usingProxy = NetlibGetIeProxyConn(nlc, true);
				if (usingProxy) goto retry;
			}
			NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
			return false;
		}
	}

	if (usingProxy && !((nloc->flags & (NLOCF_HTTP | NLOCF_SSL)) == NLOCF_HTTP && 
		(nlc->proxyType == PROXYTYPE_HTTP || nlc->proxyType == PROXYTYPE_HTTPS)))
	{
		if (!WaitUntilWritable(nlc->s, 30000)) return false;

		switch (nlc->proxyType) 
		{
		case PROXYTYPE_SOCKS4:
			if (!NetlibInitSocks4Connection(nlc, nlu, nloc)) return false;
			break;

		case PROXYTYPE_SOCKS5:
			if (!NetlibInitSocks5Connection(nlc, nlu, nloc)) return false;
			break;

		case PROXYTYPE_HTTPS:
			nlc->proxyAuthNeeded = true;
			if (!NetlibInitHttpsConnection(nlc, nlu, nloc))
			{
				usingProxy = false;
				if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
					return false;
			}
			break;

		case PROXYTYPE_HTTP:
			nlc->proxyAuthNeeded = true;
			if (!(nlu->user.flags & NUF_HTTPGATEWAY || nloc->flags & NLOCF_HTTPGATEWAY) || nloc->flags & NLOCF_SSL)
			{
				//NLOCF_HTTP not specified and no HTTP gateway available: try HTTPS
				if (!NetlibInitHttpsConnection(nlc, nlu, nloc))
				{
					//can't do HTTPS: try direct
					usingProxy = false;
					if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
						return false;
				}
			}
			else 
			{
				if (!NetlibInitHttpConnection(nlc, nlu, nloc)) return false;
			}
			break;

		default:
			SetLastError(ERROR_INVALID_PARAMETER);
			FreePartiallyInitedConnection(nlc);
			return false;
		}
	}
	else if (nloc->flags & NLOCF_HTTPGATEWAY)
	{
		if (!NetlibInitHttpConnection(nlc, nlu, nloc)) return false;
		nlc->usingDirectHttpGateway = true;
	}

	NetlibLogf(nlu,"(%d) Connected to %s:%d", nlc->s, nloc->szHost, nloc->wPort);

	if (NLOCF_SSL & nloc->flags)
	{
		return NetlibStartSsl((WPARAM)nlc, 0) != 0;
	}

	return true;
}
Пример #26
0
static bool my_connectIPv6(NetlibConnection *nlc, NETLIBOPENCONNECTION * nloc)
{
	int rc = SOCKET_ERROR, retrycnt = 0;
	u_long notblocking = 1;
	DWORD lasterr = 0;
	static const TIMEVAL tv = { 1, 0 };

	unsigned int dwTimeout = (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2) ? nloc->timeout : 0;
	// if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
	if (dwTimeout == 0) dwTimeout = 30;

	// this is for XP SP2 where there is a default connection attempt limit of 10/second
	if (connectionTimeout) {
		WaitForSingleObject(hConnectionOpenMutex, 10000);
		int waitdiff = GetTickCount() - g_LastConnectionTick;
		if (waitdiff < connectionTimeout) SleepEx(connectionTimeout, TRUE);
		g_LastConnectionTick = GetTickCount();
		ReleaseMutex(hConnectionOpenMutex);

		// might of died in between the wait
		if (Miranda_Terminated()) return false;
	}

	char szPort[6];
	addrinfo *air = NULL, *ai, hints = {0};

	hints.ai_family = AF_UNSPEC;

	if (nloc->flags & NLOCF_UDP) {
		hints.ai_socktype = SOCK_DGRAM;
		hints.ai_protocol = IPPROTO_UDP;
	}
	else {
		hints.ai_socktype = SOCK_STREAM;
		hints.ai_protocol = IPPROTO_TCP;
	}

	if (nlc->proxyType) {
		if (!nlc->szProxyServer)
			return false;

		if (nloc)
			NetlibLogf(nlc->nlu, "(%p) Connecting to proxy %s:%d for %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort, nloc->szHost, nloc->wPort);
		else
			NetlibLogf(nlc->nlu, "(%p) Connecting to proxy %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort);

		_itoa(nlc->wProxyPort, szPort, 10);
		if (GetAddrInfoA(nlc->szProxyServer, szPort, &hints, &air)) {
			NetlibLogf(nlc->nlu, "%s %d: %s() for host %s failed (%u)", __FILE__, __LINE__, "getaddrinfo", nlc->szProxyServer, WSAGetLastError());
			return false;
		}
	}
	else {
		if (!nloc || !nloc->szHost)
			return false;

		NetlibLogf(nlc->nlu, "(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort);

		_itoa(nlc->nloc.wPort, szPort, 10);

		if (GetAddrInfoA(nlc->nloc.szHost, szPort, &hints, &air)) {
			NetlibLogf(nlc->nlu, "%s %d: %s() for host %s failed (%u)", __FILE__, __LINE__, "getaddrinfo", nlc->nloc.szHost, WSAGetLastError());
			return false;
		}
	}

	for (ai = air; ai && !Miranda_Terminated(); ai = ai->ai_next) {
		NetlibLogf(nlc->nlu, "(%p) Connecting to ip %s ....", nlc, ptrA( NetlibAddressToString((SOCKADDR_INET_M*)ai->ai_addr)));
retry:
		nlc->s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (nlc->s == INVALID_SOCKET)
			return false;

		// return the socket to non blocking
		if (ioctlsocket(nlc->s, FIONBIO, &notblocking) != 0)
			return false;

		if (nlc->nlu->settings.specifyOutgoingPorts && nlc->nlu->settings.szOutgoingPorts  && nlc->nlu->settings.szOutgoingPorts[0]) {
			SOCKET s = ai->ai_family == AF_INET ? nlc->s : INVALID_SOCKET;
			SOCKET s6 = ai->ai_family == AF_INET6 ? nlc->s : INVALID_SOCKET;
			if (!BindSocketToPort(nlc->nlu->settings.szOutgoingPorts, s, s6, &nlc->nlu->inportnum))
				NetlibLogf(nlc->nlu, "Netlib connect: Not enough ports for outgoing connections specified");
		}

		// try a connect
		if (connect(nlc->s, ai->ai_addr, (int)ai->ai_addrlen) == 0) {
			rc = 0;
			break;
		}

		// didn't work, was it cos of nonblocking?
		if (WSAGetLastError() != WSAEWOULDBLOCK) {
			rc = SOCKET_ERROR;
			closesocket(nlc->s);
			nlc->s = INVALID_SOCKET;
			continue;
		}

		while (true) { // timeout loop
			fd_set r, w, e;
			FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
			FD_SET(nlc->s, &r);
			FD_SET(nlc->s, &w);
			FD_SET(nlc->s, &e);
			if ((rc = select(0, &r, &w, &e, &tv)) == SOCKET_ERROR)
				break;

			if (rc > 0) {
				if (FD_ISSET(nlc->s, &w)){
					// connection was successful
					rc = 0;
					lasterr = 0;
				}
				if (FD_ISSET(nlc->s, &r)) {
					// connection was closed
					rc = SOCKET_ERROR;
					lasterr = WSAECONNRESET;
				}
				if (FD_ISSET(nlc->s, &e)) {
					// connection failed.
					int len = sizeof(lasterr);
					rc = SOCKET_ERROR;
					getsockopt(nlc->s, SOL_SOCKET, SO_ERROR, (char*)&lasterr, &len);
					if (lasterr == WSAEADDRINUSE && ++retrycnt <= 2)
					{
						closesocket(nlc->s);
						nlc->s = INVALID_SOCKET;
						goto retry;
					}
				}
				break;
			}
			else if (Miranda_Terminated()) {
				rc = SOCKET_ERROR;
				lasterr = ERROR_TIMEOUT;
				break;
			}
			else if (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2 && nloc->waitcallback != NULL && nloc->waitcallback(&dwTimeout) == 0) {
				rc = SOCKET_ERROR;
				lasterr = ERROR_TIMEOUT;
				break;
			}
			if (--dwTimeout == 0) {
				rc = SOCKET_ERROR;
				lasterr = ERROR_TIMEOUT;
				break;
			}
		}

		if (rc == 0) break;

		closesocket(nlc->s);
		nlc->s = INVALID_SOCKET;
	}

	FreeAddrInfoA(air);

	notblocking = 0;
	if (nlc->s != INVALID_SOCKET) ioctlsocket(nlc->s, FIONBIO, &notblocking);
	if (rc && lasterr) SetLastError(lasterr);
	return rc == 0;
}
Пример #27
0
static int my_connect(NetlibConnection *nlc, NETLIBOPENCONNECTION * nloc)
{
	int rc = 0, retrycnt = 0;
	u_long notblocking = 1;	
	DWORD lasterr = 0;	
	static const TIMEVAL tv = { 1, 0 };

	unsigned int dwTimeout = (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2) ? nloc->timeout : 0;
	// if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
	if (dwTimeout == 0) dwTimeout = 30;

	// this is for XP SP2 where there is a default connection attempt limit of 10/second
	if (connectionTimeout)
	{
		WaitForSingleObject(hConnectionOpenMutex, 10000);
		int waitdiff = GetTickCount() - g_LastConnectionTick;
		if (waitdiff < connectionTimeout) SleepEx(connectionTimeout, TRUE);
		g_LastConnectionTick = GetTickCount();
		ReleaseMutex(hConnectionOpenMutex);

		// might of died in between the wait
		if (Miranda_Terminated()) return SOCKET_ERROR;
	}

retry:
	nlc->s = socket(AF_INET,nloc->flags & NLOCF_UDP ? SOCK_DGRAM : SOCK_STREAM, 0);
	if (nlc->s == INVALID_SOCKET) return SOCKET_ERROR;

	// return the socket to non blocking
	if (ioctlsocket(nlc->s, FIONBIO, &notblocking) != 0) return SOCKET_ERROR;

	if (nlc->nlu->settings.specifyOutgoingPorts && nlc->nlu->settings.szOutgoingPorts  && nlc->nlu->settings.szOutgoingPorts[0]) 
	{
		if (!BindSocketToPort(nlc->nlu->settings.szOutgoingPorts, nlc->s, &nlc->nlu->inportnum))
			NetlibLogf(nlc->nlu,"Netlib connect: Not enough ports for outgoing connections specified");
	} 

	// try a connect
	if (connect(nlc->s, (LPSOCKADDR)&nlc->sinProxy, sizeof(nlc->sinProxy)) == 0) 
	{
		goto unblock;
	}

	// didn't work, was it cos of nonblocking?
	if (WSAGetLastError() != WSAEWOULDBLOCK) 
	{
		rc = SOCKET_ERROR;
		goto unblock;
	}

	for (;;) 
	{		
		fd_set r, w, e;
		FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
		FD_SET(nlc->s, &r);
		FD_SET(nlc->s, &w);
		FD_SET(nlc->s, &e);		
		if ((rc = select(0, &r, &w, &e, &tv)) == SOCKET_ERROR) 
			break;

		if (rc > 0) 
		{			
			if (FD_ISSET(nlc->s, &w))
			{
				// connection was successful
				rc = 0;
			}
			if (FD_ISSET(nlc->s, &r)) 
			{
				// connection was closed
				rc = SOCKET_ERROR;
				lasterr = WSAECONNRESET;
			}
			if (FD_ISSET(nlc->s, &e)) 
			{
				// connection failed.
				int len = sizeof(lasterr);
				rc = SOCKET_ERROR;
				getsockopt(nlc->s, SOL_SOCKET, SO_ERROR, (char*)&lasterr, &len);
				if (lasterr == WSAEADDRINUSE && ++retrycnt <= 2) 
				{
					closesocket(nlc->s);
					goto retry;
				}
			}
			break;
		} 
		else if (Miranda_Terminated()) 
		{
			rc = SOCKET_ERROR;
			lasterr = ERROR_TIMEOUT;
			break;
		} 
		else if (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2 && 
			nloc->waitcallback != NULL && nloc->waitcallback(&dwTimeout) == 0)
		{
			rc = SOCKET_ERROR;
			lasterr = ERROR_TIMEOUT;
			break;
		}
		if (--dwTimeout == 0) 
		{
			rc = SOCKET_ERROR;
			lasterr = ERROR_TIMEOUT;
			break;
		}
	}

unblock:	
	notblocking = 0;
	ioctlsocket(nlc->s, FIONBIO, &notblocking);
	if (lasterr) SetLastError(lasterr);
	return rc;
}
Пример #28
0
bool NetlibDoConnect(NetlibConnection *nlc)
{
	NETLIBOPENCONNECTION *nloc = &nlc->nloc;
	NetlibUser *nlu = nlc->nlu;

	mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;

	bool usingProxy = false, forceHttps = false;
	if (nlu->settings.useProxy) {
		if (nlu->settings.proxyType == PROXYTYPE_IE)
			usingProxy = NetlibGetIeProxyConn(nlc, false);
		else {
			if (nlu->settings.szProxyServer && nlu->settings.szProxyServer[0]) {
				nlc->szProxyServer = mir_strdup(nlu->settings.szProxyServer);
				nlc->wProxyPort = nlu->settings.wProxyPort;
				nlc->proxyType = nlu->settings.proxyType;
				usingProxy = true;
			}
		}
	}

	while (!my_connect(nlc, nloc)) {
		// Fallback to direct only when using HTTP proxy, as this is what used by companies
		// If other type of proxy used it's an indication of security nutcase, leave him alone
		if (usingProxy && (nlc->proxyType == PROXYTYPE_HTTPS || nlc->proxyType == PROXYTYPE_HTTP)) {
			usingProxy = false;
			nlc->proxyType = 0;
			NetlibLogf(nlu,"Fallback to direct connection");
			continue;
		}
		if (nlu->settings.useProxy && !usingProxy && nlu->settings.proxyType == PROXYTYPE_IE && !forceHttps) {
			forceHttps = true;
			usingProxy = NetlibGetIeProxyConn(nlc, true);
			if (usingProxy) continue;
		}
		NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
		return false;
	}

	if (usingProxy && !((nloc->flags & (NLOCF_HTTP | NLOCF_SSL)) == NLOCF_HTTP && (nlc->proxyType == PROXYTYPE_HTTP || nlc->proxyType == PROXYTYPE_HTTPS))) {
		if (!WaitUntilWritable(nlc->s, 30000))
			return false;

		switch (nlc->proxyType) {
		case PROXYTYPE_SOCKS4:
			if (!NetlibInitSocks4Connection(nlc, nlu, nloc))
				return false;
			break;

		case PROXYTYPE_SOCKS5:
			if (!NetlibInitSocks5Connection(nlc, nlu, nloc))
				return false;
			break;

		case PROXYTYPE_HTTPS:
			nlc->proxyAuthNeeded = true;
			if (!NetlibInitHttpsConnection(nlc, nlu, nloc)) {
				usingProxy = false;
				if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
					return false;
			}
			break;

		case PROXYTYPE_HTTP:
			nlc->proxyAuthNeeded = true;
			if (!(nlu->user.flags & NUF_HTTPGATEWAY || nloc->flags & NLOCF_HTTPGATEWAY) || nloc->flags & NLOCF_SSL) {
				//NLOCF_HTTP not specified and no HTTP gateway available: try HTTPS
				if (!NetlibInitHttpsConnection(nlc, nlu, nloc)) {
					//can't do HTTPS: try direct
					usingProxy = false;
					if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
						return false;
				}
			}
			else if (!NetlibInitHttpConnection(nlc, nlu, nloc))
				return false;

			break;

		default:
			SetLastError(ERROR_INVALID_PARAMETER);
			FreePartiallyInitedConnection(nlc);
			return false;
		}
	}
	else if (nloc->flags & NLOCF_HTTPGATEWAY) {
		if (!NetlibInitHttpConnection(nlc, nlu, nloc)) return false;
		nlc->usingDirectHttpGateway = true;
	}

	NetlibLogf(nlu, "(%d) Connected to %s:%d", nlc->s, nloc->szHost, nloc->wPort);

	if (NLOCF_SSL & nloc->flags)
		return NetlibStartSsl((WPARAM)nlc, 0) != 0;

	return true;
}