mirror of
https://github.com/libssh2/libssh2.git
synced 2025-08-08 19:02:07 +03:00
Add libssh2_session_method_pref() and libssh2_session_methods().
Specify methods to be used and retreive what methods were negotiated.
This commit is contained in:
4
README
4
README
@@ -22,6 +22,10 @@ Version 0.2
|
|||||||
|
|
||||||
Added libssh2_session_callback_set() for setting ignore/debug/disconnect/macerror callbacks
|
Added libssh2_session_callback_set() for setting ignore/debug/disconnect/macerror callbacks
|
||||||
|
|
||||||
|
Added libssh2_session_method_pref() to selectively set methods and method preferences.
|
||||||
|
|
||||||
|
Added libssh2_session_methods() to determine what methods were negotiated.
|
||||||
|
|
||||||
Version 0.1
|
Version 0.1
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@@ -43,7 +43,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#define LIBSSH2_VERSION "0.1"
|
#define LIBSSH2_VERSION "0.1"
|
||||||
#define LIBSSH2_APINO 200412091107
|
#define LIBSSH2_APINO 200412091407
|
||||||
|
|
||||||
/* Part of every banner, user specified or not */
|
/* Part of every banner, user specified or not */
|
||||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||||
@@ -140,6 +140,18 @@
|
|||||||
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
||||||
#define LIBSSH2_CALLBACK_MACERROR 3
|
#define LIBSSH2_CALLBACK_MACERROR 3
|
||||||
|
|
||||||
|
/* libssh2_session_method_pref() constants */
|
||||||
|
#define LIBSSH2_METHOD_KEX 0
|
||||||
|
#define LIBSSH2_METHOD_HOSTKEY 1
|
||||||
|
#define LIBSSH2_METHOD_CRYPT_CS 2
|
||||||
|
#define LIBSSH2_METHOD_CRYPT_SC 3
|
||||||
|
#define LIBSSH2_METHOD_MAC_CS 4
|
||||||
|
#define LIBSSH2_METHOD_MAC_SC 5
|
||||||
|
#define LIBSSH2_METHOD_COMP_CS 6
|
||||||
|
#define LIBSSH2_METHOD_COMP_SC 7
|
||||||
|
#define LIBSSH2_METHOD_LANG_CS 8
|
||||||
|
#define LIBSSH2_METHOD_LANG_SC 9
|
||||||
|
|
||||||
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||||
|
|
||||||
@@ -214,6 +226,13 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
|
|||||||
|
|
||||||
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
||||||
|
|
||||||
|
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs);
|
||||||
|
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
|
||||||
|
char **crypt_cs, char **crypt_sc,
|
||||||
|
char **mac_cs, char **mac_sc,
|
||||||
|
char **comp_cs, char **comp_sc,
|
||||||
|
char **lang_cs, char **lang_sc);
|
||||||
|
|
||||||
/* Userauth API */
|
/* Userauth API */
|
||||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
||||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
||||||
|
@@ -135,9 +135,10 @@ typedef struct _libssh2_endpoint_data {
|
|||||||
void *comp_abstract;
|
void *comp_abstract;
|
||||||
|
|
||||||
/* Method Preferences -- NULL yields "load order" */
|
/* Method Preferences -- NULL yields "load order" */
|
||||||
LIBSSH2_CRYPT_METHOD **crypt_prefs;
|
char *crypt_prefs;
|
||||||
LIBSSH2_MAC_METHOD **mac_prefs;
|
char *mac_prefs;
|
||||||
LIBSSH2_COMP_METHOD **comp_prefs;
|
char *comp_prefs;
|
||||||
|
char *lang_prefs;
|
||||||
} libssh2_endpoint_data;
|
} libssh2_endpoint_data;
|
||||||
|
|
||||||
struct _LIBSSH2_SESSION {
|
struct _LIBSSH2_SESSION {
|
||||||
@@ -154,8 +155,8 @@ struct _LIBSSH2_SESSION {
|
|||||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||||
|
|
||||||
/* Method preferences -- NULL yields "load order" */
|
/* Method preferences -- NULL yields "load order" */
|
||||||
LIBSSH2_KEX_METHOD **kex_prefs;
|
char *kex_prefs;
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs;
|
char *hostkey_prefs;
|
||||||
|
|
||||||
int exchanging_keys;
|
int exchanging_keys;
|
||||||
int newkeys;
|
int newkeys;
|
||||||
|
312
src/kex.c
312
src/kex.c
@@ -671,16 +671,16 @@ static size_t libssh2_kex_method_list(unsigned char *buf, size_t list_strlen, LI
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
#define LIBSSH2_METHOD_PREFS \
|
#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
|
||||||
LIBSSH2_KEX_METHOD **kex_prefs = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods; \
|
#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); \
|
if (prefvar) { \
|
||||||
LIBSSH2_CRYPT_METHOD **crypt_cs_prefs = session->local.crypt_prefs ? session->local.crypt_prefs : libssh2_crypt_methods(); \
|
libssh2_htonu32((buf), (prefvarlen)); \
|
||||||
LIBSSH2_CRYPT_METHOD **crypt_sc_prefs = session->remote.crypt_prefs ? session->remote.crypt_prefs : libssh2_crypt_methods(); \
|
buf += 4; \
|
||||||
LIBSSH2_COMP_METHOD **comp_cs_prefs = session->local.comp_prefs ? session->local.comp_prefs : libssh2_comp_methods(); \
|
memcpy((buf), (prefvar), (prefvarlen)); \
|
||||||
LIBSSH2_COMP_METHOD **comp_sc_prefs = session->remote.comp_prefs ? session->remote.comp_prefs : libssh2_comp_methods(); \
|
buf += (prefvarlen); \
|
||||||
LIBSSH2_MAC_METHOD **mac_cs_prefs = session->local.mac_prefs ? session->local.mac_prefs : libssh2_mac_methods(); \
|
} else { \
|
||||||
LIBSSH2_MAC_METHOD **mac_sc_prefs = session->remote.mac_prefs ? session->remote.mac_prefs : libssh2_mac_methods();
|
buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
|
||||||
|
}
|
||||||
|
|
||||||
/* {{{ libssh2_kexinit
|
/* {{{ libssh2_kexinit
|
||||||
* Send SSH_MSG_KEXINIT packet
|
* Send SSH_MSG_KEXINIT packet
|
||||||
@@ -694,18 +694,17 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
|||||||
size_t mac_cs_len, mac_sc_len;
|
size_t mac_cs_len, mac_sc_len;
|
||||||
size_t lang_cs_len, lang_sc_len;
|
size_t lang_cs_len, lang_sc_len;
|
||||||
unsigned char *data, *s;
|
unsigned char *data, *s;
|
||||||
LIBSSH2_METHOD_PREFS
|
|
||||||
|
|
||||||
kex_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)kex_prefs);
|
kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
|
||||||
hostkey_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
hostkey_len = LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, libssh2_hostkey_methods());
|
||||||
crypt_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
crypt_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, libssh2_crypt_methods());
|
||||||
crypt_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
crypt_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||||
mac_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
mac_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, libssh2_mac_methods());
|
||||||
mac_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
mac_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, libssh2_mac_methods());
|
||||||
comp_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
comp_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, libssh2_comp_methods());
|
||||||
comp_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
comp_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, libssh2_comp_methods());
|
||||||
lang_cs_len = 0; /* No langs in this version */
|
lang_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
|
||||||
lang_sc_len = 0; /* No langs in this version */
|
lang_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
|
||||||
|
|
||||||
data_len += kex_len + hostkey_len + \
|
data_len += kex_len + hostkey_len + \
|
||||||
crypt_cs_len + crypt_sc_len + \
|
crypt_cs_len + crypt_sc_len + \
|
||||||
@@ -726,16 +725,16 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
|||||||
s += 16;
|
s += 16;
|
||||||
|
|
||||||
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
||||||
s += libssh2_kex_method_list(s, kex_len, (LIBSSH2_COMMON_METHOD**)kex_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, libssh2_kex_methods);
|
||||||
s += libssh2_kex_method_list(s, hostkey_len, (LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, libssh2_hostkey_methods());
|
||||||
s += libssh2_kex_method_list(s, crypt_cs_len, (LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, libssh2_crypt_methods());
|
||||||
s += libssh2_kex_method_list(s, crypt_sc_len, (LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||||
s += libssh2_kex_method_list(s, mac_cs_len, (LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, libssh2_mac_methods());
|
||||||
s += libssh2_kex_method_list(s, mac_sc_len, (LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, libssh2_mac_methods());
|
||||||
s += libssh2_kex_method_list(s, comp_cs_len, (LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, libssh2_comp_methods());
|
||||||
s += libssh2_kex_method_list(s, comp_sc_len, (LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, libssh2_comp_methods());
|
||||||
s += libssh2_kex_method_list(s, lang_cs_len, NULL);
|
LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, NULL);
|
||||||
s += libssh2_kex_method_list(s, lang_sc_len, NULL);
|
LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, NULL);
|
||||||
|
|
||||||
/* No optimistic KEX packet follows */
|
/* No optimistic KEX packet follows */
|
||||||
/* Deal with optimistic packets
|
/* Deal with optimistic packets
|
||||||
@@ -803,14 +802,61 @@ static unsigned char *libssh2_kex_agree_instr(unsigned char *haystack, unsigned
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_get_method_by_name
|
||||||
|
*/
|
||||||
|
static LIBSSH2_COMMON_METHOD *libssh2_get_method_by_name(char *name, int name_len, LIBSSH2_COMMON_METHOD **methodlist)
|
||||||
|
{
|
||||||
|
while (*methodlist) {
|
||||||
|
if ((strlen((*methodlist)->name) == name_len) &&
|
||||||
|
(strncmp((*methodlist)->name, name, name_len) == 0)) {
|
||||||
|
return *methodlist;
|
||||||
|
}
|
||||||
|
methodlist++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ libssh2_kex_agree_hostkey
|
/* {{{ libssh2_kex_agree_hostkey
|
||||||
* Agree on a Hostkey which works with this kex
|
* Agree on a Hostkey which works with this kex
|
||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex_flags, unsigned char *hostkey, unsigned long hostkey_len)
|
static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex_flags, unsigned char *hostkey, unsigned long hostkey_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_HOSTKEY_METHOD **hostkeyp = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods();
|
LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (session->hostkey_prefs) {
|
||||||
|
s = session->hostkey_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
|
||||||
|
LIBSSH2_HOSTKEY_METHOD *method = (LIBSSH2_HOSTKEY_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)hostkeyp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
|
||||||
|
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
|
||||||
|
(method->encrypt)) {
|
||||||
|
/* Either this hostkey can do encryption or this kex just doesn't require it */
|
||||||
|
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) == 0) ||
|
||||||
|
(method->sig_verify)) {
|
||||||
|
/* Either this hostkey can do signing or this kex just doesn't require it */
|
||||||
|
session->hostkey = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*hostkeyp)->name) {
|
while ((*hostkeyp)->name) {
|
||||||
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -839,9 +885,37 @@ static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex
|
|||||||
static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char *kex, unsigned long kex_len,
|
static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char *kex, unsigned long kex_len,
|
||||||
unsigned char *hostkey, unsigned long hostkey_len)
|
unsigned char *hostkey, unsigned long hostkey_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_KEX_METHOD **kexp = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods;
|
LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (session->kex_prefs) {
|
||||||
|
s = session->kex_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
if (libssh2_kex_agree_instr(kex, kex_len, s, method_len)) {
|
||||||
|
LIBSSH2_KEX_METHOD *method = (LIBSSH2_KEX_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)kexp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've agreed on a key exchange method,
|
||||||
|
* Can we agree on a hostkey that works with this kex?
|
||||||
|
*/
|
||||||
|
if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) {
|
||||||
|
session->kex = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (*kexp && (*kexp)->name) {
|
while (*kexp && (*kexp)->name) {
|
||||||
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
|
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -864,9 +938,33 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
|
|||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
|
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_CRYPT_METHOD **cryptp = endpoint->crypt_prefs ? endpoint->crypt_prefs : libssh2_crypt_methods();
|
LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (endpoint->crypt_prefs) {
|
||||||
|
s = endpoint->crypt_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
|
||||||
|
if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
|
||||||
|
LIBSSH2_CRYPT_METHOD *method = (LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->crypt = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*cryptp)->name) {
|
while ((*cryptp)->name) {
|
||||||
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -885,9 +983,33 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
|
|||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *mac, unsigned long mac_len)
|
static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *mac, unsigned long mac_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_MAC_METHOD **macp = endpoint->mac_prefs ? endpoint->mac_prefs : libssh2_mac_methods();
|
LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (endpoint->mac_prefs) {
|
||||||
|
s = endpoint->mac_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
|
||||||
|
if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
|
||||||
|
LIBSSH2_MAC_METHOD *method = (LIBSSH2_MAC_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)macp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->mac = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*macp)->name) {
|
while ((*macp)->name) {
|
||||||
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -906,9 +1028,33 @@ static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data
|
|||||||
*/
|
*/
|
||||||
static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, unsigned long comp_len)
|
static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, unsigned long comp_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_COMP_METHOD **compp = endpoint->comp_prefs ? endpoint->comp_prefs : libssh2_comp_methods();
|
LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
|
|
||||||
|
if (endpoint->comp_prefs) {
|
||||||
|
s = endpoint->comp_prefs;
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
unsigned char *p = strchr(s, ',');
|
||||||
|
int method_len = (p ? (p - s) : strlen(s));
|
||||||
|
|
||||||
|
if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
|
||||||
|
LIBSSH2_COMP_METHOD *method = (LIBSSH2_COMP_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)compp);
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
/* Invalid method -- Should never be reached */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint->comp = method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? p + 1 : NULL;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*compp)->name) {
|
while ((*compp)->name) {
|
||||||
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
||||||
if (s) {
|
if (s) {
|
||||||
@@ -1054,3 +1200,97 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_method_pref
|
||||||
|
* Set preferred method
|
||||||
|
*/
|
||||||
|
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs)
|
||||||
|
{
|
||||||
|
char **prefvar, *s, *newprefs;
|
||||||
|
int prefs_len = strlen(prefs);
|
||||||
|
LIBSSH2_COMMON_METHOD **mlist;
|
||||||
|
|
||||||
|
switch (method_type) {
|
||||||
|
case LIBSSH2_METHOD_KEX:
|
||||||
|
prefvar = &session->kex_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_kex_methods;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_HOSTKEY:
|
||||||
|
prefvar = &session->hostkey_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_hostkey_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_CRYPT_CS:
|
||||||
|
prefvar = &session->local.crypt_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_crypt_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_CRYPT_SC:
|
||||||
|
prefvar = &session->remote.crypt_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_crypt_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_MAC_CS:
|
||||||
|
prefvar = &session->local.mac_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_mac_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_MAC_SC:
|
||||||
|
prefvar = &session->remote.mac_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_mac_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_COMP_CS:
|
||||||
|
prefvar = &session->local.comp_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_comp_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_COMP_SC:
|
||||||
|
prefvar = &session->remote.comp_prefs;
|
||||||
|
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_comp_methods();
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_LANG_CS:
|
||||||
|
prefvar = &session->local.lang_prefs;
|
||||||
|
mlist = NULL;
|
||||||
|
break;
|
||||||
|
case LIBSSH2_METHOD_LANG_SC:
|
||||||
|
prefvar = &session->remote.lang_prefs;
|
||||||
|
mlist = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
|
||||||
|
if (!newprefs) {
|
||||||
|
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Error allocated space for method preferences", 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(s, prefs, prefs_len + 1);
|
||||||
|
|
||||||
|
while (s && *s) {
|
||||||
|
char *p = strchr(s, ',');
|
||||||
|
int method_len = p ? (p - s) : strlen(s);
|
||||||
|
|
||||||
|
if (!libssh2_get_method_by_name(s, method_len, mlist)) {
|
||||||
|
/* Strip out unsupported method */
|
||||||
|
if (p) {
|
||||||
|
memcpy(s, p + 1, strlen(s) - method_len);
|
||||||
|
} else {
|
||||||
|
if (s > newprefs) {
|
||||||
|
*(--s) = '\0';
|
||||||
|
} else {
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = p ? (p + 1) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(newprefs) == 0) {
|
||||||
|
LIBSSH2_FREE(session, newprefs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*prefvar) {
|
||||||
|
LIBSSH2_FREE(session, *prefvar);
|
||||||
|
}
|
||||||
|
*prefvar = newprefs;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
@@ -338,6 +338,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free banner(s) */
|
||||||
if (session->remote.banner) {
|
if (session->remote.banner) {
|
||||||
LIBSSH2_FREE(session, session->remote.banner);
|
LIBSSH2_FREE(session, session->remote.banner);
|
||||||
}
|
}
|
||||||
@@ -345,6 +346,40 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
|||||||
LIBSSH2_FREE(session, session->local.banner);
|
LIBSSH2_FREE(session, session->local.banner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free preference(s) */
|
||||||
|
if (session->kex_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->kex_prefs);
|
||||||
|
}
|
||||||
|
if (session->hostkey_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->hostkey_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->local.crypt_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.crypt_prefs);
|
||||||
|
}
|
||||||
|
if (session->local.mac_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.mac_prefs);
|
||||||
|
}
|
||||||
|
if (session->local.comp_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.comp_prefs);
|
||||||
|
}
|
||||||
|
if (session->local.lang_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->local.lang_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->remote.crypt_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.crypt_prefs);
|
||||||
|
}
|
||||||
|
if (session->remote.mac_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.mac_prefs);
|
||||||
|
}
|
||||||
|
if (session->remote.comp_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.comp_prefs);
|
||||||
|
}
|
||||||
|
if (session->remote.lang_prefs) {
|
||||||
|
LIBSSH2_FREE(session, session->remote.lang_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
/* Cleanup any remaining packets */
|
/* Cleanup any remaining packets */
|
||||||
while (session->packets.head) {
|
while (session->packets.head) {
|
||||||
LIBSSH2_PACKET *tmp = session->packets.head;
|
LIBSSH2_PACKET *tmp = session->packets.head;
|
||||||
@@ -405,3 +440,47 @@ LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int rea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ libssh2_session_methods
|
||||||
|
* Return the currently active methods
|
||||||
|
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
|
||||||
|
* Strings should NOT be freed
|
||||||
|
*/
|
||||||
|
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
|
||||||
|
char **crypt_cs, char **crypt_sc,
|
||||||
|
char **mac_cs, char **mac_sc,
|
||||||
|
char **comp_cs, char **comp_sc,
|
||||||
|
char **lang_cs, char **lang_sc)
|
||||||
|
{
|
||||||
|
if (kex) {
|
||||||
|
*kex = session->kex->name;
|
||||||
|
}
|
||||||
|
if (hostkey) {
|
||||||
|
*hostkey = session->hostkey->name;
|
||||||
|
}
|
||||||
|
if (crypt_cs) {
|
||||||
|
*crypt_cs = session->local.crypt->name;
|
||||||
|
}
|
||||||
|
if (crypt_sc) {
|
||||||
|
*crypt_sc = session->remote.crypt->name;
|
||||||
|
}
|
||||||
|
if (mac_cs) {
|
||||||
|
*mac_cs = session->local.mac->name;
|
||||||
|
}
|
||||||
|
if (mac_sc) {
|
||||||
|
*mac_sc = session->remote.mac->name;
|
||||||
|
}
|
||||||
|
if (comp_cs) {
|
||||||
|
*comp_cs = session->local.comp->name;
|
||||||
|
}
|
||||||
|
if (comp_sc) {
|
||||||
|
*comp_sc = session->remote.comp->name;
|
||||||
|
}
|
||||||
|
if (lang_cs) {
|
||||||
|
*lang_cs = "";
|
||||||
|
}
|
||||||
|
if (lang_sc) {
|
||||||
|
*lang_sc = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
Reference in New Issue
Block a user