agent: Don't keep socket to ssh/gpg-agent open

Instead, create a socket when necessary.  Apparently, it can prevent
the agent from getting terminated (e.g. during system shutdown) if e.g.
charon-nm is still running with an open connection to the agent.
This commit is contained in:
Tobias Brunner
2019-02-20 10:43:19 +01:00
parent 71b22c250f
commit d091703a9e
@@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2013-2019 Tobias Brunner
* Copyright (C) 2008-2009 Martin Willi * Copyright (C) 2008-2009 Martin Willi
* HSR Hochschule fuer Technik Rapperswil * HSR Hochschule fuer Technik Rapperswil
* *
@@ -44,9 +45,9 @@ struct private_agent_private_key_t {
agent_private_key_t public; agent_private_key_t public;
/** /**
* ssh-agent unix socket connection * Path to the UNIX socket
*/ */
int socket; char *path;
/** /**
* public key encoded in SSH format * public key encoded in SSH format
@@ -174,28 +175,35 @@ static int open_connection(char *path)
*/ */
static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey) static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
{ {
int len; int socket, len;
char buf[2048]; char buf[2048];
chunk_t blob, key; chunk_t blob, key;
bool success = FALSE;
len = htonl(1); socket = open_connection(this->path);
buf[0] = SSH_AGENT_ID_REQUEST; if (socket < 0)
if (write(this->socket, &len, sizeof(len)) != sizeof(len) ||
write(this->socket, &buf, 1) != 1)
{ {
DBG1(DBG_LIB, "writing to ssh-agent failed");
return FALSE; return FALSE;
} }
len = htonl(1);
buf[0] = SSH_AGENT_ID_REQUEST;
if (write(socket, &len, sizeof(len)) != sizeof(len) ||
write(socket, &buf, 1) != 1)
{
DBG1(DBG_LIB, "writing to ssh-agent failed");
goto done;
}
blob = chunk_create(buf, sizeof(buf)); blob = chunk_create(buf, sizeof(buf));
blob.len = read(this->socket, blob.ptr, blob.len); blob.len = read(socket, blob.ptr, blob.len);
if (blob.len < sizeof(uint32_t) + sizeof(u_char) || if (blob.len < sizeof(uint32_t) + sizeof(u_char) ||
read_uint32(&blob) != blob.len || read_uint32(&blob) != blob.len ||
read_byte(&blob) != SSH_AGENT_ID_RESPONSE) read_byte(&blob) != SSH_AGENT_ID_RESPONSE)
{ {
DBG1(DBG_LIB, "received invalid ssh-agent identity response"); DBG1(DBG_LIB, "received invalid ssh-agent identity response");
return FALSE; goto done;
} }
read_uint32(&blob); read_uint32(&blob);
@@ -219,9 +227,12 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
continue; continue;
} }
this->key = chunk_clone(key); this->key = chunk_clone(key);
return TRUE; success = TRUE;
break;
} }
return FALSE; done:
close(socket);
return success;
} }
static bool scheme_supported(private_agent_private_key_t *this, static bool scheme_supported(private_agent_private_key_t *this,
@@ -271,6 +282,8 @@ METHOD(private_key_t, sign, bool,
uint32_t len, flags = 0; uint32_t len, flags = 0;
char buf[2048], *prefix = NULL; char buf[2048], *prefix = NULL;
chunk_t blob; chunk_t blob;
int socket;
bool success = FALSE;
if (!scheme_supported(this, scheme, &flags, &prefix)) if (!scheme_supported(this, scheme, &flags, &prefix))
{ {
@@ -279,46 +292,52 @@ METHOD(private_key_t, sign, bool,
return FALSE; return FALSE;
} }
socket = open_connection(this->path);
if (socket < 0)
{
return FALSE;
}
len = htonl(1 + sizeof(uint32_t) * 3 + this->key.len + data.len); len = htonl(1 + sizeof(uint32_t) * 3 + this->key.len + data.len);
buf[0] = SSH_AGENT_SIGN_REQUEST; buf[0] = SSH_AGENT_SIGN_REQUEST;
if (write(this->socket, &len, sizeof(len)) != sizeof(len) || if (write(socket, &len, sizeof(len)) != sizeof(len) ||
write(this->socket, &buf, 1) != 1) write(socket, &buf, 1) != 1)
{ {
DBG1(DBG_LIB, "writing to ssh-agent failed"); DBG1(DBG_LIB, "writing to ssh-agent failed");
return FALSE; goto done;
} }
len = htonl(this->key.len); len = htonl(this->key.len);
if (write(this->socket, &len, sizeof(len)) != sizeof(len) || if (write(socket, &len, sizeof(len)) != sizeof(len) ||
write(this->socket, this->key.ptr, this->key.len) != this->key.len) write(socket, this->key.ptr, this->key.len) != this->key.len)
{ {
DBG1(DBG_LIB, "writing to ssh-agent failed"); DBG1(DBG_LIB, "writing to ssh-agent failed");
return FALSE; goto done;
} }
len = htonl(data.len); len = htonl(data.len);
if (write(this->socket, &len, sizeof(len)) != sizeof(len) || if (write(socket, &len, sizeof(len)) != sizeof(len) ||
write(this->socket, data.ptr, data.len) != data.len) write(socket, data.ptr, data.len) != data.len)
{ {
DBG1(DBG_LIB, "writing to ssh-agent failed"); DBG1(DBG_LIB, "writing to ssh-agent failed");
return FALSE; goto done;
} }
flags = htonl(flags); flags = htonl(flags);
if (write(this->socket, &flags, sizeof(flags)) != sizeof(flags)) if (write(socket, &flags, sizeof(flags)) != sizeof(flags))
{ {
DBG1(DBG_LIB, "writing to ssh-agent failed"); DBG1(DBG_LIB, "writing to ssh-agent failed");
return FALSE; goto done;
} }
blob = chunk_create(buf, sizeof(buf)); blob = chunk_create(buf, sizeof(buf));
blob.len = read(this->socket, blob.ptr, blob.len); blob.len = read(socket, blob.ptr, blob.len);
if (blob.len < sizeof(uint32_t) + sizeof(u_char) || if (blob.len < sizeof(uint32_t) + sizeof(u_char) ||
read_uint32(&blob) != blob.len || read_uint32(&blob) != blob.len ||
read_byte(&blob) != SSH_AGENT_SIGN_RESPONSE) read_byte(&blob) != SSH_AGENT_SIGN_RESPONSE)
{ {
DBG1(DBG_LIB, "received invalid ssh-agent signature response"); DBG1(DBG_LIB, "received invalid ssh-agent signature response");
return FALSE; goto done;
} }
/* parse length */ /* parse length */
blob = read_string(&blob); blob = read_string(&blob);
@@ -326,7 +345,7 @@ METHOD(private_key_t, sign, bool,
if (prefix && !chunk_equals(read_string(&blob), chunk_from_str(prefix))) if (prefix && !chunk_equals(read_string(&blob), chunk_from_str(prefix)))
{ {
DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix); DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
return FALSE; goto done;
} }
type = this->pubkey->get_type(this->pubkey); type = this->pubkey->get_type(this->pubkey);
if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448) if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448)
@@ -335,7 +354,7 @@ METHOD(private_key_t, sign, bool,
if (blob.len) if (blob.len)
{ {
*signature = chunk_clone(blob); *signature = chunk_clone(blob);
return TRUE; success = TRUE;
} }
} }
else else
@@ -350,12 +369,18 @@ METHOD(private_key_t, sign, bool,
if (r.len && s.len) if (r.len && s.len)
{ {
*signature = chunk_cat("cc", r, s); *signature = chunk_cat("cc", r, s);
return TRUE; success = TRUE;
} }
} }
} }
DBG1(DBG_LIB, "received invalid ssh-agent signature response"); if (!success)
return FALSE; {
DBG1(DBG_LIB, "received invalid ssh-agent signature response");
}
done:
close(socket);
return success;
} }
METHOD(private_key_t, get_type, key_type_t, METHOD(private_key_t, get_type, key_type_t,
@@ -483,9 +508,9 @@ METHOD(private_key_t, destroy, void,
{ {
if (ref_put(&this->ref)) if (ref_put(&this->ref))
{ {
close(this->socket);
chunk_free(&this->key); chunk_free(&this->key);
DESTROY_IF(this->pubkey); DESTROY_IF(this->pubkey);
free(this->path);
free(this); free(this);
} }
} }
@@ -539,15 +564,10 @@ agent_private_key_t *agent_private_key_open(key_type_t type, va_list args)
.destroy = _destroy, .destroy = _destroy,
}, },
}, },
.path = strdup(path),
.ref = 1, .ref = 1,
); );
this->socket = open_connection(path);
if (this->socket < 0)
{
free(this);
return NULL;
}
if (!read_key(this, pubkey)) if (!read_key(this, pubkey))
{ {
destroy(this); destroy(this);