Пример #1
0
BOOL CHTTPClient::SendSSLRequest(char *szHost,
    char *szHostName,
    char *szPath,
    char *szUserID,
    char *szPassword,
    long lPort,
    char *szProxy,
    long lProxyPort,
    char *szProxyUser,
    char *szProxyPswd,
    char *szUserAgent,
    char *szPost,
    long dwTimeout,
    SSL **pssl,
    SSL_CTX **pssl_ctx,
    char *szTransaction)
{
    char *szConnectHost;
    char *szConnectionHeader = "Connection: close\r\n";
    char *szContentLength = "Content-Length: %d\r\n";
    char *szContentType = "Content-Type: application/x-www-form-urlencoded\r\n";
    char *szProxyConn = "Proxy-Connection: Keep-Alive\r\n";
    char *szPragma = "Pragma: no-cache\r\n";
    long lConnectPort;
    char *szBuffer = szSendBuffer;
    char szWork[256];
    char *lpWork;
    char *szGetMethod = "GET";
    char *szPostMethod = "POST";
    char *szMethod;
    BOOL RC = TRUE;
    BOOL bBIOset = FALSE;

    Base64Coder cBase64Coder;

    BIO *bio = 0;
    int done = 0, i, n;
    char buf[2048];

    // Got to have a host
    if (!szHost)
        return(FALSE);

    // Initialize strings used for cookies
    cDomain = szHostName;
    cPath = szPath;
    if (szTransaction)
        cTransaction = szTransaction;
    else
        cTransaction = "";

    // Clean up ssl storage
    try
    {
        if (ssl)
        {
            SSL_free(ssl);
            ssl = 0;
        }
    }
    catch(...)
    {
        ssl = 0;
    }

    try
    {

        // Initialise the ssl library now in rtm startup 

        // Create the context structure. Operate in the normal default SSLv3
        // in a SSLv2 header mode to maximize the number of servers
        // we can connect to.
        if (!ssl_ctx)
        {
            if (!pssl_ctx || !*pssl_ctx)
            {
                if ((ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
                {
                    bConnectFailed = TRUE;
                    throw FALSE;
                }
            }
            else
                ssl_ctx = *pssl_ctx;
        }

        // Reset variables for response
        bHeader = FALSE;
        bReadComplete = FALSE;
        bHeadRequest = FALSE;
        lReceivedLength = 0;
        lContentLength = 0;
        cHeader = "";
        cContent = "";

        // turn on all vendor bug compatibility options
        SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);

        // Create the SSL structure - defaults are inherited from the SSL_CTX
        if ((ssl = SSL_new(ssl_ctx)) == NULL)
        {
            bConnectFailed = TRUE;
            throw FALSE;
        };

        // Set as client side
        SSL_set_connect_state(ssl);

        if (!szProxy)
        {
            // No proxy
            szConnectHost = szHost;
            lConnectPort = lPort;
        }
        else
        {
            // Proxy
            szConnectHost = szProxy;
            lConnectPort = lProxyPort;
        };

        sprintf(szWork, "%s:%u", szConnectHost, (unsigned int) lConnectPort);

        // Create a BIO to handle the connect and SSL handling
        if ((bio = BIO_new_connect(szWork)) == NULL)
        {
            bConnectFailed = TRUE;
            throw FALSE;
        };

        // If using proxy then have to tunnel through to the actual ssl server
        if (szProxy)
        {
            sprintf(szBuffer, "CONNECT %s:%u HTTP/1.0\r\nUser-Agent: %s\r\n", szHostName, (unsigned int) lPort, szUserAgent);

            if (szProxyUser && szProxyPswd && strlen(szProxyUser) > 0 && strlen(szProxyPswd) > 0)
            {
                sprintf(szWork, "%s:%s", szProxyUser, szProxyPswd);
                cBase64Coder.Encode(szWork);
                sprintf(szWork, "Proxy-Authorization: Basic %s\r\n", (LPCTSTR) cBase64Coder.EncodedMessage());
                strcat(szBuffer, szWork);
            }
            strcat(szBuffer, szProxyConn);
            strcat(szBuffer, szPragma);
            strcat(szBuffer, "\r\n");

            // Send connect request
            n = strlen(szBuffer);
            i = 0;
            do
            {
                i = BIO_write(bio, &(szBuffer[i]), n);
                if (i <= 0)
                {
                    bConnectFailed = TRUE;
                    BIO_free(bio);
                    throw FALSE;
                }
                n -= i;
            }
            while(n > 0);

            // Read response from proxy
            i = BIO_read(bio, buf, sizeof(buf));
            if (i <= 0)
            {
                bConnectFailed = TRUE;
                BIO_free(bio);
                throw FALSE;
            };

            buf[i] = '\0';
            lpWork = strstr(buf, "200");
            if (!lpWork)
            {
                bConnectFailed = TRUE;
                BIO_free(bio);
                throw FALSE;
            };

        };

        // Use the newly created connect BIO
        SSL_set_bio(ssl, bio, bio);
        bBIOset = TRUE;
        if (pSession && pssl)
        {
            SSL_set_session(ssl, pSession);
        }
        else
        {
            while(!done)
            {
                int i;
                struct tm *ptr;
                time_t lt;

                lt = time(NULL);

                PROTECT_CALL
                ptr = localtime(&lt);
                char *pszTime = asctime(ptr);
                RAND_seed((unsigned char *) pszTime, strlen(pszTime));
                UNPROTECT_CALL

                // The all important handshake
                i = SSL_do_handshake(ssl);

                switch(SSL_get_error(ssl, i))
                {
                    case SSL_ERROR_NONE: // Handshake has finished, so proceed
                        done = 1;
                        break;
                    case SSL_ERROR_WANT_READ:
                    case SSL_ERROR_WANT_WRITE:
                    case SSL_ERROR_WANT_CONNECT:
                        // Perform the handshake again. 
                        sleep(1);
                        break;
                    default:
                        bConnectFailed = TRUE;
                        throw FALSE;
                        break;
                };
            };
            pSession = SSL_get_session(ssl);
        };

        if (szPost)
            szMethod = szPostMethod;
        else
            szMethod = szGetMethod;

        // Build the request
        sprintf(szBuffer, "%s %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\n", szMethod, szPath, szUserAgent, szHostName);

        if (szUserID)
        {
            sprintf(szWork, "%s:%s", szUserID, szPassword);
            cBase64Coder.Encode(szWork);
            sprintf(szWork, "Authorization: Basic %s\r\n", (LPCTSTR) cBase64Coder.EncodedMessage());
            strcat(szBuffer, szWork);
        }

        if (szPost)
        {
            strcat(szBuffer, szContentType);
            sprintf(szWork, szContentLength, strlen(szPost));
            strcat(szBuffer, szWork);
            strcat(szBuffer, szProxyConn);
            strcat(szBuffer, szPragma);
        }
        else
        {
            strcat(szBuffer, szConnectionHeader);
        }

        if (!cTransaction.empty())
            SendCookie(szBuffer);

        // Indicate end of header
        strcat(szBuffer, "\r\n");

        sDebugSendHeader = szBuffer;

        if (szPost)
            strcat(szBuffer, szPost);

        dwStartTime = ::XPlatGetMilliseconds();

        // Send request
        n = strlen(szBuffer);
        i = 0;
        do
        {
            i = SSL_write(ssl, &(szBuffer[i]), n);
            if (i <= 0)
            {
                bConnectFailed = FALSE;
                throw FALSE;
            }
            n -= i;
        }
        while(n > 0);

        // Read from the other side of the protocol
        while(1)
        {
            i = SSL_read(ssl, buf, sizeof(buf));
            if (i <= 0)
                break;

            ProcessData((unsigned char *) buf, i);

            if (!GetTimeLeft(dwTimeout, dwStartTime))
            {
                // Timed out
                bConnectFailed = FALSE;
                throw FALSE;
            };
        };
        if (szPost && !strcmp(szStatus, "100"))
        {
            printf("status 100");
            strcat(szBuffer, szPost);
            // Reset variables for response
            bHeader = FALSE;
            bReadComplete = FALSE;
            bHeadRequest = FALSE;
            lReceivedLength = 0;
            lContentLength = 0;
            cHeader = "";
            cContent = "";


            // Send request
            n = strlen(szBuffer);
            i = 0;
            do
            {
                i = SSL_write(ssl, &(szBuffer[i]), n);
                if (i <= 0)
                {
                    bConnectFailed = FALSE;
                    throw FALSE;
                }
                n -= i;
            }
            while(n > 0);

            // Read from the other side of the protocol
            while(1)
            {
                i = SSL_read(ssl, buf, sizeof(buf));
                if (i <= 0)
                    break;

                ProcessData((unsigned char *) buf, i);

                if (!GetTimeLeft(dwTimeout, dwStartTime))
                {
                    // Timed out
                    bConnectFailed = FALSE;
                    throw FALSE;
                };
            };
        };
        Disconnected();
        throw TRUE;
    }

    catch(BOOL rc)
    {
        RC = rc;

    }

    catch(...)
    {
        RC = FALSE;
        if (!bBIOset && bio)
        {
            try
            {
                BIO_free(bio);
            }
            catch(...)
            {
            }
        }
    }

    if (pssl && pssl_ctx)
    {
        if (*pssl == 0)
        {
            *pssl = ssl;
            *pssl_ctx = ssl_ctx;
            ssl = 0;
        }
        ssl_ctx = 0;
    }

    return RC;

};
Пример #2
0
CWebSock::EPageReqResult CWebSock::OnPageRequestInternal(const CString& sURI, CString& sPageRet) {
	if (CZNC::Get().GetProtectWebSessions() && GetSession()->GetIP() != GetRemoteIP()) {
		DEBUG("Expected IP: " << GetSession()->GetIP());
		DEBUG("Remote IP:   " << GetRemoteIP());
		PrintErrorPage(403, "Access denied", "This session does not belong to your IP.");
		return PAGE_DONE;
	}

	// Check that they really POSTed from one our forms by checking if they
	// know the "secret" CSRF check value. Don't do this for login since
	// CSRF against the login form makes no sense and the login form does a
	// cookies-enabled check which would break otherwise.
	if (IsPost() && GetParam("_CSRF_Check") != GetCSRFCheck() && sURI != "/login") {
		DEBUG("Expected _CSRF_Check: " << GetCSRFCheck());
		DEBUG("Actual _CSRF_Check:   " << GetParam("_CSRF_Check"));
		PrintErrorPage(403, "Access denied", "POST requests need to send "
				"a secret token to prevent cross-site request forgery attacks.");
		return PAGE_DONE;
	}

	SendCookie("SessionId", GetSession()->GetId());

	if (GetSession()->IsLoggedIn()) {
		m_sUser = GetSession()->GetUser()->GetUserName();
		m_bLoggedIn = true;
	}

	// Handle the static pages that don't require a login
	if (sURI == "/") {
		if(!m_bLoggedIn && GetParam("cookie_check", false).ToBool() && GetRequestCookie("SessionId").empty()) {
			GetSession()->AddError("Your browser does not have cookies enabled for this site!");
		}
		return PrintTemplate("index", sPageRet);
	} else if (sURI == "/favicon.ico") {
		return PrintStaticFile("/pub/favicon.ico", sPageRet);
	} else if (sURI == "/robots.txt") {
		return PrintStaticFile("/pub/robots.txt", sPageRet);
	} else if (sURI == "/logout") {
		GetSession()->SetUser(NULL);
		SetLoggedIn(false);
		Redirect("/");

		// We already sent a reply
		return PAGE_DONE;
	} else if (sURI == "/login") {
		if (GetParam("submitted").ToBool()) {
			m_sUser = GetParam("user");
			m_sPass = GetParam("pass");
			m_bLoggedIn = OnLogin(m_sUser, m_sPass);

			// AcceptedLogin()/RefusedLogin() will call Redirect()
			return PAGE_DEFERRED;
		}

		Redirect("/"); // the login form is here
		return PAGE_DONE;
	} else if (sURI.Left(5) == "/pub/") {
		return PrintStaticFile(sURI, sPageRet);
	} else if (sURI.Left(11) == "/skinfiles/") {
		CString sSkinName = sURI.substr(11);
		CString::size_type uPathStart = sSkinName.find("/");
		if (uPathStart != CString::npos) {
			CString sFilePath = sSkinName.substr(uPathStart + 1);
			sSkinName.erase(uPathStart);

			m_Template.ClearPaths();
			m_Template.AppendPath(GetSkinPath(sSkinName) + "pub");

			if (PrintFile(m_Template.ExpandFile(sFilePath))) {
				return PAGE_DONE;
			} else {
				return PAGE_NOTFOUND;
			}
		}
		return PAGE_NOTFOUND;
	} else if (sURI.Left(6) == "/mods/" || sURI.Left(10) == "/modfiles/") {
		ParsePath();
		// Make sure modules are treated as directories
		if (sURI.Right(1) != "/" && sURI.find(".") == CString::npos && sURI.TrimLeft_n("/mods/").TrimLeft_n("/").find("/") == CString::npos) {
			Redirect(sURI + "/");
			return PAGE_DONE;
		}

		CModule *pModule = CZNC::Get().GetModules().FindModule(m_sModName);
		if (!pModule) {
			// Check if GetSession()->GetUser() is NULL and display
			// an error in that case
			if (!ForceLogin())
				return PAGE_DONE;

			pModule = GetSession()->GetUser()->GetModules().FindModule(m_sModName);
		}

		if (!pModule) {
			return PAGE_NOTFOUND;
		} else if (pModule->WebRequiresLogin() && !ForceLogin()) {
			return PAGE_PRINT;
		} else if (pModule->WebRequiresAdmin() && !GetSession()->IsAdmin()) {
			PrintErrorPage(403, "Forbidden", "You need to be an admin to access this module");
			return PAGE_DONE;
		} else if (!pModule->IsGlobal() && pModule->GetUser() != GetSession()->GetUser()) {
			PrintErrorPage(403, "Forbidden", "You must login as " + pModule->GetUser()->GetUserName() + " in order to view this page");
			return PAGE_DONE;
		} else if (pModule->OnWebPreRequest(*this, m_sPage)) {
			return PAGE_DEFERRED;
		}

		VWebSubPages& vSubPages = pModule->GetSubPages();

		for (unsigned int a = 0; a < vSubPages.size(); a++) {
			TWebSubPage& SubPage = vSubPages[a];

			bool bActive = (m_sModName == pModule->GetModName() && m_sPage == SubPage->GetName());

			if (bActive && SubPage->RequiresAdmin() && !GetSession()->IsAdmin()) {
				PrintErrorPage(403, "Forbidden", "You need to be an admin to access this page");
				return PAGE_DONE;
			}
		}

		if (pModule && !pModule->IsGlobal() && (!IsLoggedIn() || pModule->GetUser() != GetSession()->GetUser())) {
			AddModLoop("UserModLoop", *pModule);
		}

		if (sURI.Left(10) == "/modfiles/") {
			m_Template.AppendPath(GetSkinPath(GetSkinName()) + "/mods/" + m_sModName + "/files/");
			m_Template.AppendPath(pModule->GetModDataDir() + "/files/");

			if (PrintFile(m_Template.ExpandFile(m_sPage.TrimLeft_n("/")))) {
				return PAGE_PRINT;
			} else {
				return PAGE_NOTFOUND;
			}
		} else {
			SetPaths(pModule, true);

			/* if a module returns false from OnWebRequest, it does not
			   want the template to be printed, usually because it did a redirect. */
			if (pModule->OnWebRequest(*this, m_sPage, m_Template)) {
				// If they already sent a reply, let's assume
				// they did what they wanted to do.
				if (SentHeader()) {
					return PAGE_DONE;
				}
				return PrintTemplate(m_sPage, sPageRet, pModule);
			}

			if (!SentHeader()) {
				PrintErrorPage(404, "Not Implemented", "The requested module does not acknowledge web requests");
			}
			return PAGE_DONE;
		}
	} else {
		CString sPage(sURI.Trim_n("/"));
		if (sPage.length() < 32) {
			for (unsigned int a = 0; a < sPage.length(); a++) {
				unsigned char c = sPage[a];

				if ((c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_') {
					return PAGE_NOTFOUND;
				}
			}

			return PrintTemplate(sPage, sPageRet);
		}
	}

	return PAGE_NOTFOUND;
}
Пример #3
0
BOOL CHTTPClient::SendRequest(const char *szHost,
    const char *szHostName,
    const char *szPath,
    const char *szUserID,
    const char *szPassword,
    long lPort,
    const char *szProxy,
    long lProxyPort,
    const char *szProxyUser,
    const char *szProxyPswd,
    const char *szUserAgent,
    const char *szPost,
    long dwTimeout,
    const char *szTransaction)

{
    char *szConnectHost;
    const char *szConnectionHeader = "Connection: close\r\n";
    const char *szContentLength = "Content-Length: %d\r\n";
    const char *szContentType = "Content-Type: application/x-www-form-urlencoded\r\n";
    const char *szProxyConn = "Proxy-Connection: Keep-Alive\r\n";
    const char *szPragma = "Pragma: no-cache\r\n";
    long lConnectPort;
    char *szBuffer = szSendBuffer;
    char szWork[256];
    const char *szGetMethod = "GET";
    const char *szPostMethod = "POST";
    char *szMethod;
    Base64Coder cBase64Coder;


    // Got to have a host
    if (!szHost)
        return(FALSE);

    // Initialize strings used for cookies
    cDomain = szHostName;
    cPath = szPath;
    if (szTransaction)
        cTransaction = szTransaction;
    else
        cTransaction = "";

    if (szPost)
        szMethod = (char *) szPostMethod;
    else
        szMethod = (char *) szGetMethod;

    if (!szProxy)
    {
        // Build request, no proxy
        szConnectHost = (char *) szHost;
        lConnectPort = lPort;

        sprintf(szBuffer, "%s %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\n", szMethod, szPath, szUserAgent, szHostName);

    }
    else
    {
        // Build request for proxy
        szConnectHost = (char *) szProxy;
        lConnectPort = lProxyPort;
        sprintf(szBuffer, "%s http://%s%s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\n", szMethod, szHostName, szPath, szUserAgent, szHostName);

        if (szProxyUser && szProxyPswd && strlen(szProxyUser) > 0 && strlen(szProxyPswd) > 0)
        {
            sprintf(szWork, "%s:%s", szProxyUser, szProxyPswd);
            cBase64Coder.Encode(szWork);
            sprintf(szWork, "Proxy-Authorization: Basic %s\r\n", (LPCTSTR) cBase64Coder.EncodedMessage());
            strcat(szBuffer, szWork);
        }
    };


    if (szUserID)
    {
        sprintf(szWork, "%s:%s", szUserID, szPassword);
        cBase64Coder.Encode(szWork);
        sprintf(szWork, "Authorization: Basic %s\r\n", (LPCTSTR) cBase64Coder.EncodedMessage());
        strcat(szBuffer, szWork);
    }

    if (szPost)
    {
        strcat(szBuffer, szContentType);
        sprintf(szWork, szContentLength, strlen(szPost));
        strcat(szBuffer, szWork);
        strcat(szBuffer, szProxyConn);
        strcat(szBuffer, szPragma);
    }
    else
    {
        strcat(szBuffer, szConnectionHeader);
    }

    if (!cTransaction.empty())
        SendCookie(szBuffer);

    // Indicate end of header
    strcat(szBuffer, "\r\n");

    sDebugSendHeader = szBuffer;

    if (szPost)
        strcat(szBuffer, szPost);

    // Attempt to connect to server
    bConnectFailed = FALSE;
    if (!ConnectToServer(szConnectHost, lConnectPort, dwTimeout))
    {
        bConnectFailed = TRUE;
        return(FALSE);
    }

    // Reset variables for response
    bHeader = FALSE;
    bReadComplete = FALSE;
    bHeadRequest = FALSE;
    lReceivedLength = 0;
    lContentLength = 0;
    cHeader = "";
    cContent = "";

    dwStartTime = ::XPlatGetMilliseconds();

    // Send request
    if (!SendDataOut(szBuffer, strlen(szBuffer), strlen(szBuffer)))
    {
        TerminateConnection();
        return(FALSE);
    };

    // Wait for a reply
    if (cRecvEvent.Lock(dwTimeout) == XPLAT_TIMEOUT)
    {
        TerminateConnection();
        return(FALSE);
    };

    // Done with connection
    TerminateConnection();

    return(TRUE);
};