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; }
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; }
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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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; }
//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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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, ¬blocking) != 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, ¬blocking); if (rc && lasterr) SetLastError(lasterr); return rc == 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; }
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; }
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; }
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, ¬blocking) != 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, ¬blocking); if (rc && lasterr) SetLastError(lasterr); return rc == 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, ¬blocking) != 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, ¬blocking); if (lasterr) SetLastError(lasterr); return rc; }
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; }