libgit2 / libgit2

A cross-platform, linkable library implementation of Git that you can use in your application.
https://libgit2.org/
Other
9.7k stars 2.41k forks source link

Assertion failure when remote proxy supports both SPNEGO/Negotiate and NTLM #5178

Closed ianhattendorf closed 5 years ago

ianhattendorf commented 5 years ago

Reproduction steps

./libgit2_clar -sonline::clone::proxy with GITTEST_REMOTE_PROXY{HOST,USER,PASS} set pointing to a proxy that supports both SPNEGO and NTLM (in my case, squid 4).

Expected behavior

Tests pass.

Actual behavior

% ./libgit2_clar -vv -sonline::clone::proxy                                                                        ✭
Loaded 374 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')

libgit2_clar: ../src/transports/auth_negotiate.c:90: negotiate_next_token: Assertion `buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDTYPE_DEFAULT' failed.
[1]    15811 abort (core dumped)  ./libgit2_clar -vv -sonline::clone::proxy

Version of libgit2 (release number or SHA1)

master (a33c0de2edace210ccb99f2dc886971b8fa68382)

Operating system(s) tested

Linux & Mac

It looks like in http.c, init_auth relies on scheme_for_challenge to init the server auth_context, which doesn't take into account whether server->cred->credtype is compatible with that scheme. I attempted to fix it below, but am still failing a couple tests and I'm sure I'm violating some preconditions.

diff --git a/src/transports/http.c b/src/transports/http.c
index d727851b7..55030b06d 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -129,17 +129,19 @@ typedef struct {
        size_t *bytes_read;
 } parser_context;

-static git_http_auth_scheme *scheme_for_challenge(const char *challenge)
+static git_http_auth_scheme *scheme_for_challenge(const char *challenge, git_cred *cred)
 {
        git_http_auth_scheme *scheme = NULL;
        size_t i;

        for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
                const char *scheme_name = auth_schemes[i].name;
+               const git_credtype_t scheme_types = auth_schemes[i].credtypes;
                size_t scheme_len;

                scheme_len = strlen(scheme_name);
-               if (strncasecmp(challenge, scheme_name, scheme_len) == 0 &&
+               if ((!cred || (cred->credtype & scheme_types)) &&
+                   strncasecmp(challenge, scheme_name, scheme_len) == 0 &&
                    (challenge[scheme_len] == '\0' || challenge[scheme_len] == ' ')) {
                        scheme = &auth_schemes[i];
                        break;
@@ -256,7 +258,7 @@ static int set_authentication_types(http_server *server)
        size_t i;

        git_vector_foreach(&server->auth_challenges, i, challenge) {
-               if ((scheme = scheme_for_challenge(challenge)) != NULL) {
+               if ((scheme = scheme_for_challenge(challenge, NULL)) != NULL) {
                        server->authtypes |= scheme->type;
                        server->credtypes |= scheme->credtypes;
                }
@@ -432,7 +434,7 @@ static int init_auth(http_server *server)
        size_t i;

        git_vector_foreach(&server->auth_challenges, i, c) {
-               s = scheme_for_challenge(c);
+               s = scheme_for_challenge(c, server->cred);

                if (s && !!(s->credtypes & server->credtypes)) {
                        scheme = s;
ethomson commented 5 years ago

Long short, I know, but I don't suppose that you can make that proxy available for testing?

ianhattendorf commented 5 years ago

I can get you the config and setup guides if that's any help. We've wanted to look into making it available externally, but that wouldn't be any time soon (if at all).

And looks like I lied, it's actually Squid 3 running on Ubuntu 18.04 LTS.

https://wiki.squid-cache.org/ConfigExamples/Authenticate/Kerberos https://wiki.squid-cache.org/ConfigExamples/Authenticate/WindowsActiveDirectory

krb5.conf


[libdefaults]
      default_realm = YOURDOMAIN.LOCAL
      dns_lookup_kdc = yes
      dns_lookup_realm = yes
      default_keytab_name = /etc/squid3/PROXY.keytab

; for Windows 2008 with AES
      default_tgs_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
      default_tkt_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
      permitted_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5

[realms]
      YOURDOMAIN.LOCAL = {
              kdc = yourdc2.yourdomain.local
              admin_server = yourdc2.yourdomain.local
      }

[domain_realm]
      .yourdomain.local = YOURDOMAIN.LOCAL
      yourdomain.local = YOURDOMAIN.LOCAL

[logging]
  kdc = FILE:/var/log/kdc.log
  admin_server = FILE:/var/log/kadmin.log
  default = FILE:/var/log/krb5lib.log

smb.conf

[global]
local master = no
workgroup = YOURDOMAIN
security = ads
realm = YOURDOMAIN.LOCAL

winbind uid = 10000-20000
winbind gid = 10000-20000
winbind use default domain = yes
winbind enum users = yes
winbind enum groups = yes

load printers = no
printing = bsd
printcap name = /dev/null
disable spoolss = yes

squid.conf

## IMPORTANT FILES ---------------------------------------------------------------------------------
# Kerberos config file:
# /etc/krb5.conf
#
# Squid config file:
# etc/squid/squid.conf
#
# Keytab:
# /etc/squid3/PROXY.default
#
# Squid Logs:
# /var/log/squid/

## PORT --------------------------------------------------------------------------------------------
# Squid default port 3128
http_port 8080

## AUTHENTICATION ----------------------------------------------------------------------------------

# negotiate kerberos and ntlm authentication
auth_param negotiate program /usr/lib/squid3/negotiate_kerberos_auth -d -s HTTP/squid4.yourdomain.local@YOURDOMAIN.LOCAL -k /etc/squid3/PROXY.keytab
auth_param negotiate children 10
auth_param negotiate keep_alive off

# pure ntlm authentication
auth_param ntlm program /usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp
auth_param ntlm children 20
auth_param ntlm credentialsttl 2 hours
auth_param ntlm keep_alive on

## ACL RULES ---------------------------------------------------------------------------------------
acl authenticated proxy_auth REQUIRED
http_access allow authenticated

#which specific IPs do you want to allow to connect and use the proxy? Labeled them as clients here
acl clients          src             10.10.0.0/16

#specify from which network the clients are from (localnet)
acl localnet src 10.10.0.0/16

#on which ports do we allow connections using the proxy
acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl Safe_ports port 1025-65535  # unregistered ports
acl CONNECT method CONNECT

http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager

## LOGGING -----------------------------------------------------------------------------------------
cache_log /var/log/squid/squid-debug.log