Example #1
0
static int _apply_userpass_credential(HINTERNET request, DWORD target, DWORD scheme, git_cred *cred)
{
	git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
	wchar_t *user, *pass;
	int user_len = 0, pass_len = 0, error = 0;

	if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0)
		goto done;

	if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0)
		goto done;

	if (!WinHttpSetCredentials(request, target, scheme, user, pass, NULL)) {
		giterr_set(GITERR_OS, "failed to set credentials");
		error = -1;
	}

done:
	if (user_len > 0)
		git__memzero(user, user_len * sizeof(wchar_t));

	if (pass_len > 0)
		git__memzero(pass, pass_len * sizeof(wchar_t));

	git__free(user);
	git__free(pass);

	return error;
}
Example #2
0
static int winhttp_connect(
    winhttp_subtransport *t,
    const char *url)
{
    wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
    wchar_t *wide_host;
    int32_t port;
    const char *default_port = "80";
    int error = -1;
    int default_timeout = TIMEOUT_INFINITE;
    int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;

    /* Prepare port */
    if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
        return -1;

    /* Prepare host */
    if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
        giterr_set(GITERR_OS, "Unable to convert host to wide characters");
        return -1;
    }

    /* Establish session */
    t->session = WinHttpOpen(
                     ua,
                     WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                     WINHTTP_NO_PROXY_NAME,
                     WINHTTP_NO_PROXY_BYPASS,
                     0);

    if (!t->session) {
        giterr_set(GITERR_OS, "Failed to init WinHTTP");
        goto on_error;
    }

    if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
        giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP");
        goto on_error;
    }


    /* Establish connection */
    t->connection = WinHttpConnect(
                        t->session,
                        wide_host,
                        (INTERNET_PORT) port,
                        0);

    if (!t->connection) {
        giterr_set(GITERR_OS, "Failed to connect to host");
        goto on_error;
    }

    error = 0;

on_error:
    git__free(wide_host);

    return error;
}
Example #3
0
int cl_setenv(const char *name, const char *value)
{
	wchar_t *wide_name, *wide_value;

	cl_assert(git__utf8_to_16_alloc(&wide_name, name) >= 0);

	if (value) {
		cl_assert(git__utf8_to_16_alloc(&wide_value, value) >= 0);
		cl_assert(SetEnvironmentVariableW(wide_name, wide_value));
	} else {
		/* Windows XP returns 0 (failed) when passing NULL for lpValue when
		* lpName does not exist in the environment block. This behavior
		* seems to have changed in later versions. Don't check the return value
		* of SetEnvironmentVariable when passing NULL for lpValue. */
		SetEnvironmentVariableW(wide_name, NULL);
	}

	return 0;
}
Example #4
0
static int fallback_cred_acquire_cb(
	git_cred **cred,
	const char *url,
	const char *username_from_url,
	unsigned int allowed_types,
	void *payload)
{
	int error = 1;

	GIT_UNUSED(username_from_url);
	GIT_UNUSED(payload);

	/* If the target URI supports integrated Windows authentication
	 * as an authentication mechanism */
	if (GIT_CREDTYPE_DEFAULT & allowed_types) {
		wchar_t *wide_url;

		/* Convert URL to wide characters */
		if (git__utf8_to_16_alloc(&wide_url, url) < 0) {
			giterr_set(GITERR_OS, "Failed to convert string to wide form");
			return -1;
		}

		if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) {
			IInternetSecurityManager* pISM;

			/* And if the target URI is in the My Computer, Intranet, or Trusted zones */
			if (SUCCEEDED(CoCreateInstance(&CLSID_InternetSecurityManager, NULL,
				CLSCTX_ALL, &IID_IInternetSecurityManager, (void **)&pISM))) {
				DWORD dwZone;

				if (SUCCEEDED(pISM->lpVtbl->MapUrlToZone(pISM, wide_url, &dwZone, 0)) &&
					(URLZONE_LOCAL_MACHINE == dwZone ||
					URLZONE_INTRANET == dwZone ||
					URLZONE_TRUSTED == dwZone)) {
					git_cred *existing = *cred;

					if (existing)
						existing->free(existing);

					/* Then use default Windows credentials to authenticate this request */
					error = git_cred_default_new(cred);
				}

				pISM->lpVtbl->Release(pISM);
			}

			CoUninitialize();
		}

		git__free(wide_url);
	}

	return error;
}
Example #5
0
static int apply_basic_credential_proxy(HINTERNET request, git_cred *cred)
{
	git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
	wchar_t *user, *pass;
	int error;

	if ((error = git__utf8_to_16_alloc(&user, c->username)) < 0)
		return error;

	if ((error = git__utf8_to_16_alloc(&pass, c->password)) < 0)
		return error;

	if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_PROXY, WINHTTP_AUTH_SCHEME_BASIC,
	                           user, pass, NULL)) {
		giterr_set(GITERR_OS, "failed to set proxy auth");
		error = -1;
	}

	git__free(user);
	git__free(pass);

	return error;
}
Example #6
0
static int apply_basic_credential(HINTERNET request, git_cred *cred)
{
	git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
	git_buf buf = GIT_BUF_INIT, raw = GIT_BUF_INIT;
	wchar_t *wide = NULL;
	int error = -1, wide_len;

	git_buf_printf(&raw, "%s:%s", c->username, c->password);

	if (git_buf_oom(&raw) ||
		git_buf_puts(&buf, "Authorization: Basic ") < 0 ||
		git_buf_encode_base64(&buf, git_buf_cstr(&raw), raw.size) < 0)
		goto on_error;

	if ((wide_len = git__utf8_to_16_alloc(&wide, git_buf_cstr(&buf))) < 0) {
		giterr_set(GITERR_OS, "Failed to convert string to wide form");
		goto on_error;
	}

	if (!WinHttpAddRequestHeaders(request, wide, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
		giterr_set(GITERR_OS, "Failed to add a header to the request");
		goto on_error;
	}

	error = 0;

on_error:
	/* We were dealing with plaintext passwords, so clean up after ourselves a bit. */
	if (wide)
		memset(wide, 0x0, wide_len * sizeof(wchar_t));

	if (buf.size)
		memset(buf.ptr, 0x0, buf.size);

	if (raw.size)
		memset(raw.ptr, 0x0, raw.size);

	git__free(wide);
	git_buf_free(&buf);
	git_buf_free(&raw);
	return error;
}
Example #7
0
char *cl_getenv(const char *name)
{
	wchar_t *wide_name, *wide_value;
	char *utf8_value = NULL;
	DWORD value_len;

	cl_assert(git__utf8_to_16_alloc(&wide_name, name) >= 0);

	value_len = GetEnvironmentVariableW(wide_name, NULL, 0);

	if (value_len) {
		cl_assert(wide_value = git__malloc(value_len * sizeof(wchar_t)));
		cl_assert(GetEnvironmentVariableW(wide_name, wide_value, value_len));
		cl_assert(git__utf16_to_8_alloc(&utf8_value, wide_value) >= 0);
		git__free(wide_value);
	}

	git__free(wide_name);
	return utf8_value;
}
Example #8
0
static int winhttp_stream_connect(winhttp_stream *s)
{
	winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
	git_buf buf = GIT_BUF_INIT;
	char *proxy_url = NULL;
	wchar_t ct[MAX_CONTENT_TYPE_LEN];
	LPCWSTR types[] = { L"*/*", NULL };
	BOOL peerdist = FALSE;
	int error = -1;
	unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS;
	int default_timeout = TIMEOUT_INFINITE;
	int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;

	/* Prepare URL */
	git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url);

	if (git_buf_oom(&buf))
		return -1;

	/* Convert URL to wide characters */
	if (git__utf8_to_16_alloc(&s->request_uri, git_buf_cstr(&buf)) < 0) {
		giterr_set(GITERR_OS, "Failed to convert string to wide form");
		goto on_error;
	}

	/* Establish request */
	s->request = WinHttpOpenRequest(
			t->connection,
			s->verb,
			s->request_uri,
			NULL,
			WINHTTP_NO_REFERER,
			types,
			t->connection_data.use_ssl ? WINHTTP_FLAG_SECURE : 0);

	if (!s->request) {
		giterr_set(GITERR_OS, "Failed to open request");
		goto on_error;
	}

	if (!WinHttpSetTimeouts(s->request, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
		giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP");
		goto on_error;
	}

	/* Set proxy if necessary */
	if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0)
		goto on_error;

	if (proxy_url) {
		WINHTTP_PROXY_INFO proxy_info;
		wchar_t *proxy_wide;

		/* Convert URL to wide characters */
		int proxy_wide_len = git__utf8_to_16_alloc(&proxy_wide, proxy_url);

		if (proxy_wide_len < 0) {
			giterr_set(GITERR_OS, "Failed to convert string to wide form");
			goto on_error;
		}

		/* Strip any trailing forward slash on the proxy URL;
		 * WinHTTP doesn't like it if one is present */
		if (proxy_wide_len > 1 && L'/' == proxy_wide[proxy_wide_len - 2])
			proxy_wide[proxy_wide_len - 2] = L'\0';

		proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
		proxy_info.lpszProxy = proxy_wide;
		proxy_info.lpszProxyBypass = NULL;

		if (!WinHttpSetOption(s->request,
			WINHTTP_OPTION_PROXY,
			&proxy_info,
			sizeof(WINHTTP_PROXY_INFO))) {
			giterr_set(GITERR_OS, "Failed to set proxy");
			git__free(proxy_wide);
			goto on_error;
		}

		git__free(proxy_wide);
	}

	/* Disable WinHTTP redirects so we can handle them manually. Why, you ask?
	 * http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/b2ff8879-ab9f-4218-8f09-16d25dff87ae
	 */
	if (!WinHttpSetOption(s->request,
		WINHTTP_OPTION_DISABLE_FEATURE,
		&disable_redirects,
		sizeof(disable_redirects))) {
			giterr_set(GITERR_OS, "Failed to disable redirects");
			goto on_error;
	}

	/* Strip unwanted headers (X-P2P-PeerDist, X-P2P-PeerDistEx) that WinHTTP
	 * adds itself. This option may not be supported by the underlying
	 * platform, so we do not error-check it */
	WinHttpSetOption(s->request,
		WINHTTP_OPTION_PEERDIST_EXTENSION_STATE,
		&peerdist,
		sizeof(peerdist));

	/* Send Pragma: no-cache header */
	if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
		giterr_set(GITERR_OS, "Failed to add a header to the request");
		goto on_error;
	}

	if (post_verb == s->verb) {
		/* Send Content-Type and Accept headers -- only necessary on a POST */
		git_buf_clear(&buf);
		if (git_buf_printf(&buf,
			"Content-Type: application/x-git-%s-request",
			s->service) < 0)
			goto on_error;

		if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
			giterr_set(GITERR_OS, "Failed to convert content-type to wide characters");
			goto on_error;
		}

		if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
			WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
			giterr_set(GITERR_OS, "Failed to add a header to the request");
			goto on_error;
		}

		git_buf_clear(&buf);
		if (git_buf_printf(&buf,
			"Accept: application/x-git-%s-result",
			s->service) < 0)
			goto on_error;

		if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
			giterr_set(GITERR_OS, "Failed to convert accept header to wide characters");
			goto on_error;
		}

		if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
			WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
			giterr_set(GITERR_OS, "Failed to add a header to the request");
			goto on_error;
		}
	}

	/* If requested, disable certificate validation */
	if (t->connection_data.use_ssl) {
		int flags;

		if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0)
			goto on_error;
	}

	/* If we have a credential on the subtransport, apply it to the request */
	if (t->cred &&
		t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
		t->auth_mechanism == GIT_WINHTTP_AUTH_BASIC &&
		apply_basic_credential(s->request, t->cred) < 0)
		goto on_error;
	else if (t->cred &&
		t->cred->credtype == GIT_CREDTYPE_DEFAULT &&
		t->auth_mechanism == GIT_WINHTTP_AUTH_NEGOTIATE &&
		apply_default_credentials(s->request) < 0)
		goto on_error;

	/* If no other credentials have been applied and the URL has username and
	 * password, use those */
	if (!t->cred && t->connection_data.user && t->connection_data.pass) {
		if (!t->url_cred &&
			git_cred_userpass_plaintext_new(&t->url_cred, t->connection_data.user, t->connection_data.pass) < 0)
			goto on_error;
		if (apply_basic_credential(s->request, t->url_cred) < 0)
			goto on_error;
	}

	/* We've done everything up to calling WinHttpSendRequest. */

	error = 0;

on_error:
	if (error < 0)
		winhttp_stream_close(s);

	git__free(proxy_url);
	git_buf_free(&buf);
	return error;
}
Example #9
0
static int filter_apply(
	git_filter				*self,
	void					**payload, /* may be read and/or set */
	git_buf					*to,
	const git_buf			*from,
	const git_filter_source	*src)
{
	struct filter_filter *ffs = (struct filter_filter *)self;
	git_config *config;
	git_buf configKey = GIT_BUF_INIT;
	int isRequired = FALSE;
	int error;
	const char *cmd = NULL;
	git_buf cmdBuf = GIT_BUF_INIT;
	wchar_t *wide_cmd;
	COMMAND_HANDLE commandHandle = COMMAND_HANDLE_INIT;
	git_buf errBuf = GIT_BUF_INIT;
	DWORD exitCode;

	if (!*payload)
		return GIT_PASSTHROUGH;

	if (git_repository_config__weakptr(&config, git_filter_source_repo(src)))
		return -1;

	git_buf_join3(&configKey, '.', "filter", *payload, "required");
	if (git_buf_oom(&configKey)) {
		giterr_set_oom();
		return -1;
	}

	error = git_config_get_bool(&isRequired, config, configKey.ptr);
	git_buf_free(&configKey);
	if (error && error != GIT_ENOTFOUND)
		return -1;

	git_buf_join(&configKey, '.', "filter", *payload);
	if (git_filter_source_mode(src) == GIT_FILTER_SMUDGE) {
		git_buf_puts(&configKey, ".smudge");
	} else {
		git_buf_puts(&configKey, ".clean");
	}
	if (git_buf_oom(&configKey)) {
		giterr_set_oom();
		return -1;
	}

	error = git_config_get_string(&cmd, config, configKey.ptr);
	git_buf_free(&configKey);
	if (error && error != GIT_ENOTFOUND)
		return -1;

	if (error == GIT_ENOTFOUND) {
		if (isRequired)
			return -1;
		return GIT_PASSTHROUGH;
	}

	git_buf_puts(&cmdBuf, cmd);
	if (git_buf_oom(&cmdBuf)) {
		giterr_set_oom();
		return -1;
	}

	if (expandPerCentF(&cmdBuf, git_filter_source_path(src)))
		return -1;

	if (ffs->shexepath) {
		// build params for sh.exe
		git_buf shParams = GIT_BUF_INIT;
		git_buf_puts(&shParams, " -c \"");
		git_buf_text_puts_escaped(&shParams, cmdBuf.ptr, "\"\\", "\\");
		git_buf_puts(&shParams, "\"");
		if (git_buf_oom(&shParams)) {
			git_buf_free(&cmdBuf);
			giterr_set_oom();
			return -1;
		}
		git_buf_swap(&shParams, &cmdBuf);
		git_buf_free(&shParams);
	}

	if (git__utf8_to_16_alloc(&wide_cmd, cmdBuf.ptr) < 0)
	{
		git_buf_free(&cmdBuf);
		giterr_set_oom();
		return -1;
	}
	git_buf_free(&cmdBuf);

	if (ffs->shexepath) {
		// build cmd, i.e. shexepath + params
		size_t len = wcslen(ffs->shexepath) + wcslen(wide_cmd) + 1;
		wchar_t *tmp = git__calloc(len, sizeof(wchar_t));
		if (!tmp) {
			git__free(wide_cmd);
			giterr_set_oom();
			return -1;
		}
		wcscat_s(tmp, len, ffs->shexepath);
		wcscat_s(tmp, len, wide_cmd);
		git__free(wide_cmd);
		wide_cmd = tmp;
	}

	commandHandle.errBuf = &errBuf;
	if (command_start(wide_cmd, &commandHandle, ffs->pEnv)) {
		git__free(wide_cmd);
		if (isRequired)
			return -1;
		return GIT_PASSTHROUGH;
	}
	git__free(wide_cmd);

	if (commmand_start_stdout_reading_thread(&commandHandle, to)) {
		command_close(&commandHandle);
		return -1;
	}

	if (command_write_gitbuf(&commandHandle, from)) {
		DWORD exitCode = command_close(&commandHandle);
		if (exitCode)
			setProcessError(exitCode, &errBuf);
		git_buf_free(&errBuf);
		if (isRequired)
			return -1;
		return GIT_PASSTHROUGH;
	}
	command_close_stdin(&commandHandle);

	if (command_wait_stdout_reading_thread(&commandHandle)) {
		DWORD exitCode = command_close(&commandHandle);
		if (exitCode)
			setProcessError(exitCode, &errBuf);
		git_buf_free(&errBuf);
		if (isRequired)
			return -1;
		return GIT_PASSTHROUGH;
	}

	exitCode = command_close(&commandHandle);
	if (exitCode) {
		if (isRequired) {
			setProcessError(exitCode, &errBuf);
			git_buf_free(&errBuf);
			return -1;
		}
		git_buf_free(&errBuf);
		return GIT_PASSTHROUGH;
	}

	git_buf_free(&errBuf);

	return 0;
}
Example #10
0
static int winhttp_connect(
	winhttp_subtransport *t)
{
	wchar_t *wide_host;
	int32_t port;
	wchar_t *wide_ua;
	git_buf ua = GIT_BUF_INIT;
	int error = -1;
	int default_timeout = TIMEOUT_INFINITE;
	int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;

	t->session = NULL;
	t->connection = NULL;

	/* Prepare port */
	if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
		return -1;

	/* Prepare host */
	if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		return -1;
	}

	if ((error = user_agent(&ua)) < 0) {
		git__free(wide_host);
		return error;
	}

	if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		git__free(wide_host);
		git_buf_free(&ua);
		return -1;
	}

	git_buf_free(&ua);

	/* Establish session */
	t->session = WinHttpOpen(
		wide_ua,
		WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
		WINHTTP_NO_PROXY_NAME,
		WINHTTP_NO_PROXY_BYPASS,
		0);

	if (!t->session) {
		giterr_set(GITERR_OS, "failed to init WinHTTP");
		goto on_error;
	}

	if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
		giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
		goto on_error;
	}

	
	/* Establish connection */
	t->connection = WinHttpConnect(
		t->session,
		wide_host,
		(INTERNET_PORT) port,
		0);

	if (!t->connection) {
		giterr_set(GITERR_OS, "failed to connect to host");
		goto on_error;
	}

	if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
		giterr_set(GITERR_OS, "failed to set status callback");
		goto on_error;
	}

	error = 0;

on_error:
	if (error < 0)
		winhttp_close_connection(t);

	git__free(wide_host);
	git__free(wide_ua);

	return error;
}
Example #11
0
static int winhttp_stream_connect(winhttp_stream *s)
{
	winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
	git_buf buf = GIT_BUF_INIT;
	char *proxy_url = NULL;
	wchar_t ct[MAX_CONTENT_TYPE_LEN];
	LPCWSTR types[] = { L"*/*", NULL };
	BOOL peerdist = FALSE;
	int error = -1;
	unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS;
	int default_timeout = TIMEOUT_INFINITE;
	int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
	size_t i;
	const git_proxy_options *proxy_opts;

	/* Prepare URL */
	git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url);

	if (git_buf_oom(&buf))
		return -1;

	/* Convert URL to wide characters */
	if (git__utf8_to_16_alloc(&s->request_uri, git_buf_cstr(&buf)) < 0) {
		giterr_set(GITERR_OS, "failed to convert string to wide form");
		goto on_error;
	}

	/* Establish request */
	s->request = WinHttpOpenRequest(
			t->connection,
			s->verb,
			s->request_uri,
			NULL,
			WINHTTP_NO_REFERER,
			types,
			t->connection_data.use_ssl ? WINHTTP_FLAG_SECURE : 0);

	if (!s->request) {
		giterr_set(GITERR_OS, "failed to open request");
		goto on_error;
	}

	if (!WinHttpSetTimeouts(s->request, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
		giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
		goto on_error;
	}

	proxy_opts = &t->owner->proxy;
	if (proxy_opts->type == GIT_PROXY_AUTO) {
		/* Set proxy if necessary */
		if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0)
			goto on_error;
	}
	else if (proxy_opts->type == GIT_PROXY_SPECIFIED) {
		proxy_url = git__strdup(proxy_opts->url);
		GITERR_CHECK_ALLOC(proxy_url);
	}

	if (proxy_url) {
		git_buf processed_url = GIT_BUF_INIT;
		WINHTTP_PROXY_INFO proxy_info;
		wchar_t *proxy_wide;

		if (!git__prefixcmp(proxy_url, SCHEME_HTTP)) {
			t->proxy_connection_data.use_ssl = false;
		} else if (!git__prefixcmp(proxy_url, SCHEME_HTTPS)) {
			t->proxy_connection_data.use_ssl = true;
		} else {
			giterr_set(GITERR_NET, "invalid URL: '%s'", proxy_url);
			return -1;
		}

		gitno_connection_data_free_ptrs(&t->proxy_connection_data);

		if ((error = gitno_extract_url_parts(&t->proxy_connection_data.host, &t->proxy_connection_data.port, NULL,
				&t->proxy_connection_data.user, &t->proxy_connection_data.pass, proxy_url, NULL)) < 0)
			goto on_error;

		if (t->proxy_connection_data.user && t->proxy_connection_data.pass) {
			if (t->proxy_cred) {
				t->proxy_cred->free(t->proxy_cred);
			}

			if ((error = git_cred_userpass_plaintext_new(&t->proxy_cred, t->proxy_connection_data.user, t->proxy_connection_data.pass)) < 0)
				goto on_error;
		}

		if (t->proxy_connection_data.use_ssl)
			git_buf_PUTS(&processed_url, SCHEME_HTTPS);
		else
			git_buf_PUTS(&processed_url, SCHEME_HTTP);

		git_buf_puts(&processed_url, t->proxy_connection_data.host);
		if (t->proxy_connection_data.port)
			git_buf_printf(&processed_url, ":%s", t->proxy_connection_data.port);

		if (git_buf_oom(&processed_url)) {
			giterr_set_oom();
			error = -1;
			goto on_error;
		}

		/* Convert URL to wide characters */
		error = git__utf8_to_16_alloc(&proxy_wide, processed_url.ptr);
		git_buf_free(&processed_url);
		if (error < 0)
			goto on_error;

		proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
		proxy_info.lpszProxy = proxy_wide;
		proxy_info.lpszProxyBypass = NULL;

		if (!WinHttpSetOption(s->request,
			WINHTTP_OPTION_PROXY,
			&proxy_info,
			sizeof(WINHTTP_PROXY_INFO))) {
			giterr_set(GITERR_OS, "failed to set proxy");
			git__free(proxy_wide);
			goto on_error;
		}

		git__free(proxy_wide);

		if (t->proxy_cred) {
			if (t->proxy_cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT) {
				if ((error = apply_userpass_credential_proxy(s->request, t->proxy_cred)) < 0)
					goto on_error;
			}
		}

	}

	/* Disable WinHTTP redirects so we can handle them manually. Why, you ask?
	 * http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/b2ff8879-ab9f-4218-8f09-16d25dff87ae
	 */
	if (!WinHttpSetOption(s->request,
		WINHTTP_OPTION_DISABLE_FEATURE,
		&disable_redirects,
		sizeof(disable_redirects))) {
			giterr_set(GITERR_OS, "failed to disable redirects");
			goto on_error;
	}

	/* Strip unwanted headers (X-P2P-PeerDist, X-P2P-PeerDistEx) that WinHTTP
	 * adds itself. This option may not be supported by the underlying
	 * platform, so we do not error-check it */
	WinHttpSetOption(s->request,
		WINHTTP_OPTION_PEERDIST_EXTENSION_STATE,
		&peerdist,
		sizeof(peerdist));

	/* Send Pragma: no-cache header */
	if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
		giterr_set(GITERR_OS, "failed to add a header to the request");
		goto on_error;
	}

	if (post_verb == s->verb) {
		/* Send Content-Type and Accept headers -- only necessary on a POST */
		git_buf_clear(&buf);
		if (git_buf_printf(&buf,
			"Content-Type: application/x-git-%s-request",
			s->service) < 0)
			goto on_error;

		if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
			giterr_set(GITERR_OS, "failed to convert content-type to wide characters");
			goto on_error;
		}

		if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
			WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
			giterr_set(GITERR_OS, "failed to add a header to the request");
			goto on_error;
		}

		git_buf_clear(&buf);
		if (git_buf_printf(&buf,
			"Accept: application/x-git-%s-result",
			s->service) < 0)
			goto on_error;

		if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
			giterr_set(GITERR_OS, "failed to convert accept header to wide characters");
			goto on_error;
		}

		if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
			WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
			giterr_set(GITERR_OS, "failed to add a header to the request");
			goto on_error;
		}
	}

	for (i = 0; i < t->owner->custom_headers.count; i++) {
		if (t->owner->custom_headers.strings[i]) {
			git_buf_clear(&buf);
			git_buf_puts(&buf, t->owner->custom_headers.strings[i]);
			if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
				giterr_set(GITERR_OS, "failed to convert custom header to wide characters");
				goto on_error;
			}

			if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
				WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
				giterr_set(GITERR_OS, "failed to add a header to the request");
				goto on_error;
			}
		}
	}

	/* If requested, disable certificate validation */
	if (t->connection_data.use_ssl) {
		int flags;

		if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0)
			goto on_error;
	}

	/* If we have a credential on the subtransport, apply it to the request */
	if (t->cred &&
		t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
		apply_userpass_credential(s->request, t->auth_mechanisms, t->cred) < 0)
		goto on_error;
	else if (t->cred &&
		t->cred->credtype == GIT_CREDTYPE_DEFAULT &&
		apply_default_credentials(s->request, t->auth_mechanisms) < 0)
		goto on_error;

	/* If no other credentials have been applied and the URL has username and
	 * password, use those */
	if (!t->cred && t->connection_data.user && t->connection_data.pass) {
		if (!t->url_cred &&
			git_cred_userpass_plaintext_new(&t->url_cred, t->connection_data.user, t->connection_data.pass) < 0)
			goto on_error;
		if (apply_userpass_credential(s->request, GIT_WINHTTP_AUTH_BASIC, t->url_cred) < 0)
			goto on_error;
	}

	/* We've done everything up to calling WinHttpSendRequest. */

	error = 0;

on_error:
	if (error < 0)
		winhttp_stream_close(s);

	git__free(proxy_url);
	git_buf_free(&buf);
	return error;
}
Example #12
0
static int _git_ssh_setup_tunnel(
	ssh_subtransport *t,
	const char *url,
	const char *gitCmd,
	git_smart_subtransport_stream **stream)
{
	char *host = NULL, *port = NULL, *path = NULL, *user = NULL, *pass = NULL;
	size_t i;
	ssh_stream *s;
	wchar_t *ssh = t->sshtoolpath;
	wchar_t *wideParams = NULL;
	wchar_t *cmd = NULL;
	git_buf params = GIT_BUF_INIT;
	int isPutty;
	size_t length;

	*stream = NULL;
	if (ssh_stream_alloc(t, url, gitCmd, stream) < 0) {
		giterr_set_oom();
		return -1;
	}

	s = (ssh_stream *)*stream;

	for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) {
		const char *p = ssh_prefixes[i];

		if (!git__prefixcmp(url, p)) {
			if (extract_url_parts(&host, &port, &path, &user, &pass, url, NULL) < 0)
				goto on_error;

			goto post_extract;
		}
	}
	if (git_ssh_extract_url_parts(&host, &user, url) < 0)
		goto on_error;

post_extract:
	if (!ssh)
	{
		giterr_set(GITERR_SSH, "No GIT_SSH tool configured");
		goto on_error;
	}

	isPutty = wcstristr(ssh, L"plink");
	if (port) {
		if (isPutty)
			git_buf_printf(&params, " -P %s", port);
		else
			git_buf_printf(&params, " -p %s", port);
	}
	if (isPutty && !wcstristr(ssh, L"tortoiseplink")) {
		git_buf_puts(&params, " -batch");
	}
	if (user)
		git_buf_printf(&params, " %s@%s ", user, host);
	else
		git_buf_printf(&params, " %s ", host);
	if (gen_proto(&params, s->cmd, s->url))
		goto on_error;
	if (git_buf_oom(&params)) {
		giterr_set_oom();
		goto on_error;
	}

	if (git__utf8_to_16_alloc(&wideParams, params.ptr) < 0) {
		giterr_set_oom();
		goto on_error;
	}
	git_buf_free(&params);

	length = wcslen(ssh) + wcslen(wideParams) + 3;
	cmd = git__calloc(length, sizeof(wchar_t));
	if (!cmd) {
		giterr_set_oom();
		goto on_error;
	}

	wcscat_s(cmd, length, L"\"");
	wcscat_s(cmd, length, ssh);
	wcscat_s(cmd, length, L"\"");
	wcscat_s(cmd, length, wideParams);

	if (command_start(cmd, &s->commandHandle, t->pEnv, isPutty ? CREATE_NEW_CONSOLE : DETACHED_PROCESS))
		goto on_error;

	git__free(wideParams);
	git__free(cmd);
	t->current_stream = s;
	git__free(host);
	git__free(port);
	git__free(path);
	git__free(user);
	git__free(pass);

	return 0;

on_error:
	t->current_stream = NULL;

	if (*stream)
		ssh_stream_free(*stream);

	git_buf_free(&params);

	if (wideParams)
		git__free(wideParams);

	if (cmd)
		git__free(cmd);

	git__free(host);
	git__free(port);
	git__free(user);
	git__free(pass);

	return -1;
}
Example #13
0
static int winhttp_connect(
	winhttp_subtransport *t)
{
	wchar_t *wide_host;
	int32_t port;
	wchar_t *wide_ua;
	git_buf ua = GIT_BUF_INIT;
	int error = -1;
	int default_timeout = TIMEOUT_INFINITE;
	int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
	DWORD protocols =
		WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
		WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
		WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;

	t->session = NULL;
	t->connection = NULL;

	/* Prepare port */
	if (git__strtol32(&port, t->connection_data.port, NULL, 10) < 0)
		return -1;

	/* Prepare host */
	if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		return -1;
	}


	if ((error = git_http__user_agent(&ua)) < 0) {
		git__free(wide_host);
		return error;
	}

	if (git__utf8_to_16_alloc(&wide_ua, git_buf_cstr(&ua)) < 0) {
		giterr_set(GITERR_OS, "unable to convert host to wide characters");
		git__free(wide_host);
		git_buf_free(&ua);
		return -1;
	}

	git_buf_free(&ua);

	/* Establish session */
	t->session = WinHttpOpen(
		wide_ua,
		WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
		WINHTTP_NO_PROXY_NAME,
		WINHTTP_NO_PROXY_BYPASS,
		0);

	if (!t->session) {
		giterr_set(GITERR_OS, "failed to init WinHTTP");
		goto on_error;
	}

	/*
	 * Do a best-effort attempt to enable TLS 1.2 but allow this to
	 * fail; if TLS 1.2 support is not available for some reason,
	 * ignore the failure (it will keep the default protocols).
	 */
	WinHttpSetOption(t->session,
		WINHTTP_OPTION_SECURE_PROTOCOLS,
		&protocols,
		sizeof(protocols));

	if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
		giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
		goto on_error;
	}


	/* Establish connection */
	t->connection = WinHttpConnect(
		t->session,
		wide_host,
		(INTERNET_PORT) port,
		0);

	if (!t->connection) {
		giterr_set(GITERR_OS, "failed to connect to host");
		goto on_error;
	}

	if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
		giterr_set(GITERR_OS, "failed to set status callback");
		goto on_error;
	}

	error = 0;

on_error:
	if (error < 0)
		winhttp_close_connection(t);

	git__free(wide_host);
	git__free(wide_ua);

	return error;
}