Support unlimited number of host names in a single line of the known_hosts file.
Previously the code assumed either a single host name or a hostname,ip-address pair. However, according to the spec [1], there can be any number of comma separated host names or IP addresses. [1] http://www.openbsd.org/cgi-bin/man.cgi?query=sshd&sektion=8
This commit is contained in:
202
src/knownhost.c
202
src/knownhost.c
@@ -566,60 +566,76 @@ libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts)
|
|||||||
LIBSSH2_FREE(hosts->session, hosts);
|
LIBSSH2_FREE(hosts->session, hosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* hostline()
|
/* old style plain text: [name]([,][name])*
|
||||||
*
|
|
||||||
* Parse a single known_host line pre-split into host and key.
|
for the sake of simplicity, we add them as separate hosts with the same
|
||||||
*
|
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.
|
static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||||
*
|
|
||||||
* The function assumes new-lines have already been removed from the arguments.
|
|
||||||
*/
|
|
||||||
static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
|
||||||
const char *host, size_t hostlen,
|
const char *host, size_t hostlen,
|
||||||
const char *key, size_t keylen)
|
const char *key, size_t keylen, int key_type,
|
||||||
|
const char *comment, size_t commentlen)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
size_t namelen = 0;
|
||||||
|
const char *name = host + hostlen;
|
||||||
|
|
||||||
|
if(hostlen < 1)
|
||||||
|
return _libssh2_error(hosts->session,
|
||||||
|
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
|
"Failed to parse known_hosts line "
|
||||||
|
"(no host names)");
|
||||||
|
|
||||||
|
while(name > host) {
|
||||||
|
--name;
|
||||||
|
++namelen;
|
||||||
|
|
||||||
|
/* when we get the the start or see a comma coming up, add the host
|
||||||
|
name to the collection */
|
||||||
|
if((name == host) || (*(name-1) == ',')) {
|
||||||
|
|
||||||
|
char hostbuf[256];
|
||||||
|
|
||||||
|
/* make sure we don't overflow the buffer */
|
||||||
|
if(namelen >= sizeof(hostbuf)-1)
|
||||||
|
return _libssh2_error(hosts->session,
|
||||||
|
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
|
"Failed to parse known_hosts line "
|
||||||
|
"(unexpected length)");
|
||||||
|
|
||||||
|
/* copy host name to the temp buffer and zero terminate */
|
||||||
|
memcpy(hostbuf, name, namelen);
|
||||||
|
hostbuf[namelen]=0;
|
||||||
|
|
||||||
|
rc = knownhost_add(hosts, hostbuf, NULL, key, keylen,
|
||||||
|
comment, commentlen,
|
||||||
|
key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN |
|
||||||
|
LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if(name > host) {
|
||||||
|
namelen = 0;
|
||||||
|
--name; // skip comma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |1|[salt]|[hash] */
|
||||||
|
static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||||
|
const char *host, size_t hostlen,
|
||||||
|
const char *key, size_t keylen, int key_type,
|
||||||
|
const char *comment, size_t commentlen)
|
||||||
{
|
{
|
||||||
const char *p;
|
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;
|
|
||||||
size_t seplen = 0;
|
|
||||||
char saltbuf[32];
|
char saltbuf[32];
|
||||||
char hostbuf[256];
|
char hostbuf[256];
|
||||||
|
|
||||||
/* Figure out host format */
|
const char *salt = &host[3]; /* skip the magic marker */
|
||||||
if((hostlen >2) && memcmp(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
|
|
||||||
*/
|
|
||||||
size_t scan = hostlen;
|
|
||||||
|
|
||||||
while(scan && (*host != ',')) {
|
|
||||||
host++;
|
|
||||||
scan--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(scan) {
|
|
||||||
sep = host+1;
|
|
||||||
seplen = scan-1;
|
|
||||||
hostlen -= scan; /* deduct what's left to scan from the first
|
|
||||||
host name */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
host = orig;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* |1|[salt]|[hash] */
|
|
||||||
type = LIBSSH2_KNOWNHOST_TYPE_SHA1;
|
|
||||||
|
|
||||||
salt = &host[3]; /* skip the magic marker */
|
|
||||||
hostlen -= 3; /* deduct the marker */
|
hostlen -= 3; /* deduct the marker */
|
||||||
|
|
||||||
/* this is where the salt starts, find the end of it */
|
/* this is where the salt starts, find the end of it */
|
||||||
@@ -644,24 +660,55 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
|||||||
/* now make the host point to the hash */
|
/* now make the host point to the hash */
|
||||||
host = hash;
|
host = hash;
|
||||||
hostlen -= saltlen+1; /* deduct the salt and separator */
|
hostlen -= saltlen+1; /* deduct the salt and separator */
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make some checks that the lengths seem sensible */
|
/* check that the lengths seem sensible */
|
||||||
if((keylen < 20) ||
|
if(hostlen >= sizeof(hostbuf)-1)
|
||||||
(seplen >= sizeof(hostbuf)-1) ||
|
|
||||||
(hostlen >= sizeof(hostbuf)-1))
|
|
||||||
return _libssh2_error(hosts->session,
|
return _libssh2_error(hosts->session,
|
||||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
"Failed to parse known_hosts line "
|
"Failed to parse known_hosts line "
|
||||||
"(unexpected length)");
|
"(unexpected length)");
|
||||||
|
|
||||||
|
memcpy(hostbuf, host, hostlen);
|
||||||
|
hostbuf[hostlen]=0;
|
||||||
|
|
||||||
|
return knownhost_add(hosts, hostbuf, salt, key, keylen, comment,
|
||||||
|
commentlen,
|
||||||
|
key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 |
|
||||||
|
LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0; /* XXX: This should be an error, shouldn't it? */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hostline()
|
||||||
|
*
|
||||||
|
* 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,
|
||||||
|
const char *key, size_t keylen)
|
||||||
|
{
|
||||||
|
const char *comment = NULL;
|
||||||
|
size_t commentlen = 0;
|
||||||
|
int key_type;
|
||||||
|
|
||||||
|
/* make some checks that the lengths seem sensible */
|
||||||
|
if(keylen < 20)
|
||||||
|
return _libssh2_error(hosts->session,
|
||||||
|
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
|
"Failed to parse known_hosts line "
|
||||||
|
"(key too short)");
|
||||||
|
|
||||||
switch(key[0]) {
|
switch(key[0]) {
|
||||||
case '0': case '1': case '2': case '3': case '4':
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
type |= LIBSSH2_KNOWNHOST_KEY_RSA1;
|
key_type = LIBSSH2_KNOWNHOST_KEY_RSA1;
|
||||||
|
|
||||||
/* Note that the old-style keys (RSA1) aren't truly base64, but we
|
/* 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
|
* claim it is for now since we can get away with strcmp()ing the
|
||||||
@@ -672,9 +719,9 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
|||||||
|
|
||||||
case 's': /* ssh-dss or ssh-rsa */
|
case 's': /* ssh-dss or ssh-rsa */
|
||||||
if(!strncmp(key, "ssh-dss", 7))
|
if(!strncmp(key, "ssh-dss", 7))
|
||||||
type |= LIBSSH2_KNOWNHOST_KEY_SSHDSS;
|
key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
|
||||||
else if(!strncmp(key, "ssh-rsa", 7))
|
else if(!strncmp(key, "ssh-rsa", 7))
|
||||||
type |= LIBSSH2_KNOWNHOST_KEY_SSHRSA;
|
key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
|
||||||
else
|
else
|
||||||
/* unknown key type */
|
/* unknown key type */
|
||||||
return _libssh2_error(hosts->session,
|
return _libssh2_error(hosts->session,
|
||||||
@@ -721,30 +768,21 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
|||||||
"Unknown key format");
|
"Unknown key format");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sep) {
|
/* Figure out host format */
|
||||||
/* The second host after the comma, add this first. Copy it to the
|
if((hostlen >2) && memcmp(host, "|1|", 3)) {
|
||||||
temp buffer and zero terminate */
|
/* old style plain text: [name]([,][name])*
|
||||||
memcpy(hostbuf, sep, seplen);
|
|
||||||
hostbuf[seplen]=0;
|
|
||||||
|
|
||||||
rc = knownhost_add(hosts, hostbuf, salt, key, keylen,
|
for the sake of simplicity, we add them as separate hosts with the
|
||||||
comment, commentlen,
|
same key
|
||||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
*/
|
||||||
NULL);
|
return oldstyle_hostline(hosts, host, hostlen, key, keylen, key_type,
|
||||||
if(rc)
|
comment, commentlen);
|
||||||
return rc;
|
}
|
||||||
|
else {
|
||||||
|
/* |1|[salt]|[hash] */
|
||||||
|
return hashed_hostline(hosts, host, hostlen, key, keylen, key_type,
|
||||||
|
comment, commentlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!salt)
|
|
||||||
host = orig;
|
|
||||||
memcpy(hostbuf, host, hostlen);
|
|
||||||
hostbuf[hostlen]=0;
|
|
||||||
|
|
||||||
rc = knownhost_add(hosts, hostbuf, salt, key, keylen, comment,
|
|
||||||
commentlen,
|
|
||||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
|
||||||
NULL);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -764,7 +802,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
|||||||
* <name> or <hash>
|
* <name> or <hash>
|
||||||
*
|
*
|
||||||
* <name> consists of
|
* <name> consists of
|
||||||
* [name,address] or just [name] or just [address]
|
* [name] optionally followed by [,name] one or more times
|
||||||
*
|
*
|
||||||
* <hash> consists of
|
* <hash> consists of
|
||||||
* |1|<salt>|hash
|
* |1|<salt>|hash
|
||||||
|
|||||||
Reference in New Issue
Block a user