version 1.45, 2015/01/08 10:14:08 |
version 1.46, 2015/01/15 09:40:00 |
|
|
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "log.h" |
#include "log.h" |
#include "key.h" |
#include "sshkey.h" |
#include "ssh.h" |
#include "ssh.h" |
#include "ssh2.h" |
#include "ssh2.h" |
#include "misc.h" |
#include "misc.h" |
#include "buffer.h" |
#include "sshbuf.h" |
#include "authfile.h" |
#include "authfile.h" |
#include "msg.h" |
#include "msg.h" |
#include "canohost.h" |
#include "canohost.h" |
|
|
uid_t original_real_uid; |
uid_t original_real_uid; |
|
|
static int |
static int |
valid_request(struct passwd *pw, char *host, Key **ret, u_char *data, |
valid_request(struct passwd *pw, char *host, struct sshkey **ret, |
u_int datalen) |
u_char *data, size_t datalen) |
{ |
{ |
Buffer b; |
struct sshbuf *b; |
Key *key = NULL; |
struct sshkey *key = NULL; |
u_char *pkblob; |
u_char type, *pkblob; |
u_int blen, len; |
char *p; |
char *pkalg, *p; |
size_t blen, len; |
int pktype, fail; |
char *pkalg, *luser; |
|
int r, pktype, fail; |
|
|
if (ret != NULL) |
if (ret != NULL) |
*ret = NULL; |
*ret = NULL; |
fail = 0; |
fail = 0; |
|
|
buffer_init(&b); |
if ((b = sshbuf_from(data, datalen)) == NULL) |
buffer_append(&b, data, datalen); |
fatal("%s: sshbuf_from failed", __func__); |
|
|
/* session id, currently limited to SHA1 (20 bytes) or SHA256 (32) */ |
/* session id, currently limited to SHA1 (20 bytes) or SHA256 (32) */ |
p = buffer_get_string(&b, &len); |
if ((r = sshbuf_get_string(b, NULL, &len)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if (len != 20 && len != 32) |
if (len != 20 && len != 32) |
fail++; |
fail++; |
free(p); |
|
|
|
if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) |
if ((r = sshbuf_get_u8(b, &type)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (type != SSH2_MSG_USERAUTH_REQUEST) |
fail++; |
fail++; |
|
|
/* server user */ |
/* server user */ |
buffer_skip_string(&b); |
if ((r = sshbuf_skip_string(b)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
/* service */ |
/* service */ |
p = buffer_get_string(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &p, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if (strcmp("ssh-connection", p) != 0) |
if (strcmp("ssh-connection", p) != 0) |
fail++; |
fail++; |
free(p); |
free(p); |
|
|
/* method */ |
/* method */ |
p = buffer_get_string(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &p, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if (strcmp("hostbased", p) != 0) |
if (strcmp("hostbased", p) != 0) |
fail++; |
fail++; |
free(p); |
free(p); |
|
|
/* pubkey */ |
/* pubkey */ |
pkalg = buffer_get_string(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0 || |
pkblob = buffer_get_string(&b, &blen); |
(r = sshbuf_get_string(b, &pkblob, &blen)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
pktype = key_type_from_name(pkalg); |
pktype = sshkey_type_from_name(pkalg); |
if (pktype == KEY_UNSPEC) |
if (pktype == KEY_UNSPEC) |
fail++; |
fail++; |
else if ((key = key_from_blob(pkblob, blen)) == NULL) |
else if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { |
|
error("%s: bad key blob: %s", __func__, ssh_err(r)); |
fail++; |
fail++; |
else if (key->type != pktype) |
} else if (key->type != pktype) |
fail++; |
fail++; |
free(pkalg); |
free(pkalg); |
free(pkblob); |
free(pkblob); |
|
|
/* client host name, handle trailing dot */ |
/* client host name, handle trailing dot */ |
p = buffer_get_string(&b, &len); |
if ((r = sshbuf_get_cstring(b, &p, &len)) != 0) |
debug2("valid_request: check expect chost %s got %s", host, p); |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
debug2("%s: check expect chost %s got %s", __func__, host, p); |
if (strlen(host) != len - 1) |
if (strlen(host) != len - 1) |
fail++; |
fail++; |
else if (p[len - 1] != '.') |
else if (p[len - 1] != '.') |
|
|
free(p); |
free(p); |
|
|
/* local user */ |
/* local user */ |
p = buffer_get_string(&b, NULL); |
if ((r = sshbuf_get_cstring(b, &luser, NULL)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
|
if (strcmp(pw->pw_name, p) != 0) |
if (strcmp(pw->pw_name, luser) != 0) |
fail++; |
fail++; |
free(p); |
free(luser); |
|
|
/* end of message */ |
/* end of message */ |
if (buffer_len(&b) != 0) |
if (sshbuf_len(b) != 0) |
fail++; |
fail++; |
buffer_free(&b); |
sshbuf_free(b); |
|
|
debug3("valid_request: fail %d", fail); |
debug3("%s: fail %d", __func__, fail); |
|
|
if (fail && key != NULL) |
if (fail && key != NULL) |
key_free(key); |
sshkey_free(key); |
else |
else |
*ret = key; |
*ret = key; |
|
|
|
|
int |
int |
main(int argc, char **argv) |
main(int argc, char **argv) |
{ |
{ |
Buffer b; |
struct sshbuf *b; |
Options options; |
Options options; |
#define NUM_KEYTYPES 4 |
#define NUM_KEYTYPES 4 |
Key *keys[NUM_KEYTYPES], *key = NULL; |
struct sshkey *keys[NUM_KEYTYPES], *key = NULL; |
struct passwd *pw; |
struct passwd *pw; |
int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd; |
int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd; |
u_char *signature, *data; |
u_char *signature, *data, rver; |
char *host, *fp; |
char *host, *fp; |
u_int slen, dlen; |
size_t slen, dlen; |
|
|
/* Ensure that stdin and stdout are connected */ |
/* Ensure that stdin and stdout are connected */ |
if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2) |
if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2) |
|
|
if (!found) |
if (!found) |
fatal("no hostkey found"); |
fatal("no hostkey found"); |
|
|
buffer_init(&b); |
if ((b = sshbuf_new()) == NULL) |
if (ssh_msg_recv(STDIN_FILENO, &b) < 0) |
fatal("%s: sshbuf_new failed", __func__); |
|
if (ssh_msg_recv(STDIN_FILENO, b) < 0) |
fatal("ssh_msg_recv failed"); |
fatal("ssh_msg_recv failed"); |
if (buffer_get_char(&b) != version) |
if ((r = sshbuf_get_u8(b, &rver)) != 0) |
fatal("bad version"); |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fd = buffer_get_int(&b); |
if (rver != version) |
if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO)) |
fatal("bad version: received %d, expected %d", rver, version); |
|
if ((r = sshbuf_get_u32(b, (u_int *)&fd)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (fd < 0 || fd == STDIN_FILENO || fd == STDOUT_FILENO) |
fatal("bad fd"); |
fatal("bad fd"); |
if ((host = get_local_name(fd)) == NULL) |
if ((host = get_local_name(fd)) == NULL) |
fatal("cannot get local name for fd"); |
fatal("cannot get local name for fd"); |
|
|
data = buffer_get_string(&b, &dlen); |
if ((r = sshbuf_get_string(b, &data, &dlen)) != 0) |
|
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
if (valid_request(pw, host, &key, data, dlen) < 0) |
if (valid_request(pw, host, &key, data, dlen) < 0) |
fatal("not a valid request"); |
fatal("not a valid request"); |
free(host); |
free(host); |
|
|
found = 0; |
found = 0; |
for (i = 0; i < NUM_KEYTYPES; i++) { |
for (i = 0; i < NUM_KEYTYPES; i++) { |
if (keys[i] != NULL && |
if (keys[i] != NULL && |
key_equal_public(key, keys[i])) { |
sshkey_equal_public(key, keys[i])) { |
found = 1; |
found = 1; |
break; |
break; |
} |
} |
} |
} |
if (!found) { |
if (!found) { |
fp = key_fingerprint(key, options.fingerprint_hash, |
fp = sshkey_fingerprint(key, options.fingerprint_hash, |
SSH_FP_DEFAULT); |
SSH_FP_DEFAULT); |
fatal("no matching hostkey found for key %s %s", |
fatal("no matching hostkey found for key %s %s", |
key_type(key), fp); |
sshkey_type(key), fp ? fp : ""); |
} |
} |
|
|
if (key_sign(keys[i], &signature, &slen, data, dlen) != 0) |
if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen, 0)) != 0) |
fatal("key_sign failed"); |
fatal("sshkey_sign failed: %s", ssh_err(r)); |
free(data); |
free(data); |
|
|
/* send reply */ |
/* send reply */ |
buffer_clear(&b); |
sshbuf_reset(b); |
buffer_put_string(&b, signature, slen); |
if ((r = sshbuf_put_string(b, signature, slen)) != 0) |
if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
|
if (ssh_msg_send(STDOUT_FILENO, version, b) == -1) |
fatal("ssh_msg_send failed"); |
fatal("ssh_msg_send failed"); |
|
|
return (0); |
return (0); |