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
9d641283
Commit
9d641283
authored
Nov 08, 2012
by
Philip Kelley
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1048 from pwkelley/basic_auth
Basic authentication for http and winhttp
parents
8ff2b0c7
11fa8472
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
595 additions
and
123 deletions
+595
-123
include/git2/remote.h
+16
-1
include/git2/transport.h
+49
-0
src/netops.c
+6
-3
src/remote.c
+10
-1
src/remote.h
+1
-0
src/transports/cred.c
+58
-0
src/transports/http.c
+269
-101
src/transports/local.c
+7
-1
src/transports/smart.c
+7
-1
src/transports/smart.h
+1
-0
src/transports/winhttp.c
+171
-15
No files found.
include/git2/remote.h
View file @
9d641283
...
...
@@ -287,6 +287,19 @@ GIT_EXTERN(int) git_remote_add(git_remote **out, git_repository *repo, const cha
GIT_EXTERN
(
void
)
git_remote_check_cert
(
git_remote
*
remote
,
int
check
);
/**
* Set a credentials acquisition callback for this remote. If the remote is
* not available for anonymous access, then you must set this callback in order
* to provide credentials to the transport at the time of authentication
* failure so that retry can be performed.
*
* @param remote the remote to configure
* @param The credentials acquisition callback to use (defaults to NULL)
*/
GIT_EXTERN
(
void
)
git_remote_set_cred_acquire_cb
(
git_remote
*
remote
,
git_cred_acquire_cb
cred_acquire_cb
);
/**
* Sets a custom transport for the remote. The caller can use this function
* to bypass the automatic discovery of a transport by URL scheme (i.e.
* http://, https://, git://) and supply their own transport to be used
...
...
@@ -297,7 +310,9 @@ GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check);
* @param remote the remote to configure
* @param transport the transport object for the remote to use
*/
GIT_EXTERN
(
int
)
git_remote_set_transport
(
git_remote
*
remote
,
git_transport
*
transport
);
GIT_EXTERN
(
int
)
git_remote_set_transport
(
git_remote
*
remote
,
git_transport
*
transport
);
/**
* Argument to the completion callback which tells it which operation
...
...
include/git2/transport.h
View file @
9d641283
...
...
@@ -20,6 +20,54 @@
GIT_BEGIN_DECL
/*
*** Begin interface for credentials acquisition ***
*/
typedef
enum
{
/* git_cred_userpass_plaintext */
GIT_CREDTYPE_USERPASS_PLAINTEXT
=
1
,
}
git_credtype_t
;
/* The base structure for all credential types */
typedef
struct
git_cred
{
git_credtype_t
credtype
;
void
(
*
free
)(
struct
git_cred
*
cred
);
}
git_cred
;
/* A plaintext username and password */
typedef
struct
git_cred_userpass_plaintext
{
git_cred
parent
;
char
*
username
;
char
*
password
;
}
git_cred_userpass_plaintext
;
/**
* Creates a new plain-text username and password credential object.
*
* @param cred The newly created credential object.
* @param username The username of the credential.
* @param password The password of the credential.
*/
GIT_EXTERN
(
int
)
git_cred_userpass_plaintext_new
(
git_cred
**
cred
,
const
char
*
username
,
const
char
*
password
);
/**
* Signature of a function which acquires a credential object.
*
* @param cred The newly created credential object.
* @param url The resource for which we are demanding a credential.
* @param allowed_types A bitmask stating which cred types are OK to return.
*/
typedef
int
(
*
git_cred_acquire_cb
)(
git_cred
**
cred
,
const
char
*
url
,
int
allowed_types
);
/*
*** End interface for credentials acquisition ***
*** Begin base transport interface ***
*/
...
...
@@ -43,6 +91,7 @@ typedef struct git_transport {
* direction. */
int
(
*
connect
)(
struct
git_transport
*
transport
,
const
char
*
url
,
git_cred_acquire_cb
cred_acquire_cb
,
int
direction
,
int
flags
);
...
...
src/netops.c
View file @
9d641283
...
...
@@ -193,16 +193,19 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons)
static
int
gitno_ssl_teardown
(
gitno_ssl
*
ssl
)
{
int
ret
;
do
{
ret
=
SSL_shutdown
(
ssl
->
ssl
);
}
while
(
ret
==
0
);
if
(
ret
<
0
)
return
ssl_set_error
(
ssl
,
ret
);
ret
=
ssl_set_error
(
ssl
,
ret
);
else
ret
=
0
;
SSL_free
(
ssl
->
ssl
);
SSL_CTX_free
(
ssl
->
ctx
);
return
0
;
return
ret
;
}
/* Match host names according to RFC 2818 rules */
...
...
src/remote.c
View file @
9d641283
...
...
@@ -492,7 +492,7 @@ int git_remote_connect(git_remote *remote, int direction)
if
(
!
remote
->
check_cert
)
flags
|=
GIT_TRANSPORTFLAGS_NO_CHECK_CERT
;
if
(
t
->
connect
(
t
,
url
,
direction
,
flags
)
<
0
)
if
(
t
->
connect
(
t
,
url
,
remote
->
cred_acquire_cb
,
direction
,
flags
)
<
0
)
goto
on_error
;
remote
->
transport
=
t
;
...
...
@@ -809,6 +809,15 @@ void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callback
remote
->
callbacks
.
data
);
}
void
git_remote_set_cred_acquire_cb
(
git_remote
*
remote
,
git_cred_acquire_cb
cred_acquire_cb
)
{
assert
(
remote
);
remote
->
cred_acquire_cb
=
cred_acquire_cb
;
}
int
git_remote_set_transport
(
git_remote
*
remote
,
git_transport
*
transport
)
{
assert
(
remote
&&
transport
);
...
...
src/remote.h
View file @
9d641283
...
...
@@ -22,6 +22,7 @@ struct git_remote {
git_vector
refs
;
struct
git_refspec
fetch
;
struct
git_refspec
push
;
git_cred_acquire_cb
cred_acquire_cb
;
git_transport
*
transport
;
git_repository
*
repo
;
git_remote_callbacks
callbacks
;
...
...
src/transports/cred.c
0 → 100644
View file @
9d641283
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "git2.h"
#include "smart.h"
static
void
plaintext_free
(
struct
git_cred
*
cred
)
{
git_cred_userpass_plaintext
*
c
=
(
git_cred_userpass_plaintext
*
)
cred
;
int
pass_len
=
strlen
(
c
->
password
);
git__free
(
c
->
username
);
/* Zero the memory which previously held the password */
memset
(
c
->
password
,
0x0
,
pass_len
);
git__free
(
c
->
password
);
git__free
(
c
);
}
int
git_cred_userpass_plaintext_new
(
git_cred
**
cred
,
const
char
*
username
,
const
char
*
password
)
{
git_cred_userpass_plaintext
*
c
;
if
(
!
cred
)
return
-
1
;
c
=
(
git_cred_userpass_plaintext
*
)
git__malloc
(
sizeof
(
git_cred_userpass_plaintext
));
GITERR_CHECK_ALLOC
(
c
);
c
->
parent
.
credtype
=
GIT_CREDTYPE_USERPASS_PLAINTEXT
;
c
->
parent
.
free
=
plaintext_free
;
c
->
username
=
git__strdup
(
username
);
if
(
!
c
->
username
)
{
git__free
(
c
);
return
-
1
;
}
c
->
password
=
git__strdup
(
password
);
if
(
!
c
->
password
)
{
git__free
(
c
->
username
);
git__free
(
c
);
return
-
1
;
}
*
cred
=
&
c
->
parent
;
return
0
;
}
\ No newline at end of file
src/transports/http.c
View file @
9d641283
...
...
@@ -10,6 +10,7 @@
#include "http_parser.h"
#include "buffer.h"
#include "netops.h"
#include "smart.h"
static
const
char
*
prefix_http
=
"http://"
;
static
const
char
*
prefix_https
=
"https://"
;
...
...
@@ -18,15 +19,23 @@ static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-p
static
const
char
*
upload_pack_service_url
=
"/git-upload-pack"
;
static
const
char
*
get_verb
=
"GET"
;
static
const
char
*
post_verb
=
"POST"
;
static
const
char
*
basic_authtype
=
"Basic"
;
#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
#define PARSE_ERROR_GENERIC -1
#define PARSE_ERROR_REPLAY -2
enum
last_cb
{
NONE
,
FIELD
,
VALUE
};
typedef
enum
{
GIT_HTTP_AUTH_BASIC
=
1
,
}
http_authmechanism_t
;
typedef
struct
{
git_smart_subtransport_stream
parent
;
const
char
*
service
;
...
...
@@ -37,27 +46,28 @@ typedef struct {
typedef
struct
{
git_smart_subtransport
parent
;
git_transpo
rt
*
owner
;
transport_sma
rt
*
owner
;
gitno_socket
socket
;
const
char
*
path
;
char
*
host
;
char
*
port
;
char
*
port
;
git_cred
*
cred
;
http_authmechanism_t
auth_mechanism
;
unsigned
connected
:
1
,
use_ssl
:
1
,
no_check_cert
:
1
;
use_ssl
:
1
;
/* Parser structures */
http_parser
parser
;
http_parser_settings
settings
;
gitno_buffer
parse_buffer
;
git_buf
parse_temp
;
git_buf
parse_header_name
;
git_buf
parse_header_value
;
char
parse_buffer_data
[
2048
];
char
*
content_type
;
git_vector
www_authenticate
;
enum
last_cb
last_cb
;
int
parse_error
;
unsigned
parse_finished
:
1
,
ct_found
:
1
,
ct_finished
:
1
;
int
parse_error
;
unsigned
parse_finished
:
1
;
}
http_subtransport
;
typedef
struct
{
...
...
@@ -70,10 +80,42 @@ typedef struct {
size_t
*
bytes_read
;
}
parser_context
;
static
int
gen_request
(
git_buf
*
buf
,
const
char
*
path
,
const
char
*
host
,
const
char
*
op
,
const
char
*
service
,
const
char
*
service_url
,
ssize_t
content_length
)
static
int
apply_basic_credential
(
git_buf
*
buf
,
git_cred
*
cred
)
{
git_cred_userpass_plaintext
*
c
=
(
git_cred_userpass_plaintext
*
)
cred
;
git_buf
raw
=
GIT_BUF_INIT
;
int
error
=
-
1
;
git_buf_printf
(
&
raw
,
"%s:%s"
,
c
->
username
,
c
->
password
);
if
(
git_buf_oom
(
&
raw
)
||
git_buf_puts
(
buf
,
"Authorization: Basic "
)
<
0
||
git_buf_put_base64
(
buf
,
git_buf_cstr
(
&
raw
),
raw
.
size
)
<
0
||
git_buf_puts
(
buf
,
"
\r\n
"
)
<
0
)
goto
on_error
;
error
=
0
;
on_error:
if
(
raw
.
size
)
memset
(
raw
.
ptr
,
0x0
,
raw
.
size
);
git_buf_free
(
&
raw
);
return
error
;
}
static
int
gen_request
(
git_buf
*
buf
,
const
char
*
path
,
const
char
*
host
,
git_cred
*
cred
,
http_authmechanism_t
auth_mechanism
,
const
char
*
op
,
const
char
*
service
,
const
char
*
service_url
,
ssize_t
content_length
)
{
if
(
path
==
NULL
)
/* Is 'git fetch http://host.com/' valid? */
if
(
!
path
)
path
=
"/"
;
git_buf_printf
(
buf
,
"%s %s%s HTTP/1.1
\r\n
"
,
op
,
path
,
service_url
);
...
...
@@ -86,6 +128,13 @@ static int gen_request(git_buf *buf, const char *path, const char *host, const c
}
else
{
git_buf_puts
(
buf
,
"Accept: */*
\r\n
"
);
}
/* Apply credentials to the request */
if
(
cred
&&
cred
->
credtype
==
GIT_CREDTYPE_USERPASS_PLAINTEXT
&&
auth_mechanism
==
GIT_HTTP_AUTH_BASIC
&&
apply_basic_credential
(
buf
,
cred
)
<
0
)
return
-
1
;
git_buf_puts
(
buf
,
"
\r\n
"
);
if
(
git_buf_oom
(
buf
))
...
...
@@ -94,88 +143,157 @@ static int gen_request(git_buf *buf, const char *path, const char *host, const c
return
0
;
}
static
int
parse_unauthorized_response
(
git_vector
*
www_authenticate
,
int
*
allowed_types
,
http_authmechanism_t
*
auth_mechanism
)
{
unsigned
i
;
char
*
entry
;
git_vector_foreach
(
www_authenticate
,
i
,
entry
)
{
if
(
!
strncmp
(
entry
,
basic_authtype
,
5
)
&&
(
entry
[
5
]
==
'\0'
||
entry
[
5
]
==
' '
))
{
*
allowed_types
|=
GIT_CREDTYPE_USERPASS_PLAINTEXT
;
*
auth_mechanism
=
GIT_HTTP_AUTH_BASIC
;
}
}
return
0
;
}
static
int
on_header_ready
(
http_subtransport
*
t
)
{
git_buf
*
name
=
&
t
->
parse_header_name
;
git_buf
*
value
=
&
t
->
parse_header_value
;
char
*
dup
;
if
(
!
t
->
content_type
&&
!
strcmp
(
"Content-Type"
,
git_buf_cstr
(
name
)))
{
t
->
content_type
=
git__strdup
(
git_buf_cstr
(
value
));
GITERR_CHECK_ALLOC
(
t
->
content_type
);
}
else
if
(
!
strcmp
(
"WWW-Authenticate"
,
git_buf_cstr
(
name
)))
{
dup
=
git__strdup
(
git_buf_cstr
(
value
));
GITERR_CHECK_ALLOC
(
dup
);
git_vector_insert
(
&
t
->
www_authenticate
,
dup
);
}
return
0
;
}
static
int
on_header_field
(
http_parser
*
parser
,
const
char
*
str
,
size_t
len
)
{
parser_context
*
ctx
=
(
parser_context
*
)
parser
->
data
;
http_subtransport
*
t
=
ctx
->
t
;
git_buf
*
buf
=
&
t
->
parse_temp
;
if
(
t
->
last_cb
==
VALUE
&&
t
->
ct_found
)
{
t
->
ct_finished
=
1
;
t
->
ct_found
=
0
;
t
->
content_type
=
git__strdup
(
git_buf_cstr
(
buf
));
GITERR_CHECK_ALLOC
(
t
->
content_type
);
git_buf_clear
(
buf
);
}
/* Both parse_header_name and parse_header_value are populated
* and ready for consumption */
if
(
VALUE
==
t
->
last_cb
)
if
(
on_header_ready
(
t
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
if
(
t
->
ct_found
)
{
t
->
last_cb
=
FIELD
;
return
0
;
}
if
(
NONE
==
t
->
last_cb
||
VALUE
==
t
->
last_cb
)
git_buf_clear
(
&
t
->
parse_header_name
);
if
(
t
->
last_cb
!=
FIELD
)
git_buf_clear
(
buf
)
;
if
(
git_buf_put
(
&
t
->
parse_header_name
,
str
,
len
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
git_buf_put
(
buf
,
str
,
len
);
t
->
last_cb
=
FIELD
;
return
git_buf_oom
(
buf
);
return
0
;
}
static
int
on_header_value
(
http_parser
*
parser
,
const
char
*
str
,
size_t
len
)
{
parser_context
*
ctx
=
(
parser_context
*
)
parser
->
data
;
http_subtransport
*
t
=
ctx
->
t
;
git_buf
*
buf
=
&
t
->
parse_temp
;
if
(
t
->
ct_finished
)
{
t
->
last_cb
=
VALUE
;
return
0
;
}
assert
(
NONE
!=
t
->
last_cb
);
if
(
t
->
last_cb
==
VALUE
)
git_buf_
put
(
buf
,
str
,
len
);
if
(
FIELD
==
t
->
last_cb
)
git_buf_
clear
(
&
t
->
parse_header_value
);
if
(
t
->
last_cb
==
FIELD
&&
!
strcmp
(
git_buf_cstr
(
buf
),
"Content-Type"
))
{
t
->
ct_found
=
1
;
git_buf_clear
(
buf
);
git_buf_put
(
buf
,
str
,
len
);
}
if
(
git_buf_put
(
&
t
->
parse_header_value
,
str
,
len
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
t
->
last_cb
=
VALUE
;
return
git_buf_oom
(
buf
);
return
0
;
}
static
int
on_headers_complete
(
http_parser
*
parser
)
{
parser_context
*
ctx
=
(
parser_context
*
)
parser
->
data
;
http_subtransport
*
t
=
ctx
->
t
;
git_buf
*
buf
=
&
t
->
parse_temp
;
http_stream
*
s
=
ctx
->
s
;
git_buf
buf
=
GIT_BUF_INIT
;
/* The content-type is text/plain for 404, so don't validate */
if
(
parser
->
status_code
==
404
)
{
git_buf_clear
(
buf
);
return
0
;
/* Both parse_header_name and parse_header_value are populated
* and ready for consumption. */
if
(
VALUE
==
t
->
last_cb
)
if
(
on_header_ready
(
t
)
<
0
)
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
/* Check for an authentication failure. */
if
(
parser
->
status_code
==
401
&&
get_verb
==
s
->
verb
&&
t
->
owner
->
cred_acquire_cb
)
{
int
allowed_types
=
0
;
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
)))
{
if
(
t
->
owner
->
cred_acquire_cb
(
&
t
->
cred
,
t
->
owner
->
url
,
allowed_types
)
<
0
)
return
PARSE_ERROR_GENERIC
;
assert
(
t
->
cred
);
/* Successfully acquired a credential. */
return
t
->
parse_error
=
PARSE_ERROR_REPLAY
;
}
}
if
(
t
->
content_type
==
NULL
)
{
t
->
content_type
=
git__strdup
(
git_buf_cstr
(
buf
));
if
(
t
->
content_type
==
NULL
)
return
t
->
parse_error
=
-
1
;
/* Check for a 200 HTTP status code. */
if
(
parser
->
status_code
!=
200
)
{
giterr_set
(
GITERR_NET
,
"Unexpected HTTP status code: %d"
,
parser
->
status_code
);
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
}
git_buf_clear
(
buf
);
git_buf_printf
(
buf
,
"application/x-git-%s-advertisement"
,
ctx
->
s
->
service
);
if
(
git_buf_oom
(
buf
))
return
t
->
parse_error
=
-
1
;
/* The response must contain a Content-Type header. */
if
(
!
t
->
content_type
)
{
giterr_set
(
GITERR_NET
,
"No Content-Type header in response"
);
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
}
if
(
strcmp
(
t
->
content_type
,
git_buf_cstr
(
buf
)))
{
giterr_set
(
GITERR_NET
,
"Invalid content-type: %s"
,
t
->
content_type
);
return
t
->
parse_error
=
-
1
;
/* The Content-Type header must match our expectation. */
if
(
get_verb
==
s
->
verb
)
git_buf_printf
(
&
buf
,
"application/x-git-%s-advertisement"
,
ctx
->
s
->
service
);
else
git_buf_printf
(
&
buf
,
"application/x-git-%s-result"
,
ctx
->
s
->
service
);
if
(
git_buf_oom
(
&
buf
))
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
if
(
strcmp
(
t
->
content_type
,
git_buf_cstr
(
&
buf
)))
{
git_buf_free
(
&
buf
);
giterr_set
(
GITERR_NET
,
"Invalid Content-Type: %s"
,
t
->
content_type
);
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
}
git_buf_clear
(
buf
);
git_buf_free
(
&
buf
);
return
0
;
}
...
...
@@ -186,11 +304,6 @@ static int on_message_complete(http_parser *parser)
t
->
parse_finished
=
1
;
if
(
parser
->
status_code
==
404
)
{
giterr_set
(
GITERR_NET
,
"Remote error: %s"
,
git_buf_cstr
(
&
t
->
parse_temp
));
t
->
parse_error
=
-
1
;
}
return
0
;
}
...
...
@@ -201,7 +314,7 @@ static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
if
(
ctx
->
buf_size
<
len
)
{
giterr_set
(
GITERR_NET
,
"Can't fit data in the buffer"
);
return
t
->
parse_error
=
-
1
;
return
t
->
parse_error
=
PARSE_ERROR_GENERIC
;
}
memcpy
(
ctx
->
buffer
,
str
,
len
);
...
...
@@ -212,6 +325,36 @@ static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
return
0
;
}
static
void
clear_parser_state
(
http_subtransport
*
t
)
{
unsigned
i
;
char
*
entry
;
http_parser_init
(
&
t
->
parser
,
HTTP_RESPONSE
);
gitno_buffer_setup
(
&
t
->
socket
,
&
t
->
parse_buffer
,
t
->
parse_buffer_data
,
sizeof
(
t
->
parse_buffer_data
));
t
->
last_cb
=
NONE
;
t
->
parse_error
=
0
;
t
->
parse_finished
=
0
;
git_buf_free
(
&
t
->
parse_header_name
);
git_buf_init
(
&
t
->
parse_header_name
,
0
);
git_buf_free
(
&
t
->
parse_header_value
);
git_buf_init
(
&
t
->
parse_header_value
,
0
);
git__free
(
t
->
content_type
);
t
->
content_type
=
NULL
;
git_vector_foreach
(
&
t
->
www_authenticate
,
i
,
entry
)
git__free
(
entry
);
git_vector_free
(
&
t
->
www_authenticate
);
}
static
int
http_stream_read
(
git_smart_subtransport_stream
*
stream
,
char
*
buffer
,
...
...
@@ -219,17 +362,22 @@ static int http_stream_read(
size_t
*
bytes_read
)
{
http_stream
*
s
=
(
http_stream
*
)
stream
;
http_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
http_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
git_buf
request
=
GIT_BUF_INIT
;
parser_context
ctx
;
replay:
*
bytes_read
=
0
;
assert
(
t
->
connected
);
if
(
!
s
->
sent_request
)
{
if
(
gen_request
(
&
request
,
t
->
path
,
t
->
host
,
s
->
verb
,
s
->
service
,
s
->
service_url
,
0
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Failed to generate request"
);
clear_parser_state
(
t
);
if
(
gen_request
(
&
request
,
t
->
path
,
t
->
host
,
t
->
cred
,
t
->
auth_mechanism
,
s
->
verb
,
s
->
service
,
s
->
service_url
,
0
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Failed to generate request"
);
return
-
1
;
}
...
...
@@ -239,7 +387,7 @@ static int http_stream_read(
}
git_buf_free
(
&
request
);
s
->
sent_request
=
1
;
s
->
sent_request
=
1
;
}
t
->
parse_buffer
.
offset
=
0
;
...
...
@@ -250,10 +398,11 @@ static int http_stream_read(
if
(
gitno_recv
(
&
t
->
parse_buffer
)
<
0
)
return
-
1
;
/* This call to http_parser_execute will result in invocations of the on_* family of
* callbacks. The most interesting of these is on_body_fill_buffer, which is called
* when data is ready to be copied into the target buffer. We need to marshal the
* buffer, buf_size, and bytes_read parameters to this callback. */
/* This call to http_parser_execute will result in invocations of the on_*
* family of callbacks. The most interesting of these is
* on_body_fill_buffer, which is called when data is ready to be copied
* into the target buffer. We need to marshal the buffer, buf_size, and
* bytes_read parameters to this callback. */
ctx
.
t
=
t
;
ctx
.
s
=
s
;
ctx
.
buffer
=
buffer
;
...
...
@@ -262,11 +411,23 @@ static int http_stream_read(
/* Set the context, call the parser, then unset the context. */
t
->
parser
.
data
=
&
ctx
;
http_parser_execute
(
&
t
->
parser
,
&
t
->
settings
,
t
->
parse_buffer
.
data
,
t
->
parse_buffer
.
offset
);
http_parser_execute
(
&
t
->
parser
,
&
t
->
settings
,
t
->
parse_buffer
.
data
,
t
->
parse_buffer
.
offset
);
t
->
parser
.
data
=
NULL
;
/* If there was a handled authentication failure, then parse_error
* will have signaled us that we should replay the request. */
if
(
PARSE_ERROR_REPLAY
==
t
->
parse_error
)
{
s
->
sent_request
=
0
;
goto
replay
;
}
if
(
t
->
parse_error
<
0
)
return
t
->
parse_error
;
return
-
1
;
return
0
;
}
...
...
@@ -277,7 +438,7 @@ static int http_stream_write(
size_t
len
)
{
http_stream
*
s
=
(
http_stream
*
)
stream
;
http_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
http_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
git_buf
request
=
GIT_BUF_INIT
;
assert
(
t
->
connected
);
...
...
@@ -287,7 +448,11 @@ static int http_stream_write(
assert
(
!
s
->
sent_request
);
if
(
!
s
->
sent_request
)
{
if
(
gen_request
(
&
request
,
t
->
path
,
t
->
host
,
s
->
verb
,
s
->
service
,
s
->
service_url
,
len
)
<
0
)
{
clear_parser_state
(
t
);
if
(
gen_request
(
&
request
,
t
->
path
,
t
->
host
,
t
->
cred
,
t
->
auth_mechanism
,
s
->
verb
,
s
->
service
,
s
->
service_url
,
len
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Failed to generate request"
);
return
-
1
;
}
...
...
@@ -316,9 +481,10 @@ static void http_stream_free(git_smart_subtransport_stream *stream)
git__free
(
s
);
}
static
int
http_stream_alloc
(
http_subtransport
*
t
,
git_smart_subtransport_stream
**
stream
)
static
int
http_stream_alloc
(
http_subtransport
*
t
,
git_smart_subtransport_stream
**
stream
)
{
http_stream
*
s
;
http_stream
*
s
;
if
(
!
stream
)
return
-
1
;
...
...
@@ -396,7 +562,8 @@ static int http_action(
t
->
use_ssl
=
1
;
}
if
((
ret
=
gitno_extract_host_and_port
(
&
t
->
host
,
&
t
->
port
,
url
,
default_port
))
<
0
)
if
((
ret
=
gitno_extract_host_and_port
(
&
t
->
host
,
&
t
->
port
,
url
,
default_port
))
<
0
)
return
ret
;
t
->
path
=
strchr
(
url
,
'/'
);
...
...
@@ -404,23 +571,23 @@ static int http_action(
if
(
!
t
->
connected
||
!
http_should_keep_alive
(
&
t
->
parser
))
{
if
(
t
->
use_ssl
)
{
int
transport_flags
;
if
(
t
->
owner
->
parent
.
read_flags
(
&
t
->
owner
->
parent
,
&
transport_flags
)
<
0
)
return
-
1
;
flags
|=
GITNO_CONNECT_SSL
;
if
(
t
->
no_check_cert
)
if
(
GIT_TRANSPORTFLAGS_NO_CHECK_CERT
&
transport_flags
)
flags
|=
GITNO_CONNECT_SSL_NO_CHECK_CERT
;
}
if
(
gitno_connect
(
&
t
->
socket
,
t
->
host
,
t
->
port
,
flags
)
<
0
)
return
-
1
;
t
->
parser
.
data
=
t
;
http_parser_init
(
&
t
->
parser
,
HTTP_RESPONSE
);
gitno_buffer_setup
(
&
t
->
socket
,
&
t
->
parse_buffer
,
t
->
parse_buffer_data
,
sizeof
(
t
->
parse_buffer_data
));
t
->
connected
=
1
;
}
t
->
parse_finished
=
0
;
t
->
parse_error
=
0
;
...
...
@@ -432,7 +599,7 @@ static int http_action(
case
GIT_SERVICE_UPLOADPACK
:
return
http_uploadpack
(
t
,
stream
);
}
*
stream
=
NULL
;
return
-
1
;
}
...
...
@@ -441,14 +608,23 @@ static void http_free(git_smart_subtransport *smart_transport)
{
http_subtransport
*
t
=
(
http_subtransport
*
)
smart_transport
;
git_buf_free
(
&
t
->
parse_temp
);
git__free
(
t
->
content_type
);
clear_parser_state
(
t
);
if
(
t
->
socket
.
socket
)
gitno_close
(
&
t
->
socket
);
if
(
t
->
cred
)
{
t
->
cred
->
free
(
t
->
cred
);
t
->
cred
=
NULL
;
}
git__free
(
t
->
host
);
git__free
(
t
->
port
);
git__free
(
t
);
}
int
git_smart_subtransport_http
(
git_smart_subtransport
**
out
,
git_transport
*
owner
)
int
git_smart_subtransport_http
(
git_smart_subtransport
**
out
,
git_transport
*
owner
)
{
http_subtransport
*
t
;
int
flags
;
...
...
@@ -459,18 +635,10 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own
t
=
(
http_subtransport
*
)
git__calloc
(
sizeof
(
http_subtransport
),
1
);
GITERR_CHECK_ALLOC
(
t
);
t
->
owner
=
owner
;
t
->
owner
=
(
transport_smart
*
)
owner
;
t
->
parent
.
action
=
http_action
;
t
->
parent
.
free
=
http_free
;
/* Read the flags from the owning transport */
if
(
owner
->
read_flags
&&
owner
->
read_flags
(
owner
,
&
flags
)
<
0
)
{
git__free
(
t
);
return
-
1
;
}
t
->
no_check_cert
=
flags
&
GIT_TRANSPORTFLAGS_NO_CHECK_CERT
;
t
->
settings
.
on_header_field
=
on_header_field
;
t
->
settings
.
on_header_value
=
on_header_value
;
t
->
settings
.
on_headers_complete
=
on_headers_complete
;
...
...
src/transports/local.c
View file @
9d641283
...
...
@@ -130,7 +130,11 @@ on_error:
* Try to open the url as a git directory. The direction doesn't
* matter in this case because we're calulating the heads ourselves.
*/
static
int
local_connect
(
git_transport
*
transport
,
const
char
*
url
,
int
direction
,
int
flags
)
static
int
local_connect
(
git_transport
*
transport
,
const
char
*
url
,
git_cred_acquire_cb
cred_acquire_cb
,
int
direction
,
int
flags
)
{
git_repository
*
repo
;
int
error
;
...
...
@@ -138,6 +142,8 @@ static int local_connect(git_transport *transport, const char *url, int directio
const
char
*
path
;
git_buf
buf
=
GIT_BUF_INIT
;
GIT_UNUSED
(
cred_acquire_cb
);
t
->
url
=
git__strdup
(
url
);
GITERR_CHECK_ALLOC
(
t
->
url
);
t
->
direction
=
direction
;
...
...
src/transports/smart.c
View file @
9d641283
...
...
@@ -52,7 +52,12 @@ static int git_smart__set_callbacks(
return
0
;
}
static
int
git_smart__connect
(
git_transport
*
transport
,
const
char
*
url
,
int
direction
,
int
flags
)
static
int
git_smart__connect
(
git_transport
*
transport
,
const
char
*
url
,
git_cred_acquire_cb
cred_acquire_cb
,
int
direction
,
int
flags
)
{
transport_smart
*
t
=
(
transport_smart
*
)
transport
;
git_smart_subtransport_stream
*
stream
;
...
...
@@ -66,6 +71,7 @@ static int git_smart__connect(git_transport *transport, const char *url, int dir
t
->
direction
=
direction
;
t
->
flags
=
flags
;
t
->
cred_acquire_cb
=
cred_acquire_cb
;
if
(
GIT_DIR_FETCH
==
direction
)
{
...
...
src/transports/smart.h
View file @
9d641283
...
...
@@ -99,6 +99,7 @@ typedef void (*packetsize_cb)(int received, void *payload);
typedef
struct
{
git_transport
parent
;
char
*
url
;
git_cred_acquire_cb
cred_acquire_cb
;
int
direction
;
int
flags
;
git_transport_message_cb
progress_cb
;
...
...
src/transports/winhttp.c
View file @
9d641283
...
...
@@ -30,6 +30,7 @@ static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-p
static
const
char
*
upload_pack_service_url
=
"/git-upload-pack"
;
static
const
wchar_t
*
get_verb
=
L"GET"
;
static
const
wchar_t
*
post_verb
=
L"POST"
;
static
const
wchar_t
*
basic_authtype
=
L"Basic"
;
static
const
wchar_t
*
pragma_nocache
=
L"Pragma: no-cache"
;
static
const
int
no_check_cert_flags
=
SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
...
...
@@ -37,6 +38,10 @@ static const int no_check_cert_flags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
#define OWNING_SUBTRANSPORT(s) ((winhttp_subtransport *)(s)->parent.subtransport)
typedef
enum
{
GIT_WINHTTP_AUTH_BASIC
=
1
,
}
winhttp_authmechanism_t
;
typedef
struct
{
git_smart_subtransport_stream
parent
;
const
char
*
service
;
...
...
@@ -49,16 +54,74 @@ typedef struct {
typedef
struct
{
git_smart_subtransport
parent
;
git_transpo
rt
*
owner
;
transport_sma
rt
*
owner
;
const
char
*
path
;
char
*
host
;
char
*
port
;
git_cred
*
cred
;
int
auth_mechanism
;
HINTERNET
session
;
HINTERNET
connection
;
unsigned
use_ssl
:
1
,
no_check_cert
:
1
;
unsigned
use_ssl
:
1
;
}
winhttp_subtransport
;
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_put_base64
(
&
buf
,
git_buf_cstr
(
&
raw
),
raw
.
size
)
<
0
)
goto
on_error
;
wide_len
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
git_buf_cstr
(
&
buf
),
-
1
,
NULL
,
0
);
if
(
!
wide_len
)
{
giterr_set
(
GITERR_OS
,
"Failed to measure string for wide conversion"
);
goto
on_error
;
}
wide
=
(
wchar_t
*
)
git__malloc
(
wide_len
*
sizeof
(
wchar_t
));
if
(
!
wide
)
goto
on_error
;
if
(
!
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
git_buf_cstr
(
&
buf
),
-
1
,
wide
,
wide_len
))
{
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
;
}
static
int
winhttp_stream_connect
(
winhttp_stream
*
s
)
{
winhttp_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
...
...
@@ -119,14 +182,27 @@ static int winhttp_stream_connect(winhttp_stream *s)
}
/* If requested, disable certificate validation */
if
(
t
->
use_ssl
&&
t
->
no_check_cert
)
{
if
(
!
WinHttpSetOption
(
s
->
request
,
WINHTTP_OPTION_SECURITY_FLAGS
,
if
(
t
->
use_ssl
)
{
int
flags
;
if
(
t
->
owner
->
parent
.
read_flags
(
&
t
->
owner
->
parent
,
&
flags
)
<
0
)
goto
on_error
;
if
((
GIT_TRANSPORTFLAGS_NO_CHECK_CERT
&
flags
)
&&
!
WinHttpSetOption
(
s
->
request
,
WINHTTP_OPTION_SECURITY_FLAGS
,
(
LPVOID
)
&
no_check_cert_flags
,
sizeof
(
no_check_cert_flags
)))
{
giterr_set
(
GITERR_OS
,
"Failed to set options to ignore cert errors"
);
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
;
/* We've done everything up to calling WinHttpSendRequest. */
return
0
;
...
...
@@ -136,6 +212,64 @@ on_error:
return
-
1
;
}
static
int
parse_unauthorized_response
(
HINTERNET
request
,
int
*
allowed_types
,
int
*
auth_mechanism
)
{
DWORD
index
,
buf_size
,
last_error
;
int
error
=
0
;
wchar_t
*
buf
=
NULL
;
*
allowed_types
=
0
;
for
(
index
=
0
;
;
index
++
)
{
/* Make a first call to ask for the size of the buffer to allocate
* to hold the WWW-Authenticate header */
if
(
!
WinHttpQueryHeaders
(
request
,
WINHTTP_QUERY_WWW_AUTHENTICATE
,
WINHTTP_HEADER_NAME_BY_INDEX
,
WINHTTP_NO_OUTPUT_BUFFER
,
&
buf_size
,
&
index
))
{
last_error
=
GetLastError
();
if
(
ERROR_WINHTTP_HEADER_NOT_FOUND
==
last_error
)
{
/* End of enumeration */
break
;
}
else
if
(
ERROR_INSUFFICIENT_BUFFER
==
last_error
)
{
git__free
(
buf
);
buf
=
(
wchar_t
*
)
git__malloc
(
buf_size
);
if
(
!
buf
)
{
error
=
-
1
;
break
;
}
}
else
{
giterr_set
(
GITERR_OS
,
"Failed to read WWW-Authenticate header"
);
error
=
-
1
;
break
;
}
}
/* Actually receive the data into our now-allocated buffer */
if
(
!
WinHttpQueryHeaders
(
request
,
WINHTTP_QUERY_WWW_AUTHENTICATE
,
WINHTTP_HEADER_NAME_BY_INDEX
,
buf
,
&
buf_size
,
&
index
))
{
giterr_set
(
GITERR_OS
,
"Failed to read WWW-Authenticate header"
);
error
=
-
1
;
break
;
}
if
(
!
wcsncmp
(
buf
,
basic_authtype
,
5
)
&&
(
buf
[
5
]
==
L'\0'
||
buf
[
5
]
==
L' '
))
{
*
allowed_types
|=
GIT_CREDTYPE_USERPASS_PLAINTEXT
;
*
auth_mechanism
=
GIT_WINHTTP_AUTH_BASIC
;
}
}
git__free
(
buf
);
return
error
;
}
static
int
winhttp_stream_read
(
git_smart_subtransport_stream
*
stream
,
char
*
buffer
,
...
...
@@ -145,6 +279,7 @@ static int winhttp_stream_read(
winhttp_stream
*
s
=
(
winhttp_stream
*
)
stream
;
winhttp_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
replay:
/* Connect if necessary */
if
(
!
s
->
request
&&
winhttp_stream_connect
(
s
)
<
0
)
return
-
1
;
...
...
@@ -182,6 +317,31 @@ static int winhttp_stream_read(
return
-
1
;
}
/* Handle authentication failures */
if
(
HTTP_STATUS_DENIED
==
status_code
&&
get_verb
==
s
->
verb
&&
t
->
owner
->
cred_acquire_cb
)
{
int
allowed_types
;
if
(
parse_unauthorized_response
(
s
->
request
,
&
allowed_types
,
&
t
->
auth_mechanism
)
<
0
)
return
-
1
;
if
(
allowed_types
&&
(
!
t
->
cred
||
0
==
(
t
->
cred
->
credtype
&
allowed_types
)))
{
if
(
t
->
owner
->
cred_acquire_cb
(
&
t
->
cred
,
t
->
owner
->
url
,
allowed_types
)
<
0
)
return
-
1
;
assert
(
t
->
cred
);
WinHttpCloseHandle
(
s
->
request
);
s
->
request
=
NULL
;
s
->
sent_request
=
0
;
/* Successfully acquired a credential */
goto
replay
;
}
}
if
(
HTTP_STATUS_OK
!=
status_code
)
{
giterr_set
(
GITERR_NET
,
"Request failed with status code: %d"
,
status_code
);
return
-
1
;
...
...
@@ -432,6 +592,11 @@ static void winhttp_free(git_smart_subtransport *smart_transport)
git__free
(
t
->
host
);
git__free
(
t
->
port
);
if
(
t
->
cred
)
{
t
->
cred
->
free
(
t
->
cred
);
t
->
cred
=
NULL
;
}
if
(
t
->
connection
)
{
WinHttpCloseHandle
(
t
->
connection
);
t
->
connection
=
NULL
;
...
...
@@ -448,7 +613,6 @@ static void winhttp_free(git_smart_subtransport *smart_transport)
int
git_smart_subtransport_http
(
git_smart_subtransport
**
out
,
git_transport
*
owner
)
{
winhttp_subtransport
*
t
;
int
flags
;
if
(
!
out
)
return
-
1
;
...
...
@@ -456,18 +620,10 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own
t
=
(
winhttp_subtransport
*
)
git__calloc
(
sizeof
(
winhttp_subtransport
),
1
);
GITERR_CHECK_ALLOC
(
t
);
t
->
owner
=
owner
;
t
->
owner
=
(
transport_smart
*
)
owner
;
t
->
parent
.
action
=
winhttp_action
;
t
->
parent
.
free
=
winhttp_free
;
/* Read the flags from the owning transport */
if
(
owner
->
read_flags
&&
owner
->
read_flags
(
owner
,
&
flags
)
<
0
)
{
git__free
(
t
);
return
-
1
;
}
t
->
no_check_cert
=
flags
&
GIT_TRANSPORTFLAGS_NO_CHECK_CERT
;
*
out
=
(
git_smart_subtransport
*
)
t
;
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