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
e3107e0e
Commit
e3107e0e
authored
May 16, 2013
by
Vicent Martí
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1558 from bmorganpa/ssh_transport
SSH Transport
parents
c2d282cf
84ac625d
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
771 additions
and
7 deletions
+771
-7
.gitignore
+1
-1
CMakeLists.txt
+13
-0
cmake/Modules/FindLIBSSH2.cmake
+44
-0
include/git2/transport.h
+74
-0
src/transport.c
+18
-6
src/transports/cred.c
+102
-0
src/transports/ssh.c
+519
-0
No files found.
.gitignore
View file @
e3107e0e
...
@@ -24,8 +24,8 @@ msvc/Release/
...
@@ -24,8 +24,8 @@ msvc/Release/
*.sdf
*.sdf
*.opensdf
*.opensdf
*.aps
*.aps
CMake*
*.cmake
*.cmake
!cmake/Modules/*.cmake
.DS_Store
.DS_Store
*~
*~
tags
tags
...
...
CMakeLists.txt
View file @
e3107e0e
...
@@ -14,6 +14,8 @@
...
@@ -14,6 +14,8 @@
PROJECT
(
libgit2 C
)
PROJECT
(
libgit2 C
)
CMAKE_MINIMUM_REQUIRED
(
VERSION 2.6
)
CMAKE_MINIMUM_REQUIRED
(
VERSION 2.6
)
set
(
CMAKE_MODULE_PATH
${
CMAKE_MODULE_PATH
}
"
${
CMAKE_SOURCE_DIR
}
/cmake/Modules/"
)
# Build options
# Build options
#
#
OPTION
(
SONAME
"Set the (SO)VERSION of the target"
ON
)
OPTION
(
SONAME
"Set the (SO)VERSION of the target"
ON
)
...
@@ -141,6 +143,15 @@ ELSEIF (NOT ZLIB_LIBRARY)
...
@@ -141,6 +143,15 @@ ELSEIF (NOT ZLIB_LIBRARY)
FILE
(
GLOB SRC_ZLIB deps/zlib/*.c
)
FILE
(
GLOB SRC_ZLIB deps/zlib/*.c
)
ENDIF
()
ENDIF
()
IF
(
NOT LIBSSH2_LIBRARY
)
FIND_PACKAGE
(
LIBSSH2 QUIET
)
ENDIF
()
IF
(
LIBSSH2_FOUND
)
ADD_DEFINITIONS
(
-DGIT_SSH
)
INCLUDE_DIRECTORIES
(
${
LIBSSH2_INCLUDE_DIR
}
)
SET
(
SSH_LIBRARIES
${
LIBSSH2_LIBRARIES
}
)
ENDIF
()
# Platform specific compilation flags
# Platform specific compilation flags
IF
(
MSVC
)
IF
(
MSVC
)
...
@@ -292,6 +303,7 @@ ENDIF()
...
@@ -292,6 +303,7 @@ ENDIF()
# Compile and link libgit2
# Compile and link libgit2
ADD_LIBRARY
(
git2
${
SRC_GIT2
}
${
SRC_OS
}
${
SRC_ZLIB
}
${
SRC_HTTP
}
${
SRC_REGEX
}
${
SRC_SHA1
}
${
WIN_RC
}
)
ADD_LIBRARY
(
git2
${
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_OS_LIBRARIES
(
git2
)
TARGET_OS_LIBRARIES
(
git2
)
# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240)
# Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240)
...
@@ -355,6 +367,7 @@ IF (BUILD_CLAR)
...
@@ -355,6 +367,7 @@ IF (BUILD_CLAR)
ADD_EXECUTABLE(libgit2_clar
${
SRC_GIT2
}
${
SRC_OS
}
${
SRC_CLAR
}
${
SRC_TEST
}
${
SRC_ZLIB
}
${
SRC_HTTP
}
${
SRC_REGEX
}
${
SRC_SHA1
}
)
ADD_EXECUTABLE(libgit2_clar
${
SRC_GIT2
}
${
SRC_OS
}
${
SRC_CLAR
}
${
SRC_TEST
}
${
SRC_ZLIB
}
${
SRC_HTTP
}
${
SRC_REGEX
}
${
SRC_SHA1
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSL_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSL_LIBRARIES
}
)
TARGET_LINK_LIBRARIES(libgit2_clar
${
SSH_LIBRARIES
}
)
TARGET_OS_LIBRARIES(libgit2_clar)
TARGET_OS_LIBRARIES(libgit2_clar)
MSVC_SPLIT_SOURCES(libgit2_clar)
MSVC_SPLIT_SOURCES(libgit2_clar)
...
...
cmake/Modules/FindLIBSSH2.cmake
0 → 100644
View file @
e3107e0e
if
(
LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS
)
set
(
LIBSSH2_FOUND TRUE
)
else
(
LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS
)
find_path
(
LIBSSH2_INCLUDE_DIR
NAMES
libssh2.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
${
CMAKE_INCLUDE_PATH
}
${
CMAKE_INSTALL_PREFIX
}
/include
)
find_library
(
LIBSSH2_LIBRARY
NAMES
ssh2
libssh2
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
${
CMAKE_LIBRARY_PATH
}
${
CMAKE_INSTALL_PREFIX
}
/lib
)
if
(
LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY
)
set
(
LIBSSH2_FOUND TRUE
)
endif
(
LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY
)
if
(
LIBSSH2_FOUND
)
set
(
LIBSSH2_INCLUDE_DIRS
${
LIBSSH2_INCLUDE_DIR
}
)
set
(
LIBSSH2_LIBRARIES
${
LIBSSH2_LIBRARIES
}
${
LIBSSH2_LIBRARY
}
)
endif
(
LIBSSH2_FOUND
)
endif
(
LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS
)
include/git2/transport.h
View file @
e3107e0e
...
@@ -11,6 +11,10 @@
...
@@ -11,6 +11,10 @@
#include "net.h"
#include "net.h"
#include "types.h"
#include "types.h"
#ifdef GIT_SSH
#include <libssh2.h>
#endif
/**
/**
* @file git2/transport.h
* @file git2/transport.h
* @brief Git transport interfaces and functions
* @brief Git transport interfaces and functions
...
@@ -27,6 +31,8 @@ GIT_BEGIN_DECL
...
@@ -27,6 +31,8 @@ GIT_BEGIN_DECL
typedef
enum
{
typedef
enum
{
/* git_cred_userpass_plaintext */
/* git_cred_userpass_plaintext */
GIT_CREDTYPE_USERPASS_PLAINTEXT
=
1
,
GIT_CREDTYPE_USERPASS_PLAINTEXT
=
1
,
GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE
=
2
,
GIT_CREDTYPE_SSH_PUBLICKEY
=
3
,
}
git_credtype_t
;
}
git_credtype_t
;
/* The base structure for all credential types */
/* The base structure for all credential types */
...
@@ -43,6 +49,27 @@ typedef struct git_cred_userpass_plaintext {
...
@@ -43,6 +49,27 @@ typedef struct git_cred_userpass_plaintext {
char
*
password
;
char
*
password
;
}
git_cred_userpass_plaintext
;
}
git_cred_userpass_plaintext
;
#ifdef GIT_SSH
typedef
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC
((
*
git_cred_sign_callback
));
/* A ssh key file and passphrase */
typedef
struct
git_cred_ssh_keyfile_passphrase
{
git_cred
parent
;
char
*
publickey
;
char
*
privatekey
;
char
*
passphrase
;
}
git_cred_ssh_keyfile_passphrase
;
/* A ssh public key and authentication callback */
typedef
struct
git_cred_ssh_publickey
{
git_cred
parent
;
char
*
publickey
;
size_t
publickey_len
;
void
*
sign_callback
;
void
*
sign_data
;
}
git_cred_ssh_publickey
;
#endif
/**
/**
* Creates a new plain-text username and password credential object.
* Creates a new plain-text username and password credential object.
* The supplied credential parameter will be internally duplicated.
* The supplied credential parameter will be internally duplicated.
...
@@ -57,6 +84,42 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new(
...
@@ -57,6 +84,42 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new(
const
char
*
username
,
const
char
*
username
,
const
char
*
password
);
const
char
*
password
);
#ifdef GIT_SSH
/**
* Creates a new ssh key file and passphrase credential object.
* The supplied credential parameter will be internally duplicated.
*
* @param out The newly created credential object.
* @param publickey The path to the public key of the credential.
* @param privatekey The path to the private key of the credential.
* @param passphrase The passphrase of the credential.
* @return 0 for success or an error code for failure
*/
GIT_EXTERN
(
int
)
git_cred_ssh_keyfile_passphrase_new
(
git_cred
**
out
,
const
char
*
publickey
,
const
char
*
privatekey
,
const
char
*
passphrase
);
/**
* Creates a new ssh public key credential object.
* The supplied credential parameter will be internally duplicated.
*
* @param out The newly created credential object.
* @param publickey The bytes of the public key.
* @param publickey_len The length of the public key in bytes.
* @param sign_callback The callback method for authenticating.
* @param sign_data The abstract data sent to the sign_callback method.
* @return 0 for success or an error code for failure
*/
GIT_EXTERN
(
int
)
git_cred_ssh_publickey_new
(
git_cred
**
out
,
const
char
*
publickey
,
size_t
publickey_len
,
git_cred_sign_callback
,
void
*
sign_data
);
#endif
/**
/**
* Signature of a function which acquires a credential object.
* Signature of a function which acquires a credential object.
*
*
...
@@ -319,6 +382,17 @@ GIT_EXTERN(int) git_smart_subtransport_git(
...
@@ -319,6 +382,17 @@ GIT_EXTERN(int) git_smart_subtransport_git(
git_smart_subtransport
**
out
,
git_smart_subtransport
**
out
,
git_transport
*
owner
);
git_transport
*
owner
);
/**
* Create an instance of the ssh subtransport.
*
* @param out The newly created subtransport
* @param owner The smart transport to own this subtransport
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_smart_subtransport_ssh
(
git_smart_subtransport
**
out
,
git_transport
*
owner
);
/*
/*
*** End interface for subtransports for the smart transport ***
*** End interface for subtransports for the smart transport ***
*/
*/
...
...
src/transport.c
View file @
e3107e0e
...
@@ -18,19 +18,27 @@ typedef struct transport_definition {
...
@@ -18,19 +18,27 @@ typedef struct transport_definition {
void
*
param
;
void
*
param
;
}
transport_definition
;
}
transport_definition
;
static
transport_definition
local_transport_definition
=
{
"file://"
,
1
,
git_transport_local
,
NULL
};
static
transport_definition
dummy_transport_definition
=
{
NULL
,
1
,
git_transport_dummy
,
NULL
};
static
git_smart_subtransport_definition
http_subtransport_definition
=
{
git_smart_subtransport_http
,
1
};
static
git_smart_subtransport_definition
http_subtransport_definition
=
{
git_smart_subtransport_http
,
1
};
static
git_smart_subtransport_definition
git_subtransport_definition
=
{
git_smart_subtransport_git
,
0
};
static
git_smart_subtransport_definition
git_subtransport_definition
=
{
git_smart_subtransport_git
,
0
};
#ifdef GIT_SSH
static
git_smart_subtransport_definition
ssh_subtransport_definition
=
{
git_smart_subtransport_ssh
,
0
};
#endif
static
transport_definition
local_transport_definition
=
{
"file://"
,
1
,
git_transport_local
,
NULL
};
#ifdef GIT_SSH
static
transport_definition
ssh_transport_definition
=
{
"ssh://"
,
1
,
git_transport_smart
,
&
ssh_subtransport_definition
};
#else
static
transport_definition
dummy_transport_definition
=
{
NULL
,
1
,
git_transport_dummy
,
NULL
};
#endif
static
transport_definition
transports
[]
=
{
static
transport_definition
transports
[]
=
{
{
"git://"
,
1
,
git_transport_smart
,
&
git_subtransport_definition
},
{
"git://"
,
1
,
git_transport_smart
,
&
git_subtransport_definition
},
{
"http://"
,
1
,
git_transport_smart
,
&
http_subtransport_definition
},
{
"http://"
,
1
,
git_transport_smart
,
&
http_subtransport_definition
},
{
"https://"
,
1
,
git_transport_smart
,
&
http_subtransport_definition
},
{
"https://"
,
1
,
git_transport_smart
,
&
http_subtransport_definition
},
{
"file://"
,
1
,
git_transport_local
,
NULL
},
{
"file://"
,
1
,
git_transport_local
,
NULL
},
{
"git+ssh://"
,
1
,
git_transport_dummy
,
NULL
},
#ifdef GIT_SSH
{
"ssh+git://"
,
1
,
git_transport_dummy
,
NULL
},
{
"ssh://"
,
1
,
git_transport_smart
,
&
ssh_subtransport_definition
},
#endif
{
NULL
,
0
,
0
}
{
NULL
,
0
,
0
}
};
};
...
@@ -73,7 +81,11 @@ static int transport_find_fn(const char *url, git_transport_cb *callback, void *
...
@@ -73,7 +81,11 @@ static int transport_find_fn(const char *url, git_transport_cb *callback, void *
/* It could be a SSH remote path. Check to see if there's a :
/* It could be a SSH remote path. Check to see if there's a :
* SSH is an unsupported transport mechanism in this version of libgit2 */
* SSH is an unsupported transport mechanism in this version of libgit2 */
if
(
!
definition
&&
strrchr
(
url
,
':'
))
if
(
!
definition
&&
strrchr
(
url
,
':'
))
definition
=
&
dummy_transport_definition
;
#ifdef GIT_SSH
definition
=
&
ssh_transport_definition
;
#else
definition
=
&
dummy_transport_definition
;
#endif
/* Check to see if the path points to a file on the local file system */
/* Check to see if the path points to a file on the local file system */
if
(
!
definition
&&
git_path_exists
(
url
)
&&
git_path_isdir
(
url
))
if
(
!
definition
&&
git_path_exists
(
url
)
&&
git_path_isdir
(
url
))
...
...
src/transports/cred.c
View file @
e3107e0e
...
@@ -58,3 +58,105 @@ int git_cred_userpass_plaintext_new(
...
@@ -58,3 +58,105 @@ int git_cred_userpass_plaintext_new(
*
cred
=
&
c
->
parent
;
*
cred
=
&
c
->
parent
;
return
0
;
return
0
;
}
}
#ifdef GIT_SSH
static
void
ssh_keyfile_passphrase_free
(
struct
git_cred
*
cred
)
{
git_cred_ssh_keyfile_passphrase
*
c
=
(
git_cred_ssh_keyfile_passphrase
*
)
cred
;
size_t
pass_len
=
strlen
(
c
->
passphrase
);
if
(
c
->
publickey
)
{
git__free
(
c
->
publickey
);
}
git__free
(
c
->
privatekey
);
if
(
c
->
passphrase
)
{
/* Zero the memory which previously held the passphrase */
memset
(
c
->
passphrase
,
0x0
,
pass_len
);
git__free
(
c
->
passphrase
);
}
memset
(
c
,
0
,
sizeof
(
*
c
));
git__free
(
c
);
}
int
git_cred_ssh_keyfile_passphrase_new
(
git_cred
**
cred
,
const
char
*
publickey
,
const
char
*
privatekey
,
const
char
*
passphrase
)
{
git_cred_ssh_keyfile_passphrase
*
c
;
assert
(
cred
&&
privatekey
);
c
=
git__calloc
(
1
,
sizeof
(
git_cred_ssh_keyfile_passphrase
));
GITERR_CHECK_ALLOC
(
c
);
c
->
parent
.
credtype
=
GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE
;
c
->
parent
.
free
=
ssh_keyfile_passphrase_free
;
c
->
privatekey
=
git__strdup
(
privatekey
);
GITERR_CHECK_ALLOC
(
c
->
privatekey
);
if
(
publickey
)
{
c
->
publickey
=
git__strdup
(
publickey
);
GITERR_CHECK_ALLOC
(
c
->
publickey
);
}
if
(
passphrase
)
{
c
->
passphrase
=
git__strdup
(
passphrase
);
GITERR_CHECK_ALLOC
(
c
->
passphrase
);
}
*
cred
=
&
c
->
parent
;
return
0
;
}
static
void
ssh_publickey_free
(
struct
git_cred
*
cred
)
{
git_cred_ssh_publickey
*
c
=
(
git_cred_ssh_publickey
*
)
cred
;
git__free
(
c
->
publickey
);
c
->
sign_callback
=
NULL
;
c
->
sign_data
=
NULL
;
memset
(
c
,
0
,
sizeof
(
*
c
));
git__free
(
c
);
}
int
git_cred_ssh_publickey_new
(
git_cred
**
cred
,
const
char
*
publickey
,
size_t
publickey_len
,
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC
((
*
sign_callback
)),
void
*
sign_data
)
{
git_cred_ssh_publickey
*
c
;
if
(
!
cred
)
return
-
1
;
c
=
git__malloc
(
sizeof
(
git_cred_ssh_publickey
));
GITERR_CHECK_ALLOC
(
c
);
c
->
parent
.
credtype
=
GIT_CREDTYPE_SSH_PUBLICKEY
;
c
->
parent
.
free
=
ssh_publickey_free
;
c
->
publickey
=
git__malloc
(
publickey_len
);
GITERR_CHECK_ALLOC
(
c
->
publickey
);
memcpy
(
c
->
publickey
,
publickey
,
publickey_len
);
c
->
publickey_len
=
publickey_len
;
c
->
sign_callback
=
sign_callback
;
c
->
sign_data
=
sign_data
;
*
cred
=
&
c
->
parent
;
return
0
;
}
#endif
src/transports/ssh.c
0 → 100644
View file @
e3107e0e
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifdef GIT_SSH
#include "git2.h"
#include "buffer.h"
#include "netops.h"
#include "smart.h"
#include <libssh2.h>
#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport)
static
const
char
prefix_ssh
[]
=
"ssh://"
;
static
const
char
default_user
[]
=
"git"
;
static
const
char
cmd_uploadpack
[]
=
"git-upload-pack"
;
static
const
char
cmd_receivepack
[]
=
"git-receive-pack"
;
typedef
struct
{
git_smart_subtransport_stream
parent
;
gitno_socket
socket
;
LIBSSH2_SESSION
*
session
;
LIBSSH2_CHANNEL
*
channel
;
const
char
*
cmd
;
char
*
url
;
unsigned
sent_command
:
1
;
}
ssh_stream
;
typedef
struct
{
git_smart_subtransport
parent
;
transport_smart
*
owner
;
ssh_stream
*
current_stream
;
git_cred
*
cred
;
}
ssh_subtransport
;
/*
* Create a git protocol request.
*
* For example: git-upload-pack '/libgit2/libgit2'
*/
static
int
gen_proto
(
git_buf
*
request
,
const
char
*
cmd
,
const
char
*
url
)
{
char
*
repo
;
if
(
!
git__prefixcmp
(
url
,
prefix_ssh
))
{
url
=
url
+
strlen
(
prefix_ssh
);
repo
=
strchr
(
url
,
'/'
);
}
else
{
repo
=
strchr
(
url
,
':'
);
}
if
(
!
repo
)
{
return
-
1
;
}
int
len
=
strlen
(
cmd
)
+
1
/* Space */
+
1
/* Quote */
+
strlen
(
repo
)
+
1
/* Quote */
+
1
;
git_buf_grow
(
request
,
len
);
git_buf_printf
(
request
,
"%s '%s'"
,
cmd
,
repo
);
git_buf_putc
(
request
,
'\0'
);
if
(
git_buf_oom
(
request
))
return
-
1
;
return
0
;
}
static
int
send_command
(
ssh_stream
*
s
)
{
int
error
;
git_buf
request
=
GIT_BUF_INIT
;
error
=
gen_proto
(
&
request
,
s
->
cmd
,
s
->
url
);
if
(
error
<
0
)
goto
cleanup
;
error
=
libssh2_channel_exec
(
s
->
channel
,
request
.
ptr
);
if
(
0
!=
error
)
goto
cleanup
;
s
->
sent_command
=
1
;
cleanup:
git_buf_free
(
&
request
);
return
error
;
}
static
int
ssh_stream_read
(
git_smart_subtransport_stream
*
stream
,
char
*
buffer
,
size_t
buf_size
,
size_t
*
bytes_read
)
{
ssh_stream
*
s
=
(
ssh_stream
*
)
stream
;
*
bytes_read
=
0
;
if
(
!
s
->
sent_command
&&
send_command
(
s
)
<
0
)
return
-
1
;
int
rc
=
libssh2_channel_read
(
s
->
channel
,
buffer
,
buf_size
);
if
(
rc
<
0
)
return
-
1
;
*
bytes_read
=
rc
;
return
0
;
}
static
int
ssh_stream_write
(
git_smart_subtransport_stream
*
stream
,
const
char
*
buffer
,
size_t
len
)
{
ssh_stream
*
s
=
(
ssh_stream
*
)
stream
;
if
(
!
s
->
sent_command
&&
send_command
(
s
)
<
0
)
return
-
1
;
int
rc
=
libssh2_channel_write
(
s
->
channel
,
buffer
,
len
);
if
(
rc
<
0
)
{
return
-
1
;
}
return
rc
;
}
static
void
ssh_stream_free
(
git_smart_subtransport_stream
*
stream
)
{
ssh_stream
*
s
=
(
ssh_stream
*
)
stream
;
ssh_subtransport
*
t
=
OWNING_SUBTRANSPORT
(
s
);
int
ret
;
GIT_UNUSED
(
ret
);
t
->
current_stream
=
NULL
;
if
(
s
->
channel
)
{
libssh2_channel_close
(
s
->
channel
);
libssh2_channel_free
(
s
->
channel
);
s
->
channel
=
NULL
;
}
if
(
s
->
session
)
{
libssh2_session_free
(
s
->
session
),
s
->
session
=
NULL
;
}
if
(
s
->
socket
.
socket
)
{
ret
=
gitno_close
(
&
s
->
socket
);
assert
(
!
ret
);
}
git__free
(
s
->
url
);
git__free
(
s
);
}
static
int
ssh_stream_alloc
(
ssh_subtransport
*
t
,
const
char
*
url
,
const
char
*
cmd
,
git_smart_subtransport_stream
**
stream
)
{
ssh_stream
*
s
;
if
(
!
stream
)
return
-
1
;
s
=
git__calloc
(
sizeof
(
ssh_stream
),
1
);
GITERR_CHECK_ALLOC
(
s
);
s
->
parent
.
subtransport
=
&
t
->
parent
;
s
->
parent
.
read
=
ssh_stream_read
;
s
->
parent
.
write
=
ssh_stream_write
;
s
->
parent
.
free
=
ssh_stream_free
;
s
->
cmd
=
cmd
;
s
->
url
=
git__strdup
(
url
);
if
(
!
s
->
url
)
{
git__free
(
s
);
return
-
1
;
}
*
stream
=
&
s
->
parent
;
return
0
;
}
static
int
git_ssh_extract_url_parts
(
char
**
host
,
char
**
username
,
const
char
*
url
)
{
char
*
colon
,
*
at
;
const
char
*
start
;
colon
=
strchr
(
url
,
':'
);
if
(
colon
==
NULL
)
{
giterr_set
(
GITERR_NET
,
"Malformed URL: missing :"
);
return
-
1
;
}
at
=
strchr
(
url
,
'@'
);
if
(
at
)
{
start
=
at
+
1
;
*
username
=
git__substrdup
(
url
,
at
-
url
);
}
else
{
start
=
url
;
*
username
=
git__strdup
(
default_user
);
}
*
host
=
git__substrdup
(
start
,
colon
-
start
);
return
0
;
}
static
int
_git_ssh_authenticate_session
(
LIBSSH2_SESSION
*
session
,
const
char
*
user
,
git_cred
*
cred
)
{
int
rc
;
do
{
switch
(
cred
->
credtype
)
{
case
GIT_CREDTYPE_USERPASS_PLAINTEXT
:
{
git_cred_userpass_plaintext
*
c
=
(
git_cred_userpass_plaintext
*
)
cred
;
rc
=
libssh2_userauth_password
(
session
,
c
->
username
,
c
->
password
);
break
;
}
case
GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE
:
{
git_cred_ssh_keyfile_passphrase
*
c
=
(
git_cred_ssh_keyfile_passphrase
*
)
cred
;
rc
=
libssh2_userauth_publickey_fromfile
(
session
,
user
,
c
->
publickey
,
c
->
privatekey
,
c
->
passphrase
);
break
;
}
case
GIT_CREDTYPE_SSH_PUBLICKEY
:
{
git_cred_ssh_publickey
*
c
=
(
git_cred_ssh_publickey
*
)
cred
;
rc
=
libssh2_userauth_publickey
(
session
,
user
,
(
const
unsigned
char
*
)
c
->
publickey
,
c
->
publickey_len
,
c
->
sign_callback
,
&
c
->
sign_data
);
break
;
}
default:
rc
=
LIBSSH2_ERROR_AUTHENTICATION_FAILED
;
}
}
while
(
LIBSSH2_ERROR_EAGAIN
==
rc
||
LIBSSH2_ERROR_TIMEOUT
==
rc
);
return
rc
;
}
static
int
_git_ssh_session_create
(
LIBSSH2_SESSION
**
session
,
gitno_socket
socket
)
{
if
(
!
session
)
{
return
-
1
;
}
LIBSSH2_SESSION
*
s
=
libssh2_session_init
();
if
(
!
s
)
return
-
1
;
int
rc
=
0
;
do
{
rc
=
libssh2_session_startup
(
s
,
socket
.
socket
);
}
while
(
LIBSSH2_ERROR_EAGAIN
==
rc
||
LIBSSH2_ERROR_TIMEOUT
==
rc
);
if
(
0
!=
rc
)
{
goto
on_error
;
}
libssh2_session_set_blocking
(
s
,
1
);
*
session
=
s
;
return
0
;
on_error:
if
(
s
)
{
libssh2_session_free
(
s
),
s
=
NULL
;
}
return
-
1
;
}
static
int
_git_ssh_setup_conn
(
ssh_subtransport
*
t
,
const
char
*
url
,
const
char
*
cmd
,
git_smart_subtransport_stream
**
stream
)
{
char
*
host
,
*
port
=
NULL
,
*
user
=
NULL
,
*
pass
=
NULL
;
const
char
*
default_port
=
"22"
;
ssh_stream
*
s
;
LIBSSH2_SESSION
*
session
=
NULL
;
LIBSSH2_CHANNEL
*
channel
=
NULL
;
*
stream
=
NULL
;
if
(
ssh_stream_alloc
(
t
,
url
,
cmd
,
stream
)
<
0
)
return
-
1
;
s
=
(
ssh_stream
*
)
*
stream
;
if
(
!
git__prefixcmp
(
url
,
prefix_ssh
))
{
url
=
url
+
strlen
(
prefix_ssh
);
if
(
gitno_extract_url_parts
(
&
host
,
&
port
,
&
user
,
&
pass
,
url
,
default_port
)
<
0
)
goto
on_error
;
}
else
{
if
(
git_ssh_extract_url_parts
(
&
host
,
&
user
,
url
)
<
0
)
goto
on_error
;
port
=
git__strdup
(
default_port
);
GITERR_CHECK_ALLOC
(
port
);
}
if
(
gitno_connect
(
&
s
->
socket
,
host
,
port
,
0
)
<
0
)
goto
on_error
;
if
(
user
&&
pass
)
{
if
(
git_cred_userpass_plaintext_new
(
&
t
->
cred
,
user
,
pass
)
<
0
)
goto
on_error
;
}
else
{
if
(
t
->
owner
->
cred_acquire_cb
(
&
t
->
cred
,
t
->
owner
->
url
,
user
,
GIT_CREDTYPE_USERPASS_PLAINTEXT
|
GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE
,
t
->
owner
->
cred_acquire_payload
)
<
0
)
return
-
1
;
}
assert
(
t
->
cred
);
if
(
!
user
)
{
user
=
git__strdup
(
default_user
);
}
if
(
_git_ssh_session_create
(
&
session
,
s
->
socket
)
<
0
)
goto
on_error
;
if
(
_git_ssh_authenticate_session
(
session
,
user
,
t
->
cred
)
<
0
)
goto
on_error
;
channel
=
libssh2_channel_open_session
(
session
);
if
(
!
channel
)
goto
on_error
;
libssh2_channel_set_blocking
(
channel
,
1
);
s
->
session
=
session
;
s
->
channel
=
channel
;
t
->
current_stream
=
s
;
git__free
(
host
);
git__free
(
port
);
git__free
(
user
);
git__free
(
pass
);
return
0
;
on_error:
if
(
*
stream
)
ssh_stream_free
(
*
stream
);
git__free
(
host
);
git__free
(
port
);
git__free
(
user
);
git__free
(
pass
);
if
(
session
)
libssh2_session_free
(
session
),
session
=
NULL
;
return
-
1
;
}
static
int
ssh_uploadpack_ls
(
ssh_subtransport
*
t
,
const
char
*
url
,
git_smart_subtransport_stream
**
stream
)
{
if
(
_git_ssh_setup_conn
(
t
,
url
,
cmd_uploadpack
,
stream
)
<
0
)
return
-
1
;
return
0
;
}
static
int
ssh_uploadpack
(
ssh_subtransport
*
t
,
const
char
*
url
,
git_smart_subtransport_stream
**
stream
)
{
GIT_UNUSED
(
url
);
if
(
t
->
current_stream
)
{
*
stream
=
&
t
->
current_stream
->
parent
;
return
0
;
}
giterr_set
(
GITERR_NET
,
"Must call UPLOADPACK_LS before UPLOADPACK"
);
return
-
1
;
}
static
int
ssh_receivepack_ls
(
ssh_subtransport
*
t
,
const
char
*
url
,
git_smart_subtransport_stream
**
stream
)
{
if
(
_git_ssh_setup_conn
(
t
,
url
,
cmd_receivepack
,
stream
)
<
0
)
return
-
1
;
return
0
;
}
static
int
ssh_receivepack
(
ssh_subtransport
*
t
,
const
char
*
url
,
git_smart_subtransport_stream
**
stream
)
{
GIT_UNUSED
(
url
);
if
(
t
->
current_stream
)
{
*
stream
=
&
t
->
current_stream
->
parent
;
return
0
;
}
giterr_set
(
GITERR_NET
,
"Must call RECEIVEPACK_LS before RECEIVEPACK"
);
return
-
1
;
}
static
int
_ssh_action
(
git_smart_subtransport_stream
**
stream
,
git_smart_subtransport
*
subtransport
,
const
char
*
url
,
git_smart_service_t
action
)
{
ssh_subtransport
*
t
=
(
ssh_subtransport
*
)
subtransport
;
switch
(
action
)
{
case
GIT_SERVICE_UPLOADPACK_LS
:
return
ssh_uploadpack_ls
(
t
,
url
,
stream
);
case
GIT_SERVICE_UPLOADPACK
:
return
ssh_uploadpack
(
t
,
url
,
stream
);
case
GIT_SERVICE_RECEIVEPACK_LS
:
return
ssh_receivepack_ls
(
t
,
url
,
stream
);
case
GIT_SERVICE_RECEIVEPACK
:
return
ssh_receivepack
(
t
,
url
,
stream
);
}
*
stream
=
NULL
;
return
-
1
;
}
static
int
_ssh_close
(
git_smart_subtransport
*
subtransport
)
{
ssh_subtransport
*
t
=
(
ssh_subtransport
*
)
subtransport
;
assert
(
!
t
->
current_stream
);
GIT_UNUSED
(
t
);
return
0
;
}
static
void
_ssh_free
(
git_smart_subtransport
*
subtransport
)
{
ssh_subtransport
*
t
=
(
ssh_subtransport
*
)
subtransport
;
assert
(
!
t
->
current_stream
);
git__free
(
t
);
}
int
git_smart_subtransport_ssh
(
git_smart_subtransport
**
out
,
git_transport
*
owner
)
{
ssh_subtransport
*
t
;
if
(
!
out
)
return
-
1
;
t
=
git__calloc
(
sizeof
(
ssh_subtransport
),
1
);
GITERR_CHECK_ALLOC
(
t
);
t
->
owner
=
(
transport_smart
*
)
owner
;
t
->
parent
.
action
=
_ssh_action
;
t
->
parent
.
close
=
_ssh_close
;
t
->
parent
.
free
=
_ssh_free
;
*
out
=
(
git_smart_subtransport
*
)
t
;
return
0
;
}
#endif
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