Subject: Re: [PATCH v9 5/5] transport: add from_user parameter to is_transport_allowed

From: Brandon Williams <[email-masked]>
Date: Wed, 14 Dec 2016 12:13:23 -0800

On 12/14, Jeff King wrote:
> On Tue, Dec 13, 2016 at 05:40:37PM -0800, Brandon Williams wrote:
> 
> > Add the from_user parameter to the 'is_transport_allowed' function.
> > This allows callers to query if a transport protocol is allowed, given
> > that the caller knows that the protocol is coming from the user (1) or
> > not from the user (0) such as redirects in libcurl.  If unknown a -1
> > should be provided which falls back to reading `GIT_PROTOCOL_FROM_USER`
> > to determine if the protocol came from the user.
> 
> I think your commit message is upside-down with respect to the purpose
> of the patch. The end goal we want is for http to distinguish between
> protocol restrictions for redirects versus initial requests. The rest is
> an implementation detail. It's definitely still worth discussing that
> implementation detail (though I think your in-code comments may be
> sufficient), but I don't see the rationale discussed here at all.

I'll fix the commit message to better discuss the reasoning behind the
change.

> > Signed-off-by: Brandon Williams <[email-masked]>
> > ---
> >  http.c      | 14 +++++++-------
> >  transport.c |  8 +++++---
> >  transport.h | 13 ++++++++++---
> >  3 files changed, 22 insertions(+), 13 deletions(-)
> 
> I'm trying to think of a way to test this. I guess the case we are
> covering here is when a server redirects, but the protocol is only
> allowed from the user. So:
> 
> diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
> index 044cc152f..d911afd24 100755
> --- a/t/t5812-proto-disable-http.sh
> +++ b/t/t5812-proto-disable-http.sh
> @@ -30,5 +30,12 @@ test_expect_success 'curl limits redirects' '
>  	test_must_fail git clone "$HTTPD_URL/loop-redir/smart/repo.git"
>  '
>  
> +test_expect_success 'http can be limited to from-user' '
> +	git -c protocol.http.allow=user \
> +		clone "$HTTPD_URL/smart/repo.git" plain.git &&
> +	test_must_fail git -c protocol.http.allow=user \
> +		clone "$HTTPD_URL/smart-redir-perm/repo.git" redir.git
> +'
> +
>  stop_httpd
>  test_done
> 
> It's an oddball configuration, and you'd probably just set
> http.followRedirects=false in practice, but it does correctly check this
> case.

K I'll add this in as a test.

> > @@ -588,9 +588,9 @@ static CURL *get_curl_handle(void)
> >  #endif
> >  #if LIBCURL_VERSION_NUM >= 0x071304
> >  	curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
> > -			 get_curl_allowed_protocols());
> > +			 get_curl_allowed_protocols(0));
> >  	curl_easy_setopt(result, CURLOPT_PROTOCOLS,
> > -			 get_curl_allowed_protocols());
> > +			 get_curl_allowed_protocols(-1));
> 
> This covers internal redirects done by libcurl, but not the dumb-walker
> http-alternates nonsense. We have to feed the URL from http-alternates
> back to curl ourselves, so it uses CURLOPT_PROTOCOLS even though it
> should count as "not from the user".
> 
> To fix that, I think we'd need something like:
> 
>   - get_curl_handle() stops setting these options, as it is done only
>     once when the curl handle is initialized. Instead, the protocol
>     restrictions should go into get_active_slot(), which is called for
>     each request.  The values set would remain the same, and be the
>     baseline.
> 
>   - the http-walker.c code would need to know when it's requesting from
>     the base URL, and when it's an alternate. I think this would depend
>     on the position of the "alt" in in the linked list it keeps.
> 
>   - when requesting from an alternate, http-walker would set
>     CURLOPT_PROTOCOLS with get_curl_allowed_protocols(0)
> 
> I have to admit that it sounds like a fair bit of work for a pretty
> obscure case. You'd have to:
> 
>   1. Turn http.allowRedirects to "true", to allow redirects even for
>      non-initial contact.
> 
>   2. Turn one of protocol.{http,https,ftp,ftps}.allow to "user" to
>      restrict it from being used in a redirect.
> 
> I'm tempted to punt on it and just do:
> 
>   if (http_follow_config == HTTP_FOLLOW_ALWAYS &&
>       get_curl_allowed_protocols(0) != get_curl_allowed_protocols(-1))
> 	die("user-only protocol restrictions not implemented for http-alternates");
> 
> which errs on the safe side. We could even shove that down into the case
> where we actually see some alternates, like:
> 
> diff --git a/http-walker.c b/http-walker.c
> index c2f81cd6a..5bcc850b1 100644
> --- a/http-walker.c
> +++ b/http-walker.c
> @@ -160,6 +160,12 @@ static void prefetch(struct walker *walker, unsigned char *sha1)
>  #endif
>  }
>  
> +static void check_alternates_protocol_restrictions(void)
> +{
> +	if (get_curl_allowed_protocols(0) != get_curl_allowed_protocol(-1))
> +		die("user-only protocol restrictions not implemented for http alternates");
> +}
> +
>  static void process_alternates_response(void *callback_data)
>  {
>  	struct alternates_request *alt_req =
> @@ -272,6 +278,7 @@ static void process_alternates_response(void *callback_data)
>  			/* skip "objects\n" at end */
>  			if (okay) {
>  				struct strbuf target = STRBUF_INIT;
> +				check_alternates_protocol_restrictions();
>  				strbuf_add(&target, base, serverlen);
>  				strbuf_add(&target, data + i, posn - i - 7);
>  				warning("adding alternate object store: %s",
> 
> I find it unlikely that anybody would ever care, but at least we'd do
> the safe thing. I dunno. Maybe I am just being lazy.

Well, that's unfortunate!  It does sound like a more full-proof solution
to these dumb http alternates could be involved.  I don't think your
simple "lazy" solution may be enough to not just die by default.

By default ftp/ftps will have a policy of "user only" which means they
will be set by the call to get_curl_allowed_protocol(-1) but not set by
get_curl_allowed_protocol(0).  This would result in the call to
check_alternates_protocol_restrictions failing all the time unless the
user explicitly sets ftp/ftps to "always" or "never".  If that is the
desired behavior then your proposed solution would be fine, otherwise we
may have to do the more involved approach.

-- 
Brandon Williams