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
091361f5
Commit
091361f5
authored
Nov 06, 2012
by
Philip Kelley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Basic authentication for http and winhttp
parent
a5e85d86
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
311 additions
and
6 deletions
+311
-6
include/git2/remote.h
+16
-1
include/git2/transport.h
+49
-0
src/remote.c
+10
-1
src/remote.h
+1
-0
src/transports/cred.c
+58
-0
src/transports/http.c
+0
-0
src/transports/local.c
+7
-1
src/transports/smart.c
+7
-1
src/transports/smart.h
+1
-0
src/transports/winhttp.c
+162
-2
No files found.
include/git2/remote.h
View file @
091361f5
...
...
@@ -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 @
091361f5
...
...
@@ -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/remote.c
View file @
091361f5
...
...
@@ -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 @
091361f5
...
...
@@ -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 @
091361f5
/*
* 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 @
091361f5
This diff is collapsed.
Click to expand it.
src/transports/local.c
View file @
091361f5
...
...
@@ -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 @
091361f5
...
...
@@ -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 @
091361f5
...
...
@@ -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 @
091361f5
...
...
@@ -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,75 @@ 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
;
}
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
);
...
...
@@ -127,6 +191,13 @@ static int winhttp_stream_connect(winhttp_stream *s)
}
}
/* 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 +207,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 +274,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 +312,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 +587,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
;
...
...
@@ -456,7 +616,7 @@ 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
;
...
...
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