My knownhost work as of right now. It works at least partly. More tests and
tweaks will come.
This commit is contained in:
parent
4bc1b8a1d7
commit
4b991b232d
28
NEWS
28
NEWS
@ -1,3 +1,31 @@
|
||||
* (May 7 2009) Daniel Stenberg:
|
||||
|
||||
- linked list code. I got a bit tired of the fact that we don't have any
|
||||
generic linked-list functions within libssh2 so I wrote up the first embryo
|
||||
for one that I use for this new functionality. The plan would then be to
|
||||
move all existing code that uses linked lists to use this new set.
|
||||
|
||||
- base64 encode. I had to add a base64 encoding function which was missing
|
||||
in the code base so it helps to "bloat" my patch.
|
||||
|
||||
- The knownhost API is currently:
|
||||
|
||||
_init() - init a bundle of known hosts
|
||||
_add() - add a known host
|
||||
_del() - delete a known host
|
||||
_free() - free an entire bundle of known hosts
|
||||
_check() - check if a host+key is present in the bundle
|
||||
|
||||
The convenience function:
|
||||
|
||||
_parsefile() - reads a ~/.ssh/known_hosts file and add all entries to the
|
||||
given bundle
|
||||
|
||||
- there's no docs other than some comments in the code/headers yet
|
||||
|
||||
- the patch includes changes to example/simple/ssh2_exec.c that makes use of
|
||||
a few of these functions. Using that I've verified that the functions in
|
||||
fact can verify my localhost's key agains my ~/.ssh/known_hosts file
|
||||
|
||||
* (Apr 30 2009) Daniel Stenberg:
|
||||
|
||||
|
5
TODO
5
TODO
@ -28,3 +28,8 @@ At next SONAME bump
|
||||
libssh2_channel_receive_window_adjust()
|
||||
libssh2_poll()
|
||||
libssh2_poll_channel_read()
|
||||
|
||||
* Rename a few function:
|
||||
|
||||
libssh2_hostkey_hash => libssh2_session_hostkey_hash
|
||||
libssh2_banner_set => libssh2_session_banner_set
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: ssh2_exec.c,v 1.2 2009/05/05 12:30:19 bagder Exp $
|
||||
* $Id: ssh2_exec.c,v 1.3 2009/05/07 13:09:49 bagder Exp $
|
||||
*
|
||||
* Sample showing how to use libssh2 to execute a command remotely.
|
||||
*
|
||||
@ -26,7 +26,6 @@
|
||||
|
||||
#include <libssh2.h>
|
||||
|
||||
|
||||
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
|
||||
{
|
||||
struct timeval timeout;
|
||||
@ -59,11 +58,12 @@ static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *hostname = "127.0.0.1";
|
||||
const char *commandline = "uptime";
|
||||
const char *username = "user";
|
||||
const char *password = "password";
|
||||
unsigned long hostaddr;
|
||||
int sock, i;
|
||||
int sock;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
@ -71,16 +71,17 @@ int main(int argc, char *argv[])
|
||||
int rc;
|
||||
int exitcode;
|
||||
int bytecount = 0;
|
||||
size_t len;
|
||||
LIBSSH2_KNOWNHOSTS *nh;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(MAKEWORD(2,0), &wsadata);
|
||||
#endif
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
if (argc > 1)
|
||||
/* must be ip address only */
|
||||
hostname = argv[1];
|
||||
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
@ -91,6 +92,8 @@ int main(int argc, char *argv[])
|
||||
commandline = argv[4];
|
||||
}
|
||||
|
||||
hostaddr = inet_addr(hostname);
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the
|
||||
* connection
|
||||
@ -141,17 +144,25 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
fprintf(stderr, "Fingerprint: ");
|
||||
for(i = 0; i < 16; i++) {
|
||||
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
|
||||
nh = libssh2_knownhost_init(session);
|
||||
|
||||
libssh2_knownhost_parsefile(nh, "/home/daniel/.ssh/known_hosts",
|
||||
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
|
||||
|
||||
fingerprint = libssh2_session_hostkey(session, &len);
|
||||
if(fingerprint) {
|
||||
struct libssh2_knownhost host;
|
||||
int check;
|
||||
|
||||
check = libssh2_knownhost_check(nh, (char *)hostname,
|
||||
(char *)fingerprint, len,
|
||||
LIBSSH2_KNOWNHOST_TYPE_DEFAULT, &host);
|
||||
|
||||
fprintf(stderr, "Host check: %d, key: %s\n", check,
|
||||
(check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
|
||||
host.key:"<none>");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
libssh2_knownhost_free(nh);
|
||||
|
||||
if ( strlen(password) != 0 ) {
|
||||
/* We could authenticate via password */
|
||||
|
@ -240,6 +240,7 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
|
||||
typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS;
|
||||
|
||||
typedef struct _LIBSSH2_POLLFD {
|
||||
unsigned char type; /* LIBSSH2_POLLFD_* below */
|
||||
@ -348,6 +349,7 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
|
||||
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
|
||||
#define LIBSSH2_ERROR_EAGAIN -37
|
||||
#define LIBSSH2_ERROR_MEMORY -38
|
||||
|
||||
/* Session API */
|
||||
LIBSSH2_API LIBSSH2_SESSION *
|
||||
@ -377,6 +379,9 @@ LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session,
|
||||
int hash_type);
|
||||
|
||||
LIBSSH2_API const char *libssh2_session_hostkey(LIBSSH2_SESSION *session,
|
||||
size_t *len);
|
||||
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session,
|
||||
int method_type,
|
||||
const char *prefs);
|
||||
@ -664,6 +669,131 @@ LIBSSH2_API
|
||||
const char *libssh2_version(int req_version_num);
|
||||
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_init
|
||||
*
|
||||
* Init a collection of known hosts. Returns the pointer to a collection.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_KNOWNHOSTS *
|
||||
libssh2_knownhost_init(LIBSSH2_SESSION *session);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_add
|
||||
*
|
||||
* Add a host and its associated key to the collection of known hosts.
|
||||
*
|
||||
* The 'type' argument specifies on what format the given host is:
|
||||
*
|
||||
* plain - ascii "hostname.domain.tld"
|
||||
* sha1 - SHA1(<salt> <host>) base64-encoded!
|
||||
* custom - another hash
|
||||
*
|
||||
* If 'sha1' is selected as type, the salt must be provided to the salt
|
||||
* argument. This too base64 encoded.
|
||||
*
|
||||
* The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If
|
||||
* a custom type is used, salt is ignored and you must provide the host
|
||||
* pre-hashed when checking for it in the libssh2_knownhost_check() function.
|
||||
*
|
||||
*/
|
||||
|
||||
#define LIBSSH2_KNOWNHOST_TYPE_DEFAULT (LIBSSH2_KNOWNHOST_TYPE_PLAIN | \
|
||||
LIBSSH2_KNOWNHOST_KEY_RAW)
|
||||
|
||||
/* host format (2 bits) */
|
||||
#define LIBSSH2_KNOWNHOST_TYPE_MASK 0xffff
|
||||
#define LIBSSH2_KNOWNHOST_TYPE_PLAIN 1
|
||||
#define LIBSSH2_KNOWNHOST_TYPE_SHA1 2 /* always base64 encoded */
|
||||
#define LIBSSH2_KNOWNHOST_TYPE_CUSTOM 3
|
||||
|
||||
/* key format (2 bits) */
|
||||
#define LIBSSH2_KNOWNHOST_KEY_RAW (1<<16)
|
||||
#define LIBSSH2_KNOWNHOST_KEY_BASE64 (2<<16)
|
||||
|
||||
/* type of key (2 bits) */
|
||||
#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18)
|
||||
#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18)
|
||||
#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18)
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, char *host, char *salt,
|
||||
char *key, size_t keylen, int typemask);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_check
|
||||
*
|
||||
* Check a host and its associated key against the collection of known hosts.
|
||||
*
|
||||
* The type is the type/format of the given host name.
|
||||
*
|
||||
* plain - ascii "hostname.domain.tld"
|
||||
* custom - prehashed base64 encoded. Note that this cannot use any salts.
|
||||
*
|
||||
*
|
||||
* 'knownhost' may be set to NULL if you don't care about that info.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* LIBSSH2_KNOWNHOST_CHECK_* values, see below
|
||||
*
|
||||
*/
|
||||
struct libssh2_knownhost {
|
||||
unsigned int magic; /* magic stored by the library */
|
||||
void *node; /* handle to the internal representation of this host */
|
||||
char *name; /* this is NULL if no plain text host name exists */
|
||||
char *key; /* key in base64/printable format */
|
||||
int typemask;
|
||||
};
|
||||
|
||||
#define LIBSSH2_KNOWNHOST_CHECK_MATCH 0
|
||||
#define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1
|
||||
#define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2
|
||||
#define LIBSSH2_KNOWNHOST_CHECK_FAILURE 3
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
char *host, char *key, size_t keylen,
|
||||
int typemask,
|
||||
struct libssh2_knownhost *knownhost);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_del
|
||||
*
|
||||
* Remove a host from the collection of known hosts. The 'entry' struct is
|
||||
* retrieved by a call to libssh2_knownhost_check().
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
struct libssh2_knownhost *entry);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_free
|
||||
*
|
||||
* Free an entire collection of known hosts.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API void
|
||||
libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_parsefile
|
||||
*
|
||||
* Add hosts+key pairs from a given file.
|
||||
*
|
||||
* Returns a negative value for error or number of successfully added hosts.
|
||||
*
|
||||
* This implementation currently only knows one type, all others are reserved
|
||||
* for future use.
|
||||
*/
|
||||
|
||||
#define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_parsefile(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *filename, int type);
|
||||
|
||||
/* NOTE NOTE NOTE
|
||||
libssh2_trace() has no function in builds that aren't built with debug
|
||||
enabled
|
||||
|
@ -1,9 +1,10 @@
|
||||
# $Id: Makefile.am,v 1.19 2009/03/26 22:25:23 bagder Exp $
|
||||
# $Id: Makefile.am,v 1.20 2009/05/07 13:09:49 bagder Exp $
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
|
||||
packet.c publickey.c scp.c session.c sftp.c userauth.c libssh2_priv.h \
|
||||
openssl.h libgcrypt.h transport.c version.c transport.h channel.h comp.h mac.h
|
||||
libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
|
||||
packet.c publickey.c scp.c session.c sftp.c userauth.c libssh2_priv.h \
|
||||
openssl.h libgcrypt.h transport.c version.c transport.h channel.h comp.h \
|
||||
mac.h misc.h
|
||||
|
||||
if LIBGCRYPT
|
||||
libssh2_la_SOURCES += libgcrypt.c pem.c
|
||||
|
542
src/hostkey.c
542
src/hostkey.c
@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009 by Daniel Stenberg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@ -35,7 +36,9 @@
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2.h"
|
||||
#include "libssh2_priv.h"
|
||||
#include "misc.h"
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
@ -453,3 +456,542 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_host(LIBSSH2_SESSION *session, struct known_host *entry)
|
||||
{
|
||||
if(entry) {
|
||||
if(entry->key)
|
||||
LIBSSH2_FREE(session, entry->key);
|
||||
if(entry->salt)
|
||||
LIBSSH2_FREE(session, entry->salt);
|
||||
if(entry->name)
|
||||
LIBSSH2_FREE(session, entry->name);
|
||||
LIBSSH2_FREE(session, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_session_hostkey()
|
||||
*
|
||||
* Returns the server key and length.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API const char *
|
||||
libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len)
|
||||
{
|
||||
if(session->server_hostkey_len) {
|
||||
if(len)
|
||||
*len = session->server_hostkey_len;
|
||||
return (char *) session->server_hostkey;
|
||||
}
|
||||
if(len)
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_init
|
||||
*
|
||||
* Init a collection of known hosts. Returns the pointer to a collection.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_KNOWNHOSTS *
|
||||
libssh2_knownhost_init(LIBSSH2_SESSION *session)
|
||||
{
|
||||
LIBSSH2_KNOWNHOSTS *knh =
|
||||
LIBSSH2_ALLOC(session, sizeof(struct _LIBSSH2_KNOWNHOSTS));
|
||||
|
||||
if(!knh)
|
||||
return NULL;
|
||||
|
||||
knh->session = session;
|
||||
|
||||
_libssh2_list_init(&knh->head);
|
||||
|
||||
return knh;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_add
|
||||
*
|
||||
* Add a host and its associated key to the collection of known hosts.
|
||||
*
|
||||
* The 'type' argument specifies on what format the given host and keys are:
|
||||
*
|
||||
* plain - ascii "hostname.domain.tld"
|
||||
* sha1 - SHA1(<salt> <host>) base64-encoded!
|
||||
* custom - another hash
|
||||
*
|
||||
* If 'sha1' is selected as type, the salt must be provided to the salt
|
||||
* argument. This too base64 encoded.
|
||||
*
|
||||
* The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If
|
||||
* a custom type is used, salt is ignored and you must provide the host
|
||||
* pre-hashed when checking for it in the libssh2_knownhost_check() function.
|
||||
*
|
||||
*/
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
char *host, char *salt,
|
||||
char *key, size_t keylen,
|
||||
int typemask)
|
||||
{
|
||||
struct known_host *entry =
|
||||
LIBSSH2_ALLOC(hosts->session, sizeof(struct known_host));
|
||||
size_t hostlen = strlen(host);
|
||||
int rc = LIBSSH2_ERROR_MEMORY;
|
||||
char *ptr;
|
||||
unsigned int ptrlen;
|
||||
|
||||
if(!entry)
|
||||
return rc;
|
||||
|
||||
memset(entry, 0, sizeof(struct known_host));
|
||||
|
||||
entry->typemask = typemask;
|
||||
|
||||
switch(entry->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) {
|
||||
case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
|
||||
case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
|
||||
entry->name = LIBSSH2_ALLOC(hosts->session, hostlen+1);
|
||||
if(!entry)
|
||||
goto error;
|
||||
memcpy(entry->name, host, hostlen+1);
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_TYPE_SHA1:
|
||||
rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen,
|
||||
host, hostlen);
|
||||
if(rc)
|
||||
goto error;
|
||||
entry->name = ptr;
|
||||
entry->name_len = ptrlen;
|
||||
|
||||
rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen,
|
||||
salt, strlen(salt));
|
||||
if(rc)
|
||||
goto error;
|
||||
entry->salt = ptr;
|
||||
entry->salt_len = ptrlen;
|
||||
break;
|
||||
default:
|
||||
rc = LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(typemask & LIBSSH2_KNOWNHOST_KEY_BASE64) {
|
||||
/* the provided key is base64 encoded already */
|
||||
if(!keylen)
|
||||
keylen = strlen(key);
|
||||
entry->key = LIBSSH2_ALLOC(hosts->session, keylen+1);
|
||||
if(!entry)
|
||||
goto error;
|
||||
memcpy(entry->key, key, keylen+1);
|
||||
}
|
||||
else {
|
||||
/* key is raw, we base64 encode it and store it as such */
|
||||
size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
|
||||
&ptr);
|
||||
if(!nlen)
|
||||
goto error;
|
||||
|
||||
entry->key = ptr;
|
||||
}
|
||||
|
||||
/* add this new host to the big list of known hosts */
|
||||
_libssh2_list_add(&hosts->head, &entry->node);
|
||||
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
error:
|
||||
free_host(hosts->session, entry);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define KNOWNHOST_MAGIC 0xdeadcafe
|
||||
/*
|
||||
* knownhost_to_external()
|
||||
*
|
||||
* Copies data from the internal to the external representation struct.
|
||||
*
|
||||
*/
|
||||
static void knownhost_to_external(struct known_host *node,
|
||||
struct libssh2_knownhost *ext)
|
||||
{
|
||||
if(ext) {
|
||||
ext->magic = KNOWNHOST_MAGIC;
|
||||
ext->node = node;
|
||||
ext->name = ((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) ==
|
||||
LIBSSH2_KNOWNHOST_TYPE_PLAIN)? node->name:NULL;
|
||||
ext->key = node->key;
|
||||
ext->typemask = node->typemask;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_check
|
||||
*
|
||||
* Check a host and its associated key against the collection of known hosts.
|
||||
*
|
||||
* The typemask is the type/format of the given host name and key
|
||||
*
|
||||
* plain - ascii "hostname.domain.tld"
|
||||
* sha1 - NOT SUPPORTED AS INPUT
|
||||
* custom - prehashed base64 encoded. Note that this cannot use any salts.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* LIBSSH2_KNOWNHOST_CHECK_FAILURE
|
||||
* LIBSSH2_KNOWNHOST_CHECK_NOTFOUND
|
||||
* LIBSSH2_KNOWNHOST_CHECK_MATCH
|
||||
* LIBSSH2_KNOWNHOST_CHECK_MISMATCH
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
char *host, char *key, size_t keylen,
|
||||
int typemask,
|
||||
struct libssh2_knownhost *knownhost)
|
||||
{
|
||||
struct known_host *node = _libssh2_list_first(&hosts->head);
|
||||
struct known_host *badkey = NULL;
|
||||
int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK;
|
||||
char *keyalloc = NULL;
|
||||
int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND;
|
||||
|
||||
if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1)
|
||||
/* we can't work with a sha1 as given input */
|
||||
return LIBSSH2_KNOWNHOST_CHECK_MISMATCH;
|
||||
|
||||
if(!(typemask & LIBSSH2_KNOWNHOST_KEY_BASE64)) {
|
||||
/* we got a raw key input, convert it to base64 for the checks below */
|
||||
size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
|
||||
&keyalloc);
|
||||
if(!nlen)
|
||||
return LIBSSH2_KNOWNHOST_CHECK_FAILURE;
|
||||
|
||||
/* make the key point to this */
|
||||
key = keyalloc;
|
||||
keylen = nlen;
|
||||
}
|
||||
|
||||
while (node) {
|
||||
int match = 0;
|
||||
switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) {
|
||||
case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
|
||||
if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN)
|
||||
match = !strcmp(host, node->name);
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
|
||||
if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM)
|
||||
match = !strcmp(host, node->name);
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_TYPE_SHA1:
|
||||
if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) {
|
||||
/* when we have the sha1 version stored, we can use a plain
|
||||
input to produce a hash to compare with the stored hash.
|
||||
|
||||
HMAC_Init(&mac_ctx, salt, len, md);
|
||||
HMAC_Update(&mac_ctx, host, strlen(host));
|
||||
HMAC_Final(&mac_ctx, result, NULL);
|
||||
HMAC_cleanup(&mac_ctx);
|
||||
|
||||
*/
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
|
||||
if(SHA_DIGEST_LENGTH != node->name_len) {
|
||||
/* the name hash length must be the sha1 size or
|
||||
we can't match it */
|
||||
break;
|
||||
}
|
||||
libssh2_hmac_sha1_init(&ctx, node->salt, node->salt_len);
|
||||
libssh2_hmac_update(ctx, (unsigned char *)host, strlen(host));
|
||||
libssh2_hmac_final(ctx, hash);
|
||||
libssh2_hmac_cleanup(&ctx);
|
||||
|
||||
if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH))
|
||||
/* this is a node we're interested in */
|
||||
match = 1;
|
||||
}
|
||||
break;
|
||||
default: /* unsupported type */
|
||||
break;
|
||||
}
|
||||
if(match) {
|
||||
/* host name match, now compare the keys */
|
||||
if(!strcmp(key, node->key)) {
|
||||
/* they match! */
|
||||
knownhost_to_external(node, knownhost);
|
||||
badkey = NULL;
|
||||
rc = LIBSSH2_KNOWNHOST_CHECK_MATCH;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* remember the first node that had a host match but a failed
|
||||
key match since we continue our search from here */
|
||||
if(!badkey)
|
||||
badkey = node;
|
||||
}
|
||||
}
|
||||
node= _libssh2_list_next(&node->node);
|
||||
}
|
||||
|
||||
if(badkey) {
|
||||
/* key mismatch */
|
||||
knownhost_to_external(badkey, knownhost);
|
||||
rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH;
|
||||
}
|
||||
|
||||
if(keyalloc)
|
||||
LIBSSH2_FREE(hosts->session, keyalloc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_del
|
||||
*
|
||||
* Remove a host from the collection of known hosts.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
struct libssh2_knownhost *entry)
|
||||
{
|
||||
struct known_host *node;
|
||||
if(!entry || (entry->magic != KNOWNHOST_MAGIC))
|
||||
/* check that this was retrieved the right way or get out */
|
||||
return -1;
|
||||
|
||||
/* get the internal node pointer */
|
||||
node = entry->node;
|
||||
|
||||
/* unlink from the list of all hosts */
|
||||
_libssh2_list_remove(&node->node);
|
||||
|
||||
/* free all resources */
|
||||
free_host(hosts->session, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_free
|
||||
*
|
||||
* Free an entire collection of known hosts.
|
||||
*
|
||||
*/
|
||||
LIBSSH2_API void
|
||||
libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts)
|
||||
{
|
||||
struct known_host *node;
|
||||
struct known_host *next;
|
||||
|
||||
for(node = _libssh2_list_first(&hosts->head); node; node = next) {
|
||||
next = _libssh2_list_next(&node->node);
|
||||
free_host(hosts->session, node);
|
||||
}
|
||||
LIBSSH2_FREE(hosts->session, hosts);
|
||||
}
|
||||
|
||||
/*
|
||||
* hostline()
|
||||
*
|
||||
* Parse a single known_host line pre-split into host and key.
|
||||
*
|
||||
* Note: this function assumes that the 'host' pointer points into a temporary
|
||||
* buffer as it will write to it.
|
||||
*/
|
||||
static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
char *host, size_t hostlen,
|
||||
char *key, size_t keylen)
|
||||
{
|
||||
char *p;
|
||||
char *salt = NULL;
|
||||
int rc;
|
||||
int type = LIBSSH2_KNOWNHOST_TYPE_PLAIN;
|
||||
char *sep = NULL;
|
||||
|
||||
/* Figure out host format */
|
||||
if(strncmp(host, "|1|", 3)) {
|
||||
/* old style plain text: [name][,][ip-address]
|
||||
|
||||
for the sake of simplicity, we add them as two hosts with the same
|
||||
key
|
||||
*/
|
||||
sep = strchr(host, ',');
|
||||
}
|
||||
else {
|
||||
/* |1|[salt]|[hash] */
|
||||
type = LIBSSH2_KNOWNHOST_TYPE_SHA1;
|
||||
|
||||
salt = &host[3]; /* skip the magic marker */
|
||||
|
||||
/* this is where the salt starts, find the end of it */
|
||||
for(p = salt; *p && (*p != '|'); p++)
|
||||
;
|
||||
|
||||
if(*p=='|') {
|
||||
char *hash = NULL;
|
||||
*p=0; /* terminate the salt string */
|
||||
hash = p+1; /* the hash is after the separator */
|
||||
|
||||
/* now make the host point to the hash */
|
||||
hostlen = strlen(hash);
|
||||
host = hash;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(keylen < 20)
|
||||
return -1; /* TODO: better return code */
|
||||
|
||||
switch(key[0]) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
type |= LIBSSH2_KNOWNHOST_KEY_RSA1;
|
||||
|
||||
/* Note that the old-style keys (RSA1) aren't truly base64, but we
|
||||
* claim it is for now since we can get away with strcmp()ing the
|
||||
* entire anything anyway! We need to check and fix these to make them
|
||||
* work properly.
|
||||
*/
|
||||
break;
|
||||
|
||||
case 's': /* ssh-dss or ssh-rsa */
|
||||
if(!strncmp(key, "ssh-dss", 7))
|
||||
type |= LIBSSH2_KNOWNHOST_KEY_SSHDSS;
|
||||
else if(!strncmp(key, "ssh-rsa", 7))
|
||||
type |= LIBSSH2_KNOWNHOST_KEY_SSHRSA;
|
||||
else
|
||||
return -1; /* unknown */
|
||||
|
||||
key += 7;
|
||||
keylen -= 7;
|
||||
|
||||
/* skip whitespaces */
|
||||
while((*key ==' ') || (*key == '\t')) {
|
||||
key++;
|
||||
keylen--;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* unknown key format */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(sep) {
|
||||
/* this is the second host, add this first */
|
||||
char *ipaddr;
|
||||
*sep++ = 0; /* zero terminate the first host name here */
|
||||
ipaddr = sep;
|
||||
rc = libssh2_knownhost_add(hosts, ipaddr, salt, key, keylen,
|
||||
type | LIBSSH2_KNOWNHOST_KEY_BASE64);
|
||||
if(rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = libssh2_knownhost_add(hosts, host, salt, key, keylen,
|
||||
type | LIBSSH2_KNOWNHOST_KEY_BASE64);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_parsefile
|
||||
*
|
||||
* Add hosts+key pairs from a given file.
|
||||
*
|
||||
* Returns a negative value for error or number of successfully added hosts.
|
||||
*
|
||||
* Line format:
|
||||
*
|
||||
* <host> <key>
|
||||
*
|
||||
* Where the two parts can be created like:
|
||||
*
|
||||
* <host> can be either
|
||||
* <name> or <hash>
|
||||
*
|
||||
* <name> consists of
|
||||
* [name,address] or just [name] or just [address]
|
||||
*
|
||||
* <hash> consists of
|
||||
* |1|<salt>|hash
|
||||
*
|
||||
* <key> can be one of:
|
||||
* [RSA bits] [e] [n as a decimal number]
|
||||
* 'ssh-dss' [base64-encoded-key]
|
||||
* 'ssh-rsa' [base64-encoded-key]
|
||||
*
|
||||
*/
|
||||
|
||||
#define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_parsefile(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *filename, int type)
|
||||
{
|
||||
FILE *file;
|
||||
int num = 0;
|
||||
char buf[2048];
|
||||
|
||||
if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
|
||||
return -1;
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if(file) {
|
||||
char *cp;
|
||||
char *hostp;
|
||||
char *key;
|
||||
size_t hostlen;
|
||||
|
||||
while(fgets(buf, sizeof(buf), file)) {
|
||||
cp = buf;
|
||||
|
||||
/* skip leading whitespaces */
|
||||
while((*cp==' ') || (*cp == '\t'))
|
||||
cp++;
|
||||
|
||||
if(!*cp || (*cp == '#') || (*cp == '\n'))
|
||||
/* comment or empty line */
|
||||
continue;
|
||||
|
||||
/* the host part starts here */
|
||||
hostp = cp;
|
||||
|
||||
/* move over the host to the separator */
|
||||
while(*cp && (*cp!=' ') && (*cp != '\t'))
|
||||
cp++;
|
||||
|
||||
hostlen = cp - hostp;
|
||||
|
||||
*cp++ = 0; /* terminate the host string here */
|
||||
|
||||
/* the key starts after the whitespaces */
|
||||
while(*cp && ((*cp==' ') || (*cp == '\t')))
|
||||
cp++;
|
||||
|
||||
if(!*cp)
|
||||
/* illegal line */
|
||||
continue;
|
||||
|
||||
key = cp; /* the key starts here */
|
||||
|
||||
while(*cp && (*cp != '\n'))
|
||||
cp++;
|
||||
|
||||
/* zero terminate where the newline is */
|
||||
if(*cp == '\n')
|
||||
*cp = 0;
|
||||
|
||||
/* deal with this one host+key line */
|
||||
if(!hostline(hosts, hostp, hostlen, key, strlen(key)))
|
||||
num++;
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return num;
|
||||
}
|
||||
|
17
src/kex.c
17
src/kex.c
@ -158,7 +158,7 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
|
||||
if (exchange_state->state == libssh2_NB_state_sent) {
|
||||
if (session->burn_optimistic_kexinit) {
|
||||
/* The first KEX packet to come along will be the guess initially
|
||||
/* The first KEX packet to come along will be the guess initially
|
||||
* sent by the server. That guess turned out to be wrong so we
|
||||
* need to silently ignore it */
|
||||
int burn_type;
|
||||
@ -445,12 +445,12 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
ret = -1;
|
||||
goto clean_exit;
|
||||
}
|
||||
/* The first key exchange has been performed,
|
||||
/* The first key exchange has been performed,
|
||||
switch to active crypt/comp/mac mode */
|
||||
session->state |= LIBSSH2_STATE_NEWKEYS;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
|
||||
|
||||
/* This will actually end up being just packet_type(1)
|
||||
/* This will actually end up being just packet_type(1)
|
||||
for this packet type anyway */
|
||||
LIBSSH2_FREE(session, exchange_state->tmp);
|
||||
|
||||
@ -641,11 +641,6 @@ kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session,
|
||||
exchange_state->k_value = NULL;
|
||||
}
|
||||
|
||||
if (session->server_hostkey) {
|
||||
LIBSSH2_FREE(session, session->server_hostkey);
|
||||
session->server_hostkey = NULL;
|
||||
}
|
||||
|
||||
exchange_state->state = libssh2_NB_state_idle;
|
||||
|
||||
return ret;
|
||||
@ -1013,7 +1008,7 @@ kex_method_list(unsigned char *buf, size_t list_strlen,
|
||||
*/
|
||||
static int kexinit(LIBSSH2_SESSION * session)
|
||||
{
|
||||
/* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) +
|
||||
/* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) +
|
||||
reserved(4) + length longs(40) */
|
||||
size_t data_len = 62;
|
||||
size_t kex_len, hostkey_len = 0;
|
||||
@ -1069,8 +1064,8 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
libssh2_random(s, 16);
|
||||
s += 16;
|
||||
|
||||
/* Ennumerating through these lists twice is probably (certainly?)
|
||||
inefficient from a CPU standpoint, but it saves multiple
|
||||
/* Ennumerating through these lists twice is probably (certainly?)
|
||||
inefficient from a CPU standpoint, but it saves multiple
|
||||
malloc/realloc calls */
|
||||
LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs,
|
||||
libssh2_kex_methods);
|
||||
|
@ -922,7 +922,44 @@ struct _LIBSSH2_SESSION
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
|
||||
#endif
|
||||
|
||||
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
|
||||
/* -------- */
|
||||
|
||||
/* First take towards a generic linked list handling code for libssh2
|
||||
internals */
|
||||
|
||||
struct list_head {
|
||||
struct list_node *last;
|
||||
struct list_node *first;
|
||||
};
|
||||
|
||||
struct list_node {
|
||||
struct list_node *next;
|
||||
struct list_node *prev;
|
||||
struct list_head *head;
|
||||
};
|
||||
|
||||
/* --------- */
|
||||
|
||||
struct known_host {
|
||||
struct list_node node;
|
||||
char *name; /* points to the name or the hash (allocated) */
|
||||
size_t name_len; /* needed for hashed data */
|
||||
int typemask; /* plain, sha1, custom, ... */
|
||||
char *salt; /* points to binary salt (allocated) */
|
||||
size_t salt_len; /* size of salt */
|
||||
char *key; /* the (allocated) associated key. This is kept base64
|
||||
encoded in memory. */
|
||||
};
|
||||
|
||||
struct _LIBSSH2_KNOWNHOSTS
|
||||
{
|
||||
LIBSSH2_SESSION *session; /* the session this "belongs to" */
|
||||
struct list_head head;
|
||||
};
|
||||
|
||||
|
||||
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional
|
||||
methods via .so/.dll */
|
||||
|
||||
struct _LIBSSH2_KEX_METHOD
|
||||
{
|
||||
|
145
src/misc.c
145
src/misc.c
@ -37,6 +37,8 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@ -176,7 +178,7 @@ static const short base64_reverse_table[256] = {
|
||||
* Decode a base64 chunk and store it into a newly alloc'd buffer
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_base64_decode(LIBSSH2_SESSION * session, char **data,
|
||||
libssh2_base64_decode(LIBSSH2_SESSION *session, char **data,
|
||||
unsigned int *datalen, const char *src,
|
||||
unsigned int src_len)
|
||||
{
|
||||
@ -222,6 +224,86 @@ libssh2_base64_decode(LIBSSH2_SESSION * session, char **data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- Base64 Encoding/Decoding Table --- */
|
||||
static const char table64[]=
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/*
|
||||
* _libssh2_base64_encode()
|
||||
*
|
||||
* Returns the length of the newly created base64 string. The third argument
|
||||
* is a pointer to an allocated area holding the base64 data. If something
|
||||
* went wrong, 0 is returned.
|
||||
*
|
||||
*/
|
||||
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
|
||||
const char *inp, size_t insize, char **outptr)
|
||||
{
|
||||
unsigned char ibuf[3];
|
||||
unsigned char obuf[4];
|
||||
int i;
|
||||
int inputparts;
|
||||
char *output;
|
||||
char *base64data;
|
||||
const char *indata = inp;
|
||||
|
||||
*outptr = NULL; /* set to NULL in case of failure before we reach the end */
|
||||
|
||||
if(0 == insize)
|
||||
insize = strlen(indata);
|
||||
|
||||
base64data = output = LIBSSH2_ALLOC(session, insize*4/3+4);
|
||||
if(NULL == output)
|
||||
return 0;
|
||||
|
||||
while(insize > 0) {
|
||||
for (i = inputparts = 0; i < 3; i++) {
|
||||
if(insize > 0) {
|
||||
inputparts++;
|
||||
ibuf[i] = *indata;
|
||||
indata++;
|
||||
insize--;
|
||||
}
|
||||
else
|
||||
ibuf[i] = 0;
|
||||
}
|
||||
|
||||
obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
|
||||
obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
|
||||
((ibuf[1] & 0xF0) >> 4));
|
||||
obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
|
||||
((ibuf[2] & 0xC0) >> 6));
|
||||
obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
|
||||
|
||||
switch(inputparts) {
|
||||
case 1: /* only one byte read */
|
||||
snprintf(output, 5, "%c%c==",
|
||||
table64[obuf[0]],
|
||||
table64[obuf[1]]);
|
||||
break;
|
||||
case 2: /* two bytes read */
|
||||
snprintf(output, 5, "%c%c%c=",
|
||||
table64[obuf[0]],
|
||||
table64[obuf[1]],
|
||||
table64[obuf[2]]);
|
||||
break;
|
||||
default:
|
||||
snprintf(output, 5, "%c%c%c%c",
|
||||
table64[obuf[0]],
|
||||
table64[obuf[1]],
|
||||
table64[obuf[2]],
|
||||
table64[obuf[3]] );
|
||||
break;
|
||||
}
|
||||
output += 4;
|
||||
}
|
||||
*output=0;
|
||||
*outptr = base64data; /* make it return the actual data memory */
|
||||
|
||||
return strlen(base64data); /* return the length of the new data */
|
||||
}
|
||||
/* ---- End of Base64 Encoding ---- */
|
||||
|
||||
#ifdef LIBSSH2DEBUG
|
||||
LIBSSH2_API int
|
||||
libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||
@ -283,3 +365,64 @@ libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* init the list head */
|
||||
void _libssh2_list_init(struct list_head *head)
|
||||
{
|
||||
head->first = head->last = NULL;
|
||||
}
|
||||
|
||||
/* add a node to the list */
|
||||
void _libssh2_list_add(struct list_head *head,
|
||||
struct list_node *entry)
|
||||
{
|
||||
/* store a pointer to the head */
|
||||
entry->head = head;
|
||||
|
||||
/* we add this entry at the "top" so it has no next */
|
||||
entry->next = NULL;
|
||||
|
||||
/* make our prev point to what the head thinks is last */
|
||||
entry->prev = head->last;
|
||||
|
||||
/* and make head's last be us now */
|
||||
head->last = entry;
|
||||
|
||||
/* make sure our 'prev' node points to us next */
|
||||
if(entry->prev)
|
||||
entry->prev->next = entry;
|
||||
else
|
||||
head->first = entry;
|
||||
}
|
||||
|
||||
/* return the "first" node in the list this head points to */
|
||||
void *_libssh2_list_first(struct list_head *head)
|
||||
{
|
||||
return head->first;
|
||||
}
|
||||
|
||||
/* return the next node in the list */
|
||||
void *_libssh2_list_next(struct list_node *node)
|
||||
{
|
||||
return node->next;
|
||||
}
|
||||
|
||||
/* return the prev node in the list */
|
||||
void *_libssh2_list_prev(struct list_node *node)
|
||||
{
|
||||
return node->prev;
|
||||
}
|
||||
|
||||
/* remove this node from the list */
|
||||
void _libssh2_list_remove(struct list_node *entry)
|
||||
{
|
||||
if(entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
else
|
||||
entry->head->first = entry->next;
|
||||
|
||||
if(entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
else
|
||||
entry->head->last = entry->prev;
|
||||
}
|
||||
|
63
src/misc.h
Normal file
63
src/misc.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef __LIBSSH2_MISC_H
|
||||
#define __LIBSSH2_MISC_H
|
||||
/* Copyright (c) 2009 by Daniel Stenberg
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
void _libssh2_list_init(struct list_head *head);
|
||||
|
||||
/* add a node first in the list */
|
||||
void _libssh2_list_add(struct list_head *head,
|
||||
struct list_node *entry);
|
||||
|
||||
/* return the "first" node in the list this head points to */
|
||||
void *_libssh2_list_first(struct list_head *head);
|
||||
|
||||
/* return the next node in the list */
|
||||
void *_libssh2_list_next(struct list_node *node);
|
||||
|
||||
/* return the prev node in the list */
|
||||
void *_libssh2_list_prev(struct list_node *node);
|
||||
|
||||
/* remove this node from the list */
|
||||
void _libssh2_list_remove(struct list_node *entry);
|
||||
|
||||
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
|
||||
const char *inp, size_t insize, char **outptr);
|
||||
#endif /* _LIBSSH2_MISC_H */
|
@ -924,6 +924,10 @@ session_free(LIBSSH2_SESSION *session)
|
||||
/* if the socket was previously blocking, put it back so */
|
||||
session_nonblock(session->socket_fd, 0);
|
||||
|
||||
if (session->server_hostkey) {
|
||||
LIBSSH2_FREE(session, session->server_hostkey);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, session);
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user