X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Fssh-security.c;h=bed501be996151a31ca54560b8b1513b7de975e9;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hp=45a55e40d7d2684d299714d8354a33cabf1510da;hpb=94a044f90357edefa6f4ae9f0b1d5885b0e34aee;p=debian%2Famanda diff --git a/common-src/ssh-security.c b/common-src/ssh-security.c index 45a55e4..bed501b 100644 --- a/common-src/ssh-security.c +++ b/common-src/ssh-security.c @@ -37,11 +37,10 @@ #include "util.h" #include "event.h" #include "packet.h" -#include "queue.h" #include "security.h" #include "security-util.h" +#include "sockaddr-util.h" #include "stream.h" -#include "version.h" /* * Number of seconds ssh has to start up @@ -60,6 +59,10 @@ static void ssh_connect(const char *, char *(*)(char *, void *), void (*)(void *, security_handle_t *, security_status_t), void *, void *); +static void ssh_accept(const security_driver_t *driver, char *(*conf_fn)(char *, void *), + int in, int out, + void (*fn)(security_handle_t *, pkt_t *), + void *datap); /* * This is our interface to the outside world. @@ -67,7 +70,8 @@ static void ssh_connect(const char *, char *(*)(char *, void *), const security_driver_t ssh_security_driver = { "SSH", ssh_connect, - sec_accept, + ssh_accept, + sec_get_authenticated_peer_name_hostname, sec_close, stream_sendpkt, stream_recvpkt, @@ -106,6 +110,7 @@ ssh_connect( void * arg, void * datap) { + int result; struct sec_handle *rh; char *amandad_path=NULL, *client_username=NULL, *ssh_keys=NULL; @@ -114,17 +119,20 @@ ssh_connect( auth_debug(1, "ssh_connect: %s\n", hostname); - rh = alloc(SIZEOF(*rh)); + rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, &ssh_security_driver); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; + /* get the canonical hostname */ rh->hostname = NULL; - if (resolve_hostname(hostname, 0, NULL, &rh->hostname) || rh->hostname == NULL) { + if ((result = resolve_hostname(hostname, 0, NULL, &rh->hostname)) != 0 + || rh->hostname == NULL) { security_seterror(&rh->sech, - _("%s: ssh could not resolve hostname"), hostname); + _("ssh_security could not find canonical name for '%s': %s"), + hostname, gai_strerror(result)); (*fn)(arg, &rh->sech, S_ERROR); return; } @@ -178,6 +186,99 @@ error: (*fn)(arg, &rh->sech, S_ERROR); } +/* like sec_accept, but first it gets the remote system's hostname */ +static void +ssh_accept( + const security_driver_t *driver, + char *(*conf_fn)(char *, void *), + int in, + int out, + void (*fn)(security_handle_t *, pkt_t *), + void *datap) +{ + struct sec_handle *rh; + struct tcp_conn *rc = sec_tcp_conn_get("", 0); + char *ssh_connection, *p; + char *errmsg = NULL; + sockaddr_union addr; + int result; + + /* "Accepting" an SSH connection means that amandad was invoked via sshd, so + * we should have anSSH_CONNECTION env var. If not, then this probably isn't + * a real SSH connection and we should bail out. */ + ssh_connection = getenv("SSH_CONNECTION"); + if (!ssh_connection) { + errmsg = g_strdup("$SSH_CONNECTION not set - was amandad started by sshd?"); + goto error; + } + + /* make a local copy, to munge */ + ssh_connection = g_strdup(ssh_connection); + + /* strip off the first component - the ASCII IP address */ + if ((p = strchr(ssh_connection, ' ')) == NULL) { + errmsg = g_strdup("$SSH_CONNECTION malformed"); + goto error; + } + *p = '\0'; + + /* ---- everything from here on is just a warning, leaving hostname at "" */ + + SU_INIT(&addr, AF_INET); + + /* turn the string address into a sockaddr */ + if ((result = str_to_sockaddr(ssh_connection, &addr)) != 1) { + if (result == 0) { + g_warning("Could not parse peer address %s", ssh_connection); + } else { + g_warning("Parsing peer address %s: %s", ssh_connection, gai_strerror(result)); + } + goto done; + } + + /* find the hostname */ + result = getnameinfo((struct sockaddr *)&addr, SS_LEN(&addr), + rc->hostname, sizeof(rc->hostname), NULL, 0, 0); + if (result != 0) { + g_warning("Could not get hostname for SSH client %s: %s", ssh_connection, + gai_strerror(result)); + goto done; + } + + /* and verify it */ + if (check_name_give_sockaddr(rc->hostname, + (struct sockaddr *)&addr, &errmsg) < 0) { + rc->hostname[0] = '\0'; /* null out the bad hostname */ + g_warning("Checking SSH client DNS: %s", errmsg); + amfree(errmsg); + goto done; + } + +done: + if (ssh_connection) + g_free(ssh_connection); + + rc->read = in; + rc->write = out; + rc->accept_fn = fn; + rc->driver = driver; + rc->conf_fn = conf_fn; + rc->datap = datap; + sec_tcp_conn_read(rc); + return; + +error: + if (ssh_connection) + g_free(ssh_connection); + + /* make up a fake handle for the error */ + rh = g_new0(struct sec_handle, 1); + security_handleinit(&rh->sech, driver); + security_seterror((security_handle_t*)rh, "ssh_accept: %s", errmsg); + amfree(errmsg); + (*fn)(&rh->sech, NULL); +} + /* * Forks a ssh to the host listed in rc->hostname * Returns negative on error, with an errmsg in rc->errmsg. @@ -221,11 +322,13 @@ runssh( return (0); } + /* drop root privs for good */ + set_root_privs(-1); + safe_fd(-1, 0); if(!xamandad_path || strlen(xamandad_path) <= 1) - xamandad_path = vstralloc(amlibexecdir, "/", "amandad", - versionsuffix(), NULL); + xamandad_path = vstralloc(amlibexecdir, "/", "amandad", NULL); if(!xclient_username || strlen(xclient_username) <= 1) xclient_username = CLIENT_LOGIN; if(!ssh_keys || strlen(ssh_keys) <= 1) {