mirror of
				https://github.com/libssh2/libssh2.git
				synced 2025-11-03 22:13:11 +03:00 
			
		
		
		
	split out the knownhost code from hostkey.c into its own separate source file
now: knownhost.c
This commit is contained in:
		@@ -1,10 +1,10 @@
 | 
				
			|||||||
# $Id: Makefile.am,v 1.20 2009/05/07 13:09:49 bagder Exp $
 | 
					# $Id: Makefile.am,v 1.21 2009/05/07 17:21:56 bagder Exp $
 | 
				
			||||||
AUTOMAKE_OPTIONS = foreign nostdinc
 | 
					AUTOMAKE_OPTIONS = foreign nostdinc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
 | 
					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	   \
 | 
					 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  \
 | 
					 openssl.h libgcrypt.h transport.c version.c transport.h channel.h comp.h  \
 | 
				
			||||||
 mac.h misc.h
 | 
					 mac.h misc.h knownhost.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if LIBGCRYPT
 | 
					if LIBGCRYPT
 | 
				
			||||||
libssh2_la_SOURCES += libgcrypt.c pem.c
 | 
					libssh2_la_SOURCES += libgcrypt.c pem.c
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										519
									
								
								src/hostkey.c
									
									
									
									
									
								
							
							
						
						
									
										519
									
								
								src/hostkey.c
									
									
									
									
									
								
							@@ -457,19 +457,6 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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()
 | 
					 * libssh2_session_hostkey()
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -489,509 +476,3 @@ libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len)
 | 
				
			|||||||
    return NULL;
 | 
					    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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										566
									
								
								src/knownhost.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										566
									
								
								src/knownhost.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,566 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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.h"
 | 
				
			||||||
 | 
					#include "libssh2_priv.h"
 | 
				
			||||||
 | 
					#include "misc.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Needed for struct iovec on some platforms */
 | 
				
			||||||
 | 
					#ifdef HAVE_SYS_UIO_H
 | 
				
			||||||
 | 
					#include <sys/uio.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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_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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user