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:
Alexander Lamaison
2011-03-13 00:10:41 +00:00
parent ec934f6dab
commit 527c1b2def

View File

@@ -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