Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
315cb38e
Commit
315cb38e
authored
Jul 31, 2014
by
Edward Thomson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add GSSAPI support for SPNEGO/Kerberos auth over HTTP
parent
e003f83a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
622 additions
and
30 deletions
+622
-30
CMakeLists.txt
+11
-0
cmake/Modules/FindGSSAPI.cmake
+324
-0
src/transports/http.c
+287
-30
No files found.
CMakeLists.txt
View file @
315cb38e
...
@@ -36,6 +36,7 @@ OPTION( ANDROID "Build for android NDK" OFF )
...
@@ -36,6 +36,7 @@ OPTION( ANDROID "Build for android NDK" OFF )
OPTION
(
USE_ICONV
"Link with and use iconv library"
OFF
)
OPTION
(
USE_ICONV
"Link with and use iconv library"
OFF
)
OPTION
(
USE_SSH
"Link with libssh to enable SSH support"
ON
)
OPTION
(
USE_SSH
"Link with libssh to enable SSH support"
ON
)
OPTION
(
USE_GSSAPI
"Link with libgssapi for SPNEGO auth"
ON
)
OPTION
(
VALGRIND
"Configure build for valgrind"
OFF
)
OPTION
(
VALGRIND
"Configure build for valgrind"
OFF
)
IF
(
${
CMAKE_SYSTEM_NAME
}
MATCHES
"Darwin"
)
IF
(
${
CMAKE_SYSTEM_NAME
}
MATCHES
"Darwin"
)
...
@@ -208,6 +209,14 @@ IF (LIBSSH2_FOUND)
...
@@ -208,6 +209,14 @@ IF (LIBSSH2_FOUND)
SET
(
SSH_LIBRARIES
${
LIBSSH2_LIBRARIES
}
)
SET
(
SSH_LIBRARIES
${
LIBSSH2_LIBRARIES
}
)
ENDIF
()
ENDIF
()
# Optional external dependency: libgssapi
IF
(
USE_GSSAPI
)
FIND_PACKAGE
(
GSSAPI
)
ENDIF
()
IF
(
GSSAPI_FOUND
)
ADD_DEFINITIONS
(
-DGIT_GSSAPI
)
ENDIF
()
# Optional external dependency: iconv
# Optional external dependency: iconv
IF
(
USE_ICONV
)
IF
(
USE_ICONV
)
FIND_PACKAGE
(
Iconv
)
FIND_PACKAGE
(
Iconv
)
...
@@ -387,6 +396,7 @@ ENDIF()
...
@@ -387,6 +396,7 @@ ENDIF()
ADD_LIBRARY
(
git2
${
SRC_H
}
${
SRC_GIT2
}
${
SRC_OS
}
${
SRC_ZLIB
}
${
SRC_HTTP
}
${
SRC_REGEX
}
${
SRC_SHA1
}
${
WIN_RC
}
)
ADD_LIBRARY
(
git2
${
SRC_H
}
${
SRC_GIT2
}
${
SRC_OS
}
${
SRC_ZLIB
}
${
SRC_HTTP
}
${
SRC_REGEX
}
${
SRC_SHA1
}
${
WIN_RC
}
)
TARGET_LINK_LIBRARIES
(
git2
${
SSL_LIBRARIES
}
)
TARGET_LINK_LIBRARIES
(
git2
${
SSL_LIBRARIES
}
)
TARGET_LINK_LIBRARIES
(
git2
${
SSH_LIBRARIES
}
)
TARGET_LINK_LIBRARIES
(
git2
${
SSH_LIBRARIES
}
)
TARGET_LINK_LIBRARIES
(
git2
${
GSSAPI_LIBRARIES
}
)
TARGET_LINK_LIBRARIES
(
git2
${
ICONV_LIBRARIES
}
)
TARGET_LINK_LIBRARIES
(
git2
${
ICONV_LIBRARIES
}
)
TARGET_OS_LIBRARIES
(
git2
)
TARGET_OS_LIBRARIES
(
git2
)
...
@@ -453,6 +463,7 @@ IF (BUILD_CLAR)
...
@@ -453,6 +463,7 @@ IF (BUILD_CLAR)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSL_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSL_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSH_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSH_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
GSSAPI_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
ICONV_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
ICONV_LIBRARIES
}
)
TARGET_OS_LIBRARIES(libgit2_clar)
TARGET_OS_LIBRARIES(libgit2_clar)
MSVC_SPLIT_SOURCES(libgit2_clar)
MSVC_SPLIT_SOURCES(libgit2_clar)
...
...
cmake/Modules/FindGSSAPI.cmake
0 → 100644
View file @
315cb38e
# - Try to find GSSAPI
# Once done this will define
#
# KRB5_CONFIG - Path to krb5-config
# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI
#
# Read-Only variables:
# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found
# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found
# GSSAPI_FOUND - system has GSSAPI
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
# GSSAPI_LIBRARIES - Link these to use GSSAPI
# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
#
#=============================================================================
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
#
find_path
(
GSSAPI_ROOT_DIR
NAMES
include/gssapi.h
include/gssapi/gssapi.h
HINTS
${
_GSSAPI_ROOT_HINTS
}
PATHS
${
_GSSAPI_ROOT_PATHS
}
)
mark_as_advanced
(
GSSAPI_ROOT_DIR
)
if
(
UNIX
)
find_program
(
KRB5_CONFIG
NAMES
krb5-config
PATHS
${
GSSAPI_ROOT_DIR
}
/bin
/opt/local/bin
)
mark_as_advanced
(
KRB5_CONFIG
)
if
(
KRB5_CONFIG
)
# Check if we have MIT KRB5
execute_process
(
COMMAND
${
KRB5_CONFIG
}
--vendor
RESULT_VARIABLE
_GSSAPI_VENDOR_RESULT
OUTPUT_VARIABLE
_GSSAPI_VENDOR_STRING
)
if
(
_GSSAPI_VENDOR_STRING MATCHES
".*Massachusetts.*"
)
set
(
GSSAPI_FLAVOR_MIT TRUE
)
else
()
execute_process
(
COMMAND
${
KRB5_CONFIG
}
--libs gssapi
RESULT_VARIABLE
_GSSAPI_LIBS_RESULT
OUTPUT_VARIABLE
_GSSAPI_LIBS_STRING
)
if
(
_GSSAPI_LIBS_STRING MATCHES
".*roken.*"
)
set
(
GSSAPI_FLAVOR_HEIMDAL TRUE
)
endif
()
endif
()
# Get the include dir
execute_process
(
COMMAND
${
KRB5_CONFIG
}
--cflags gssapi
RESULT_VARIABLE
_GSSAPI_INCLUDE_RESULT
OUTPUT_VARIABLE
_GSSAPI_INCLUDE_STRING
)
string
(
REGEX REPLACE
"(
\r
?
\n
)+$"
""
_GSSAPI_INCLUDE_STRING
"
${
_GSSAPI_INCLUDE_STRING
}
"
)
string
(
REGEX REPLACE
" *-I"
""
_GSSAPI_INCLUDEDIR
"
${
_GSSAPI_INCLUDE_STRING
}
"
)
endif
()
if
(
NOT GSSAPI_FLAVOR_MIT AND NOT GSSAPI_FLAVOR_HEIMDAL
)
# Check for HEIMDAL
find_package
(
PkgConfig
)
if
(
PKG_CONFIG_FOUND
)
pkg_check_modules
(
_GSSAPI heimdal-gssapi
)
endif
(
PKG_CONFIG_FOUND
)
if
(
_GSSAPI_FOUND
)
set
(
GSSAPI_FLAVOR_HEIMDAL TRUE
)
else
()
find_path
(
_GSSAPI_ROKEN
NAMES
roken.h
PATHS
${
GSSAPI_ROOT_DIR
}
/include
${
_GSSAPI_INCLUDEDIR
}
)
if
(
_GSSAPI_ROKEN
)
set
(
GSSAPI_FLAVOR_HEIMDAL TRUE
)
endif
()
endif
()
endif
()
endif
(
UNIX
)
find_path
(
GSSAPI_INCLUDE_DIR
NAMES
gssapi.h
gssapi/gssapi.h
PATHS
${
GSSAPI_ROOT_DIR
}
/include
${
_GSSAPI_INCLUDEDIR
}
)
if
(
GSSAPI_FLAVOR_MIT
)
find_library
(
GSSAPI_LIBRARY
NAMES
gssapi_krb5
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
KRB5_LIBRARY
NAMES
krb5
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
K5CRYPTO_LIBRARY
NAMES
k5crypto
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
COM_ERR_LIBRARY
NAMES
com_err
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
if
(
GSSAPI_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
GSSAPI_LIBRARY
}
)
endif
(
GSSAPI_LIBRARY
)
if
(
KRB5_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
KRB5_LIBRARY
}
)
endif
(
KRB5_LIBRARY
)
if
(
K5CRYPTO_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
K5CRYPTO_LIBRARY
}
)
endif
(
K5CRYPTO_LIBRARY
)
if
(
COM_ERR_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
COM_ERR_LIBRARY
}
)
endif
(
COM_ERR_LIBRARY
)
endif
(
GSSAPI_FLAVOR_MIT
)
if
(
GSSAPI_FLAVOR_HEIMDAL
)
find_library
(
GSSAPI_LIBRARY
NAMES
gssapi
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
KRB5_LIBRARY
NAMES
krb5
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
HCRYPTO_LIBRARY
NAMES
hcrypto
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
COM_ERR_LIBRARY
NAMES
com_err
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
HEIMNTLM_LIBRARY
NAMES
heimntlm
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
HX509_LIBRARY
NAMES
hx509
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
ASN1_LIBRARY
NAMES
asn1
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
WIND_LIBRARY
NAMES
wind
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
find_library
(
ROKEN_LIBRARY
NAMES
roken
PATHS
${
GSSAPI_ROOT_DIR
}
/lib
${
_GSSAPI_LIBDIR
}
)
if
(
GSSAPI_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
GSSAPI_LIBRARY
}
)
endif
(
GSSAPI_LIBRARY
)
if
(
KRB5_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
KRB5_LIBRARY
}
)
endif
(
KRB5_LIBRARY
)
if
(
HCRYPTO_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
HCRYPTO_LIBRARY
}
)
endif
(
HCRYPTO_LIBRARY
)
if
(
COM_ERR_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
COM_ERR_LIBRARY
}
)
endif
(
COM_ERR_LIBRARY
)
if
(
HEIMNTLM_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
HEIMNTLM_LIBRARY
}
)
endif
(
HEIMNTLM_LIBRARY
)
if
(
HX509_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
HX509_LIBRARY
}
)
endif
(
HX509_LIBRARY
)
if
(
ASN1_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
ASN1_LIBRARY
}
)
endif
(
ASN1_LIBRARY
)
if
(
WIND_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
WIND_LIBRARY
}
)
endif
(
WIND_LIBRARY
)
if
(
ROKEN_LIBRARY
)
set
(
GSSAPI_LIBRARIES
${
GSSAPI_LIBRARIES
}
${
WIND_LIBRARY
}
)
endif
(
ROKEN_LIBRARY
)
endif
(
GSSAPI_FLAVOR_HEIMDAL
)
include
(
FindPackageHandleStandardArgs
)
find_package_handle_standard_args
(
GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR
)
if
(
GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES
)
set
(
GSSAPI_FOUND TRUE
)
endif
(
GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES
)
# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
mark_as_advanced
(
GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES
)
src/transports/http.c
View file @
315cb38e
...
@@ -12,6 +12,11 @@
...
@@ -12,6 +12,11 @@
#include "netops.h"
#include "netops.h"
#include "smart.h"
#include "smart.h"
#ifdef GIT_GSSAPI
# include <gssapi.h>
# include <krb5.h>
#endif
static
const
char
*
upload_pack_service
=
"upload-pack"
;
static
const
char
*
upload_pack_service
=
"upload-pack"
;
static
const
char
*
upload_pack_ls_service_url
=
"/info/refs?service=git-upload-pack"
;
static
const
char
*
upload_pack_ls_service_url
=
"/info/refs?service=git-upload-pack"
;
static
const
char
*
upload_pack_service_url
=
"/git-upload-pack"
;
static
const
char
*
upload_pack_service_url
=
"/git-upload-pack"
;
...
@@ -21,6 +26,17 @@ static const char *receive_pack_service_url = "/git-receive-pack";
...
@@ -21,6 +26,17 @@ static const char *receive_pack_service_url = "/git-receive-pack";
static
const
char
*
get_verb
=
"GET"
;
static
const
char
*
get_verb
=
"GET"
;
static
const
char
*
post_verb
=
"POST"
;
static
const
char
*
post_verb
=
"POST"
;
static
const
char
*
basic_authtype
=
"Basic"
;
static
const
char
*
basic_authtype
=
"Basic"
;
static
const
char
*
negotiate_authtype
=
"Negotiate"
;
#ifdef GIT_GSSAPI
static
gss_OID_desc
negotiate_oid_spnego
=
{
6
,
(
void
*
)
"
\x2b\x06\x01\x05\x05\x02
"
};
static
gss_OID_desc
negotiate_oid_krb5
=
{
9
,
(
void
*
)
"
\x2a\x86\x48\x86\xf7\x12\x01\x02\x02
"
};
static
gss_OID
negotiate_oids
[]
=
{
&
negotiate_oid_spnego
,
&
negotiate_oid_krb5
,
NULL
};
#endif
#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
...
@@ -37,6 +53,7 @@ enum last_cb {
...
@@ -37,6 +53,7 @@ enum last_cb {
typedef
enum
{
typedef
enum
{
GIT_HTTP_AUTH_BASIC
=
1
,
GIT_HTTP_AUTH_BASIC
=
1
,
GIT_HTTP_AUTH_NEGOTIATE
=
2
,
}
http_authmechanism_t
;
}
http_authmechanism_t
;
typedef
struct
{
typedef
struct
{
...
@@ -61,6 +78,7 @@ typedef struct {
...
@@ -61,6 +78,7 @@ typedef struct {
git_cred
*
cred
;
git_cred
*
cred
;
git_cred
*
url_cred
;
git_cred
*
url_cred
;
http_authmechanism_t
auth_mechanism
;
http_authmechanism_t
auth_mechanism
;
char
*
auth_challenge
;
bool
connected
;
bool
connected
;
/* Parser structures */
/* Parser structures */
...
@@ -76,6 +94,14 @@ typedef struct {
...
@@ -76,6 +94,14 @@ typedef struct {
enum
last_cb
last_cb
;
enum
last_cb
last_cb
;
int
parse_error
;
int
parse_error
;
unsigned
parse_finished
:
1
;
unsigned
parse_finished
:
1
;
#ifdef GIT_GSSAPI
unsigned
negotiate_configured
:
1
,
negotiate_complete
:
1
;
git_buf
negotiate_target
;
gss_ctx_id_t
negotiate_context
;
gss_OID
negotiate_oid
;
#endif
}
http_subtransport
;
}
http_subtransport
;
typedef
struct
{
typedef
struct
{
...
@@ -88,12 +114,17 @@ typedef struct {
...
@@ -88,12 +114,17 @@ typedef struct {
size_t
*
bytes_read
;
size_t
*
bytes_read
;
}
parser_context
;
}
parser_context
;
static
int
apply_basic_credential
(
git_buf
*
buf
,
git_cred
*
cred
)
static
int
apply_basic_credential
(
git_buf
*
buf
,
http_subtransport
*
transport
,
git_cred
*
cred
)
{
{
git_cred_userpass_plaintext
*
c
=
(
git_cred_userpass_plaintext
*
)
cred
;
git_cred_userpass_plaintext
*
c
=
(
git_cred_userpass_plaintext
*
)
cred
;
git_buf
raw
=
GIT_BUF_INIT
;
git_buf
raw
=
GIT_BUF_INIT
;
int
error
=
-
1
;
int
error
=
-
1
;
GIT_UNUSED
(
transport
);
git_buf_printf
(
&
raw
,
"%s:%s"
,
c
->
username
,
c
->
password
);
git_buf_printf
(
&
raw
,
"%s:%s"
,
c
->
username
,
c
->
password
);
if
(
git_buf_oom
(
&
raw
)
||
if
(
git_buf_oom
(
&
raw
)
||
...
@@ -112,6 +143,188 @@ on_error:
...
@@ -112,6 +143,188 @@ on_error:
return
error
;
return
error
;
}
}
#ifdef GIT_GSSAPI
static
void
negotiate_err_set
(
OM_uint32
status_major
,
OM_uint32
status_minor
,
const
char
*
message
)
{
gss_buffer_desc
buffer
=
GSS_C_EMPTY_BUFFER
;
OM_uint32
status_display
,
context
=
0
;
if
(
gss_display_status
(
&
status_display
,
status_major
,
GSS_C_GSS_CODE
,
GSS_C_NO_OID
,
&
context
,
&
buffer
)
==
GSS_S_COMPLETE
)
{
giterr_set
(
GITERR_NET
,
"%s: %.*s (%d.%d)"
,
message
,
(
int
)
buffer
.
length
,
(
const
char
*
)
buffer
.
value
,
status_major
,
status_minor
);
gss_release_buffer
(
&
status_minor
,
&
buffer
);
}
else
{
giterr_set
(
GITERR_NET
,
"%s: unknown negotiate error (%d.%d)"
,
message
,
status_major
,
status_minor
);
}
}
static
int
negotiate_configure
(
http_subtransport
*
transport
)
{
OM_uint32
status_major
,
status_minor
;
gss_OID
item
,
*
oid
;
gss_OID_set
mechanism_list
;
size_t
i
;
/* Query supported mechanisms looking for SPNEGO) */
if
(
GSS_ERROR
(
status_major
=
gss_indicate_mechs
(
&
status_minor
,
&
mechanism_list
)))
{
negotiate_err_set
(
status_major
,
status_minor
,
"could not query mechanisms"
);
return
-
1
;
}
if
(
mechanism_list
)
{
for
(
oid
=
negotiate_oids
;
*
oid
;
oid
++
)
{
for
(
i
=
0
;
i
<
mechanism_list
->
count
;
i
++
)
{
item
=
&
mechanism_list
->
elements
[
i
];
if
(
item
->
length
==
(
*
oid
)
->
length
&&
memcmp
(
item
->
elements
,
(
*
oid
)
->
elements
,
item
->
length
)
==
0
)
{
transport
->
negotiate_oid
=
*
oid
;
break
;
}
}
if
(
transport
->
negotiate_oid
)
break
;
}
}
gss_release_oid_set
(
&
status_minor
,
&
mechanism_list
);
if
(
!
transport
->
negotiate_oid
)
{
giterr_set
(
GITERR_NET
,
"Negotiate authentication is not supported"
);
return
-
1
;
}
git_buf_puts
(
&
transport
->
negotiate_target
,
"HTTP@"
);
git_buf_puts
(
&
transport
->
negotiate_target
,
transport
->
connection_data
.
host
);
if
(
git_buf_oom
(
&
transport
->
negotiate_target
))
return
-
1
;
transport
->
negotiate_context
=
GSS_C_NO_CONTEXT
;
transport
->
negotiate_configured
=
1
;
return
0
;
}
static
int
negotiate_next_token
(
git_buf
*
buf
,
http_subtransport
*
transport
,
git_cred
*
cred
)
{
OM_uint32
status_major
,
status_minor
;
gss_buffer_desc
target_buffer
=
GSS_C_EMPTY_BUFFER
,
input_token
=
GSS_C_EMPTY_BUFFER
,
output_token
=
GSS_C_EMPTY_BUFFER
;
gss_buffer_t
input_token_ptr
=
GSS_C_NO_BUFFER
;
git_buf
input_buf
=
GIT_BUF_INIT
;
gss_name_t
server
=
NULL
;
gss_OID
mech
;
size_t
challenge_len
;
int
error
=
0
;
GIT_UNUSED
(
cred
);
target_buffer
.
value
=
(
void
*
)
transport
->
negotiate_target
.
ptr
;
target_buffer
.
length
=
transport
->
negotiate_target
.
size
;
status_major
=
gss_import_name
(
&
status_minor
,
&
target_buffer
,
GSS_C_NT_HOSTBASED_SERVICE
,
&
server
);
if
(
GSS_ERROR
(
status_major
))
{
negotiate_err_set
(
status_major
,
status_minor
,
"Could not parse principal"
);
error
=
-
1
;
goto
done
;
}
challenge_len
=
transport
->
auth_challenge
?
strlen
(
transport
->
auth_challenge
)
:
0
;
assert
(
challenge_len
>=
9
);
if
(
challenge_len
>
9
)
{
if
(
git_buf_decode_base64
(
&
input_buf
,
transport
->
auth_challenge
+
10
,
challenge_len
-
10
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Invalid negotiate challenge from server"
);
error
=
-
1
;
goto
done
;
}
input_token
.
value
=
input_buf
.
ptr
;
input_token
.
length
=
input_buf
.
size
;
input_token_ptr
=
&
input_token
;
}
else
if
(
transport
->
negotiate_context
!=
GSS_C_NO_CONTEXT
)
{
giterr_set
(
GITERR_NET
,
"Could not restart authentication"
);
error
=
-
1
;
goto
done
;
}
mech
=
&
negotiate_oid_spnego
;
if
(
GSS_ERROR
(
status_major
=
gss_init_sec_context
(
&
status_minor
,
GSS_C_NO_CREDENTIAL
,
&
transport
->
negotiate_context
,
server
,
mech
,
GSS_C_DELEG_FLAG
|
GSS_C_MUTUAL_FLAG
,
GSS_C_INDEFINITE
,
GSS_C_NO_CHANNEL_BINDINGS
,
input_token_ptr
,
NULL
,
&
output_token
,
NULL
,
NULL
)))
{
negotiate_err_set
(
status_major
,
status_minor
,
"Negotiate failure"
);
error
=
-
1
;
goto
done
;
}
/* This message merely told us auth was complete; we do not respond. */
if
(
status_major
==
GSS_S_COMPLETE
)
{
transport
->
negotiate_complete
=
1
;
goto
done
;
}
git_buf_puts
(
buf
,
"Authorization: Negotiate "
);
git_buf_encode_base64
(
buf
,
output_token
.
value
,
output_token
.
length
);
git_buf_puts
(
buf
,
"
\r\n
"
);
if
(
git_buf_oom
(
buf
))
error
=
-
1
;
done:
gss_release_name
(
&
status_minor
,
&
server
);
gss_release_buffer
(
&
status_minor
,
(
gss_buffer_t
)
&
output_token
);
git_buf_free
(
&
input_buf
);
return
error
;
}
static
int
apply_negotiate_credential
(
git_buf
*
buf
,
http_subtransport
*
transport
,
git_cred
*
cred
)
{
if
(
!
transport
->
negotiate_configured
&&
negotiate_configure
(
transport
)
<
0
)
return
-
1
;
if
(
transport
->
negotiate_complete
)
return
0
;
return
negotiate_next_token
(
buf
,
transport
,
cred
);
}
#endif
/* GIT_GSSAPI */
static
int
gen_request
(
static
int
gen_request
(
git_buf
*
buf
,
git_buf
*
buf
,
http_stream
*
s
,
http_stream
*
s
,
...
@@ -137,17 +350,26 @@ static int gen_request(
...
@@ -137,17 +350,26 @@ static int gen_request(
git_buf_puts
(
buf
,
"Accept: */*
\r\n
"
);
git_buf_puts
(
buf
,
"Accept: */*
\r\n
"
);
/* Apply credentials to the request */
/* Apply credentials to the request */
#ifdef GIT_GSSAPI
if
(
t
->
cred
&&
t
->
cred
->
credtype
==
GIT_CREDTYPE_DEFAULT
&&
(
t
->
auth_mechanism
&
GIT_HTTP_AUTH_NEGOTIATE
))
{
if
(
apply_negotiate_credential
(
buf
,
t
,
t
->
cred
)
<
0
)
return
-
1
;
}
else
#endif
if
(
t
->
cred
&&
t
->
cred
->
credtype
==
GIT_CREDTYPE_USERPASS_PLAINTEXT
&&
if
(
t
->
cred
&&
t
->
cred
->
credtype
==
GIT_CREDTYPE_USERPASS_PLAINTEXT
&&
t
->
auth_mechanism
==
GIT_HTTP_AUTH_BASIC
&&
t
->
auth_mechanism
==
GIT_HTTP_AUTH_BASIC
)
{
apply_basic_credential
(
buf
,
t
->
cred
)
<
0
)
if
(
apply_basic_credential
(
buf
,
t
,
t
->
cred
)
<
0
)
return
-
1
;
return
-
1
;
}
/* Use url-parsed basic auth if username and password are both provided */
/* Use url-parsed basic auth if username and password are both provided */
if
(
!
t
->
cred
&&
t
->
connection_data
.
user
&&
t
->
connection_data
.
pass
)
{
if
(
!
t
->
cred
&&
t
->
connection_data
.
user
&&
t
->
connection_data
.
pass
)
{
if
(
!
t
->
url_cred
&&
git_cred_userpass_plaintext_new
(
&
t
->
url_cred
,
if
(
!
t
->
url_cred
&&
git_cred_userpass_plaintext_new
(
&
t
->
url_cred
,
t
->
connection_data
.
user
,
t
->
connection_data
.
pass
)
<
0
)
t
->
connection_data
.
user
,
t
->
connection_data
.
pass
)
<
0
)
return
-
1
;
return
-
1
;
if
(
apply_basic_credential
(
buf
,
t
->
url_cred
)
<
0
)
return
-
1
;
if
(
apply_basic_credential
(
buf
,
t
,
t
->
url_cred
)
<
0
)
return
-
1
;
}
}
git_buf_puts
(
buf
,
"
\r\n
"
);
git_buf_puts
(
buf
,
"
\r\n
"
);
...
@@ -158,19 +380,32 @@ static int gen_request(
...
@@ -158,19 +380,32 @@ static int gen_request(
return
0
;
return
0
;
}
}
static
int
parse_
unauthorized
_response
(
static
int
parse_
authenticate
_response
(
git_vector
*
www_authenticate
,
git_vector
*
www_authenticate
,
int
*
allowed_types
,
int
*
allowed_types
,
http_authmechanism_t
*
auth_mechanism
)
http_authmechanism_t
*
auth_mechanism
,
char
**
auth_challenge
)
{
{
unsigned
i
;
unsigned
i
;
char
*
entry
;
char
*
entry
;
git_vector_foreach
(
www_authenticate
,
i
,
entry
)
{
git_vector_foreach
(
www_authenticate
,
i
,
entry
)
{
if
(
!
strncmp
(
entry
,
basic_authtype
,
5
)
&&
if
(
!
strncmp
(
entry
,
negotiate_authtype
,
9
)
&&
(
entry
[
9
]
==
'\0'
||
entry
[
9
]
==
' '
))
{
*
allowed_types
|=
GIT_CREDTYPE_DEFAULT
;
*
auth_mechanism
=
GIT_HTTP_AUTH_NEGOTIATE
;
*
auth_challenge
=
git__strdup
(
entry
);
GITERR_CHECK_ALLOC
(
*
auth_challenge
);
}
else
if
(
!
strncmp
(
entry
,
basic_authtype
,
5
)
&&
(
entry
[
5
]
==
'\0'
||
entry
[
5
]
==
' '
))
{
(
entry
[
5
]
==
'\0'
||
entry
[
5
]
==
' '
))
{
*
allowed_types
|=
GIT_CREDTYPE_USERPASS_PLAINTEXT
;
*
allowed_types
|=
GIT_CREDTYPE_USERPASS_PLAINTEXT
;
*
auth_mechanism
=
GIT_HTTP_AUTH_BASIC
;
*
auth_mechanism
=
GIT_HTTP_AUTH_BASIC
;
*
auth_challenge
=
git__strdup
(
entry
);
GITERR_CHECK_ALLOC
(
*
auth_challenge
);
}
}
}
}
...
@@ -248,7 +483,7 @@ static int on_headers_complete(http_parser *parser)
...
@@ -248,7 +483,7 @@ static int on_headers_complete(http_parser *parser)
http_subtransport
*
t
=
ctx
->
t
;
http_subtransport
*
t
=
ctx
->
t
;
http_stream
*
s
=
ctx
->
s
;
http_stream
*
s
=
ctx
->
s
;
git_buf
buf
=
GIT_BUF_INIT
;
git_buf
buf
=
GIT_BUF_INIT
;
int
error
=
0
,
no_callback
=
0
;
int
error
=
0
,
no_callback
=
0
,
allowed_auth_types
=
0
;
/* Both parse_header_name and parse_header_value are populated
/* Both parse_header_name and parse_header_value are populated
* and ready for consumption. */
* and ready for consumption. */
...
@@ -256,26 +491,31 @@ static int on_headers_complete(http_parser *parser)
...
@@ -256,26 +491,31 @@ static int on_headers_complete(http_parser *parser)
if
(
on_header_ready
(
t
)
<
0
)
if
(
on_header_ready
(
t
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
/* Check for an authentication failure. */
/* Capture authentication headers which may be a 401 (authentication
* is not complete) or a 200 (simply informing us that auth *is*
* complete.)
*/
git__free
(
t
->
auth_challenge
);
t
->
auth_challenge
=
NULL
;
if
(
parser
->
status_code
==
401
&&
if
(
parse_authenticate_response
(
&
t
->
www_authenticate
,
get_verb
==
s
->
verb
)
{
&
allowed_auth_types
,
&
t
->
auth_mechanism
,
&
t
->
auth_challenge
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
/* Check for an authentication failure. */
if
(
parser
->
status_code
==
401
&&
get_verb
==
s
->
verb
)
{
if
(
!
t
->
owner
->
cred_acquire_cb
)
{
if
(
!
t
->
owner
->
cred_acquire_cb
)
{
no_callback
=
1
;
no_callback
=
1
;
}
else
{
}
else
{
int
allowed_types
=
0
;
if
(
allowed_auth_types
&&
(
!
t
->
cred
||
0
==
(
t
->
cred
->
credtype
&
allowed_auth_types
)))
{
if
(
parse_unauthorized_response
(
&
t
->
www_authenticate
,
&
allowed_types
,
&
t
->
auth_mechanism
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
if
(
allowed_types
&&
(
!
t
->
cred
||
0
==
(
t
->
cred
->
credtype
&
allowed_types
)))
{
error
=
t
->
owner
->
cred_acquire_cb
(
&
t
->
cred
,
error
=
t
->
owner
->
cred_acquire_cb
(
&
t
->
cred
,
t
->
owner
->
url
,
t
->
owner
->
url
,
t
->
connection_data
.
user
,
t
->
connection_data
.
user
,
allowed_types
,
allowed_
auth_
types
,
t
->
owner
->
cred_acquire_payload
);
t
->
owner
->
cred_acquire_payload
);
if
(
error
==
GIT_PASSTHROUGH
)
{
if
(
error
==
GIT_PASSTHROUGH
)
{
...
@@ -511,10 +751,8 @@ replay:
...
@@ -511,10 +751,8 @@ replay:
clear_parser_state
(
t
);
clear_parser_state
(
t
);
if
(
gen_request
(
&
request
,
s
,
0
)
<
0
)
{
if
(
gen_request
(
&
request
,
s
,
0
)
<
0
)
giterr_set
(
GITERR_NET
,
"Failed to generate request"
);
return
-
1
;
return
-
1
;
}
if
(
gitno_send
(
&
t
->
socket
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
{
if
(
gitno_send
(
&
t
->
socket
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
{
git_buf_free
(
&
request
);
git_buf_free
(
&
request
);
...
@@ -613,10 +851,8 @@ static int http_stream_write_chunked(
...
@@ -613,10 +851,8 @@ static int http_stream_write_chunked(
clear_parser_state
(
t
);
clear_parser_state
(
t
);
if
(
gen_request
(
&
request
,
s
,
0
)
<
0
)
{
if
(
gen_request
(
&
request
,
s
,
0
)
<
0
)
giterr_set
(
GITERR_NET
,
"Failed to generate request"
);
return
-
1
;
return
-
1
;
}
if
(
gitno_send
(
&
t
->
socket
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
{
if
(
gitno_send
(
&
t
->
socket
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
{
git_buf_free
(
&
request
);
git_buf_free
(
&
request
);
...
@@ -688,10 +924,8 @@ static int http_stream_write_single(
...
@@ -688,10 +924,8 @@ static int http_stream_write_single(
clear_parser_state
(
t
);
clear_parser_state
(
t
);
if
(
gen_request
(
&
request
,
s
,
len
)
<
0
)
{
if
(
gen_request
(
&
request
,
s
,
len
)
<
0
)
giterr_set
(
GITERR_NET
,
"Failed to generate request"
);
return
-
1
;
return
-
1
;
}
if
(
gitno_send
(
&
t
->
socket
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
if
(
gitno_send
(
&
t
->
socket
,
request
.
ptr
,
request
.
size
,
0
)
<
0
)
goto
on_error
;
goto
on_error
;
...
@@ -855,6 +1089,24 @@ static int http_action(
...
@@ -855,6 +1089,24 @@ static int http_action(
return
-
1
;
return
-
1
;
}
}
static
void
clear_negotiate_state
(
http_subtransport
*
t
)
{
#ifdef GIT_GSSAPI
OM_uint32
status_minor
;
if
(
t
->
negotiate_context
!=
GSS_C_NO_CONTEXT
)
{
gss_delete_sec_context
(
&
status_minor
,
&
t
->
negotiate_context
,
GSS_C_NO_BUFFER
);
t
->
negotiate_context
=
GSS_C_NO_CONTEXT
;
}
git_buf_free
(
&
t
->
negotiate_target
);
t
->
negotiate_configured
=
0
;
t
->
negotiate_complete
=
0
;
t
->
negotiate_oid
=
NULL
;
#endif
}
static
int
http_close
(
git_smart_subtransport
*
subtransport
)
static
int
http_close
(
git_smart_subtransport
*
subtransport
)
{
{
http_subtransport
*
t
=
(
http_subtransport
*
)
subtransport
;
http_subtransport
*
t
=
(
http_subtransport
*
)
subtransport
;
...
@@ -876,6 +1128,11 @@ static int http_close(git_smart_subtransport *subtransport)
...
@@ -876,6 +1128,11 @@ static int http_close(git_smart_subtransport *subtransport)
t
->
url_cred
=
NULL
;
t
->
url_cred
=
NULL
;
}
}
git__free
(
t
->
auth_challenge
);
t
->
auth_challenge
=
NULL
;
clear_negotiate_state
(
t
);
gitno_connection_data_free_ptrs
(
&
t
->
connection_data
);
gitno_connection_data_free_ptrs
(
&
t
->
connection_data
);
return
0
;
return
0
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment