Add libssh2_knownhost_addc to handle comments.
Comments in known_hosts file were not handle properly. They were parsed as part of the key causing key matching to return a mismatch if the entry had a comment. This adds a new API function that takes an optional comment and changes libssh2_knownhost_readline to parse the comment as pass it to the new function. Fixes #164.
Этот коммит содержится в:
родитель
c585828d2b
Коммит
9abf81de97
2
TODO
2
TODO
@ -49,3 +49,5 @@ At next SONAME bump
|
||||
* change 'int' to 'libssh2_socket_t' in the public API for sockets.
|
||||
|
||||
* Use 'size_t' for string lengths in all functions.
|
||||
|
||||
* Add a comment field to struct libssh2_knownhost.
|
||||
|
@ -719,7 +719,7 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session);
|
||||
*
|
||||
* Add a host and its associated key to the collection of known hosts.
|
||||
*
|
||||
* The 'type' argument specifies on what format the given host is:
|
||||
* The 'type' argument specifies on what format the given host and keys are:
|
||||
*
|
||||
* plain - ascii "hostname.domain.tld"
|
||||
* sha1 - SHA1(<salt> <host>) base64-encoded!
|
||||
@ -732,6 +732,8 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session);
|
||||
* 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.
|
||||
*
|
||||
* The keylen parameter may be ommitted (zero) if the key is provided as a
|
||||
* NULL-terminated base64-encoded string.
|
||||
*/
|
||||
|
||||
/* host format (2 bits) */
|
||||
@ -759,6 +761,41 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *key, size_t keylen, int typemask,
|
||||
struct libssh2_knownhost **store);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_addc
|
||||
*
|
||||
* Add a host and its associated key to the collection of known hosts.
|
||||
*
|
||||
* Takes a comment argument that may be NULL. A NULL comment indicates
|
||||
* there is no comment and the entry will end directly after the key
|
||||
* when written out to a file. An empty string "" comment will indicate an
|
||||
* empty comment which will cause a single space to be written after the key.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The keylen parameter may be ommitted (zero) if the key is provided as a
|
||||
* NULL-terminated base64-encoded string.
|
||||
*/
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host,
|
||||
const char *salt,
|
||||
const char *key, size_t keylen,
|
||||
const char *comment, size_t commentlen, int typemask,
|
||||
struct libssh2_knownhost **store);
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_check
|
||||
*
|
||||
@ -940,8 +977,8 @@ libssh2_agent_list_identities(LIBSSH2_AGENT *agent);
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
|
||||
struct libssh2_agent_publickey **store,
|
||||
struct libssh2_agent_publickey *prev);
|
||||
struct libssh2_agent_publickey **store,
|
||||
struct libssh2_agent_publickey *prev);
|
||||
|
||||
/*
|
||||
* libssh2_agent_userauth()
|
||||
@ -952,8 +989,8 @@ libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_agent_userauth(LIBSSH2_AGENT *agent,
|
||||
const char *username,
|
||||
struct libssh2_agent_publickey *identity);
|
||||
const char *username,
|
||||
struct libssh2_agent_publickey *identity);
|
||||
|
||||
/*
|
||||
* libssh2_agent_disconnect()
|
||||
|
188
src/knownhost.c
188
src/knownhost.c
@ -48,6 +48,7 @@ struct known_host {
|
||||
size_t salt_len; /* size of salt */
|
||||
char *key; /* the (allocated) associated key. This is kept base64
|
||||
encoded in memory. */
|
||||
char *comment; /* the (allocated) optional comment text, may be NULL */
|
||||
|
||||
/* this is the struct we expose externally */
|
||||
struct libssh2_knownhost external;
|
||||
@ -62,6 +63,8 @@ struct _LIBSSH2_KNOWNHOSTS
|
||||
static void free_host(LIBSSH2_SESSION *session, struct known_host *entry)
|
||||
{
|
||||
if(entry) {
|
||||
if(entry->comment)
|
||||
LIBSSH2_FREE(session, entry->comment);
|
||||
if(entry->key)
|
||||
LIBSSH2_FREE(session, entry->key);
|
||||
if(entry->salt)
|
||||
@ -119,31 +122,12 @@ static struct libssh2_knownhost *knownhost_to_external(struct known_host *node)
|
||||
return ext;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
const char *host, const char *salt,
|
||||
const char *key, size_t keylen,
|
||||
int typemask, struct libssh2_knownhost **store)
|
||||
static int
|
||||
knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, const char *salt,
|
||||
const char *key, size_t keylen,
|
||||
const char *comment, size_t commentlen,
|
||||
int typemask, struct libssh2_knownhost **store)
|
||||
{
|
||||
struct known_host *entry =
|
||||
LIBSSH2_ALLOC(hosts->session, sizeof(struct known_host));
|
||||
@ -227,6 +211,20 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
entry->key = ptr;
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen+1);
|
||||
if(!entry->comment) {
|
||||
rc = libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for comment");
|
||||
goto error;
|
||||
}
|
||||
memcpy(entry->comment, comment, commentlen+1);
|
||||
entry->comment[commentlen]=0; /* force a terminating zero trailer */
|
||||
}
|
||||
else {
|
||||
entry->comment = NULL;
|
||||
}
|
||||
|
||||
/* add this new host to the big list of known hosts */
|
||||
_libssh2_list_add(&hosts->head, &entry->node);
|
||||
|
||||
@ -239,6 +237,77 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* The keylen parameter may be ommitted (zero) if the key is provided as a
|
||||
* NULL-terminated base64-encoded string.
|
||||
*/
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, const char *salt,
|
||||
const char *key, size_t keylen,
|
||||
int typemask, struct libssh2_knownhost **store)
|
||||
{
|
||||
return knownhost_add(hosts, host, salt, key, keylen, NULL, 0, typemask,
|
||||
store);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_addc
|
||||
*
|
||||
* Add a host and its associated key to the collection of known hosts.
|
||||
*
|
||||
* Takes a comment argument that may be NULL. A NULL comment indicates
|
||||
* there is no comment and the entry will end directly after the key
|
||||
* when written out to a file. An empty string "" comment will indicate an
|
||||
* empty comment which will cause a single space to be written after the key.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The keylen parameter may be ommitted (zero) if the key is provided as a
|
||||
* NULL-terminated base64-encoded string.
|
||||
*/
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, const char *salt,
|
||||
const char *key, size_t keylen,
|
||||
const char *comment, size_t commentlen,
|
||||
int typemask, struct libssh2_knownhost **store)
|
||||
{
|
||||
return knownhost_add(hosts, host, salt, key, keylen, comment, commentlen,
|
||||
typemask, store);
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_knownhost_check
|
||||
*
|
||||
@ -414,6 +483,10 @@ libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts)
|
||||
*
|
||||
* Parse a single known_host line pre-split into host and key.
|
||||
*
|
||||
* The key part may include an optional comment which will be parsed here
|
||||
* for ssh-rsa and ssh-dsa keys. Comments in other key types aren't handled.
|
||||
*
|
||||
* The function assumes new-lines have already been removed from the arguments.
|
||||
*/
|
||||
static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, size_t hostlen,
|
||||
@ -422,6 +495,8 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *p;
|
||||
const char *orig = host;
|
||||
const char *salt = NULL;
|
||||
const char *comment = NULL;
|
||||
size_t commentlen = 0;
|
||||
int rc;
|
||||
int type = LIBSSH2_KNOWNHOST_TYPE_PLAIN;
|
||||
const char *sep = NULL;
|
||||
@ -526,6 +601,30 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
key++;
|
||||
keylen--;
|
||||
}
|
||||
|
||||
comment = key;
|
||||
commentlen = keylen;
|
||||
|
||||
/* move over key */
|
||||
while(commentlen && *comment &&
|
||||
(*comment != ' ') && (*comment != '\t')) {
|
||||
comment++;
|
||||
commentlen--;
|
||||
}
|
||||
|
||||
/* reduce key by comment length */
|
||||
keylen -= commentlen;
|
||||
|
||||
/* Distinguish empty comment (a space) from no comment (no space) */
|
||||
if (commentlen == 0)
|
||||
comment = NULL;
|
||||
|
||||
/* skip whitespaces */
|
||||
while(commentlen && *comment &&
|
||||
((*comment ==' ') || (*comment == '\t'))) {
|
||||
comment++;
|
||||
commentlen--;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* unknown key format */
|
||||
@ -540,9 +639,10 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
memcpy(hostbuf, sep, seplen);
|
||||
hostbuf[seplen]=0;
|
||||
|
||||
rc = libssh2_knownhost_add(hosts, hostbuf, salt, key, keylen,
|
||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
||||
NULL);
|
||||
rc = libssh2_knownhost_addc(hosts, hostbuf, salt, key, keylen,
|
||||
comment, commentlen,
|
||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
||||
NULL);
|
||||
if(rc)
|
||||
return rc;
|
||||
}
|
||||
@ -552,9 +652,10 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
memcpy(hostbuf, host, hostlen);
|
||||
hostbuf[hostlen]=0;
|
||||
|
||||
rc = libssh2_knownhost_add(hosts, hostbuf, salt, key, keylen,
|
||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
||||
NULL);
|
||||
rc = libssh2_knownhost_addc(hosts, hostbuf, salt, key, keylen, comment,
|
||||
commentlen,
|
||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
||||
NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -724,6 +825,7 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
};
|
||||
const char *keytype;
|
||||
size_t nlen;
|
||||
size_t commentlen = 0;
|
||||
|
||||
/* we only support this single file type for now, bail out on all other
|
||||
attempts */
|
||||
@ -739,6 +841,10 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
/* set the string used in the file */
|
||||
keytype = keytypes[tindex];
|
||||
|
||||
/* calculate extra space needed for comment */
|
||||
if(node->comment)
|
||||
commentlen = strlen(node->comment) + 1;
|
||||
|
||||
if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) ==
|
||||
LIBSSH2_KNOWNHOST_TYPE_SHA1) {
|
||||
char *namealloc;
|
||||
@ -761,11 +867,16 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
}
|
||||
|
||||
nlen = strlen(saltalloc) + strlen(namealloc) + strlen(keytype) +
|
||||
strlen(node->key) + 7; /* |1| + | + ' ' + \n + \0 = 7 */
|
||||
strlen(node->key) + commentlen + 7;
|
||||
/* |1| + | + ' ' + \n + \0 = 7 */
|
||||
|
||||
if(nlen <= buflen)
|
||||
sprintf(buf, "|1|%s|%s%s %s\n", saltalloc, namealloc, keytype,
|
||||
node->key);
|
||||
if(node->comment)
|
||||
sprintf(buf, "|1|%s|%s%s %s %s\n", saltalloc, namealloc,
|
||||
keytype, node->key, node->comment);
|
||||
else
|
||||
sprintf(buf, "|1|%s|%s%s %s\n", saltalloc, namealloc,
|
||||
keytype, node->key);
|
||||
else
|
||||
rc = libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||
"Known-host write buffer too small");
|
||||
@ -774,11 +885,16 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
free(saltalloc);
|
||||
}
|
||||
else {
|
||||
nlen = strlen(node->name) + strlen(keytype) + strlen(node->key) + 3;
|
||||
nlen = strlen(node->name) + strlen(keytype) + strlen(node->key) +
|
||||
commentlen + 3;
|
||||
/* ' ' + '\n' + \0 = 3 */
|
||||
if(nlen <= buflen)
|
||||
/* these types have the plain name */
|
||||
sprintf(buf, "%s%s %s\n", node->name, keytype, node->key);
|
||||
if(node->comment)
|
||||
sprintf(buf, "%s%s %s %s\n", node->name, keytype, node->key,
|
||||
node->comment);
|
||||
else
|
||||
sprintf(buf, "%s%s %s\n", node->name, keytype, node->key);
|
||||
else
|
||||
rc = libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
||||
"Known-host write buffer too small");
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user