mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-25 15:27:03 +01:00
2004-07-27 Moritz Schulte <moritz@g10code.com>
* command-ssh.c: Use gcrypt memory allocators, use secure memory where necessary. 2004-07-26 Moritz Schulte <moritz@g10code.com> * command-ssh.c (data_sign): Do not forget to unsigned char when constructing human-readable key grip. * Makefile.am (gpg_agent_SOURCES): Removed: buffer.c, buffer.h; updated Libgpg-stream.
This commit is contained in:
parent
da2899b712
commit
809b77941f
@ -1,3 +1,16 @@
|
||||
2004-07-27 Moritz Schulte <moritz@g10code.com>
|
||||
|
||||
* command-ssh.c: Use gcrypt memory allocators, use secure memory
|
||||
where necessary.
|
||||
|
||||
2004-07-26 Moritz Schulte <moritz@g10code.com>
|
||||
|
||||
* command-ssh.c (data_sign): Do not forget to unsigned char when
|
||||
constructing human-readable key grip.
|
||||
|
||||
* Makefile.am (gpg_agent_SOURCES): Removed: buffer.c, buffer.h;
|
||||
updated Libgpg-stream.
|
||||
|
||||
2004-07-24 Moritz Schulte <moritz@g10code.com>
|
||||
|
||||
* gpg-stream-config.h: New file (was missing before).
|
||||
|
@ -30,7 +30,6 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
|
||||
gpg_agent_SOURCES = \
|
||||
gpg-agent.c agent.h \
|
||||
gpg-stream.c gpg-stream.h gpg-stream-config.h \
|
||||
buffer.c buffer.h \
|
||||
command.c command-ssh.c \
|
||||
query.c \
|
||||
cache.c \
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
//#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "agent.h"
|
||||
|
||||
@ -227,7 +227,7 @@ gpg_stream_write_uint32 (gpg_stream_t stream, uint32_t uint32)
|
||||
}
|
||||
|
||||
static gpg_err_code_t
|
||||
gpg_stream_read_string (gpg_stream_t stream,
|
||||
gpg_stream_read_string (gpg_stream_t stream, unsigned int secure,
|
||||
unsigned char **string, uint32_t *string_size)
|
||||
{
|
||||
gpg_err_code_t err = GPG_ERR_NO_ERROR;
|
||||
@ -241,7 +241,10 @@ gpg_stream_read_string (gpg_stream_t stream,
|
||||
goto out;
|
||||
|
||||
/* Allocate space. */
|
||||
buffer = malloc (length + 1);
|
||||
if (secure)
|
||||
buffer = gcry_malloc_secure (length + 1);
|
||||
else
|
||||
buffer = gcry_malloc (length + 1);
|
||||
if (! buffer)
|
||||
{
|
||||
err = gpg_err_code_from_errno (errno);
|
||||
@ -268,7 +271,7 @@ gpg_stream_read_string (gpg_stream_t stream,
|
||||
}
|
||||
else
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
gcry_free (buffer);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -303,8 +306,8 @@ gpg_stream_write_cstring (gpg_stream_t stream, char *string)
|
||||
}
|
||||
|
||||
static gpg_err_code_t
|
||||
gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
|
||||
unsigned int mpi_type)
|
||||
gpg_stream_read_mpint (gpg_stream_t stream, unsigned int secure,
|
||||
mpint_t *mpint, unsigned int mpi_type)
|
||||
{
|
||||
gpg_err_code_t err = GPG_ERR_NO_ERROR;
|
||||
unsigned char *mpi_data = NULL;
|
||||
@ -314,7 +317,8 @@ gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
|
||||
if (! mpi_type)
|
||||
mpi_type = GCRYMPI_FMT_STD;
|
||||
|
||||
err = gpg_stream_read_string (stream, &mpi_data, &mpi_data_size);
|
||||
err = gpg_stream_read_string (stream, secure,
|
||||
&mpi_data, &mpi_data_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -324,7 +328,7 @@ gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
|
||||
|
||||
out:
|
||||
|
||||
free (mpi_data);
|
||||
gcry_free (mpi_data);
|
||||
|
||||
if (! err)
|
||||
*mpint = mpi;
|
||||
@ -333,8 +337,8 @@ gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
|
||||
}
|
||||
|
||||
static gpg_err_code_t
|
||||
gpg_stream_write_mpint (gpg_stream_t stream, mpint_t mpint,
|
||||
unsigned int mpi_type)
|
||||
gpg_stream_write_mpint (gpg_stream_t stream,
|
||||
mpint_t mpint, unsigned int mpi_type)
|
||||
{
|
||||
gpg_err_code_t err = GPG_ERR_NO_ERROR;
|
||||
unsigned char *mpi_buffer = NULL;
|
||||
@ -376,7 +380,7 @@ gpg_stream_read_file (const char *filename,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
buffer_new = malloc (buffer_new_n);
|
||||
buffer_new = gcry_malloc (buffer_new_n);
|
||||
if (! buffer_new)
|
||||
{
|
||||
err = gpg_err_code_from_errno (errno);
|
||||
@ -436,7 +440,7 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
|
||||
unsigned char *key_type = NULL;
|
||||
gcry_mpi_t mpi_iqmp = NULL;
|
||||
|
||||
err = gpg_stream_read_string (stream, &key_type, NULL);
|
||||
err = gpg_stream_read_string (stream, 0, &key_type, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -448,22 +452,22 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
|
||||
{
|
||||
case SSH_KEY_TYPE_RSA:
|
||||
{
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.n, 0);
|
||||
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.n, 0);
|
||||
if (err)
|
||||
break;
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.e, 0);
|
||||
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.e, 0);
|
||||
if (err)
|
||||
break;
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.d, 0);
|
||||
err = gpg_stream_read_mpint (stream, 1, &key.material.rsa.d, 0);
|
||||
if (err)
|
||||
break;
|
||||
err = gpg_stream_read_mpint (stream, &mpi_iqmp, 0);
|
||||
err = gpg_stream_read_mpint (stream, 1, &mpi_iqmp, 0);
|
||||
if (err)
|
||||
break;
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.p, 0);
|
||||
err = gpg_stream_read_mpint (stream, 1, &key.material.rsa.p, 0);
|
||||
if (err)
|
||||
break;
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.q, 0);
|
||||
err = gpg_stream_read_mpint (stream, 1, &key.material.rsa.q, 0);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -483,7 +487,7 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
|
||||
{
|
||||
/* u has to be recomputed. */
|
||||
|
||||
key.material.rsa.u = gcry_mpi_new (0);
|
||||
key.material.rsa.u = gcry_mpi_snew (0);
|
||||
gcry_mpi_invm (key.material.rsa.u,
|
||||
key.material.rsa.p, key.material.rsa.q);
|
||||
}
|
||||
@ -501,19 +505,27 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
|
||||
|
||||
out:
|
||||
|
||||
free (key_type);
|
||||
gcry_free (key_type);
|
||||
gcry_mpi_release (mpi_iqmp);
|
||||
|
||||
if (! err)
|
||||
*key_secret = key;
|
||||
else
|
||||
{
|
||||
gcry_mpi_release (key.material.rsa.n);
|
||||
gcry_mpi_release (key.material.rsa.e);
|
||||
gcry_mpi_release (key.material.rsa.d);
|
||||
gcry_mpi_release (key.material.rsa.p);
|
||||
gcry_mpi_release (key.material.rsa.q);
|
||||
gcry_mpi_release (key.material.rsa.u);
|
||||
switch (key.type)
|
||||
{
|
||||
case SSH_KEY_TYPE_RSA:
|
||||
gcry_mpi_release (key.material.rsa.n);
|
||||
gcry_mpi_release (key.material.rsa.e);
|
||||
gcry_mpi_release (key.material.rsa.d);
|
||||
gcry_mpi_release (key.material.rsa.p);
|
||||
gcry_mpi_release (key.material.rsa.q);
|
||||
gcry_mpi_release (key.material.rsa.u);
|
||||
break;
|
||||
|
||||
case SSH_KEY_TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -558,7 +570,7 @@ ssh_receive_key_public (gpg_stream_t stream, ssh_key_public_t *key_public)
|
||||
ssh_key_public_t key = { 0 };
|
||||
unsigned char *key_type = NULL;
|
||||
|
||||
err = gpg_stream_read_string (stream, &key_type, NULL);
|
||||
err = gpg_stream_read_string (stream, 0, &key_type, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -570,10 +582,10 @@ ssh_receive_key_public (gpg_stream_t stream, ssh_key_public_t *key_public)
|
||||
{
|
||||
case SSH_KEY_TYPE_RSA:
|
||||
{
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.e, 0);
|
||||
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.e, 0);
|
||||
if (err)
|
||||
break;
|
||||
err = gpg_stream_read_mpint (stream, &key.material.rsa.n, 0);
|
||||
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.n, 0);
|
||||
if (err)
|
||||
break;
|
||||
break;
|
||||
@ -589,7 +601,7 @@ ssh_receive_key_public (gpg_stream_t stream, ssh_key_public_t *key_public)
|
||||
|
||||
out:
|
||||
|
||||
free (key_type);
|
||||
gcry_free (key_type);
|
||||
|
||||
if (! err)
|
||||
*key_public = key;
|
||||
@ -670,7 +682,7 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
blob_new = malloc (blob_new_size);
|
||||
blob_new = gcry_malloc (blob_new_size);
|
||||
if (! blob_new)
|
||||
{
|
||||
err = gpg_err_code_from_errno (errno);
|
||||
@ -721,7 +733,7 @@ ssh_key_grip (ssh_key_public_t *public, ssh_key_secret_t *secret,
|
||||
: secret->material.rsa.n,
|
||||
public
|
||||
? public->material.rsa.e
|
||||
: secret->material.rsa.n);
|
||||
: secret->material.rsa.e);
|
||||
break;
|
||||
|
||||
case SSH_KEY_TYPE_NONE:
|
||||
@ -867,7 +879,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
||||
}
|
||||
key_directory_n = strlen (key_directory);
|
||||
|
||||
key_path = malloc (key_directory_n + 46);
|
||||
key_path = gcry_malloc (key_directory_n + 46);
|
||||
if (! key_path)
|
||||
{
|
||||
err = gpg_err_code_from_errno (errno);
|
||||
@ -903,7 +915,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
||||
|
||||
/* Convert it into a public key. */
|
||||
err = ssh_key_public_from_stored_key (buffer, buffer_n, &key);
|
||||
free (buffer);
|
||||
gcry_free (buffer);
|
||||
buffer = NULL;
|
||||
if (err)
|
||||
goto out;
|
||||
@ -915,7 +927,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
||||
|
||||
/* Add key blob to buffer stream. */
|
||||
err = gpg_stream_write_string (key_blobs, key_blob, key_blob_n);
|
||||
free (key_blob);
|
||||
gcry_free (key_blob);
|
||||
key_blob = NULL;
|
||||
if (err)
|
||||
goto out;
|
||||
@ -949,8 +961,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
||||
gpg_stream_destroy (key_blobs);
|
||||
closedir (dir);
|
||||
free (key_directory);
|
||||
free (key_path);
|
||||
free (key_blob);
|
||||
gcry_free (key_path);
|
||||
gcry_free (key_blob);
|
||||
}
|
||||
|
||||
static gpg_err_code_t
|
||||
@ -984,7 +996,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
sprintf (&key_grip[i * 2], "%02X", ctrl->keygrip[i]);
|
||||
sprintf (&key_grip[i * 2], "%02X", (unsigned char) ctrl->keygrip[i]);
|
||||
strncpy (strchr (description, '0'), key_grip, 40);
|
||||
|
||||
err = agent_pksign_do (ctrl, description, &signature_sexp, 0);
|
||||
@ -1039,7 +1051,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
sig_blob = malloc (sig_blob_n);
|
||||
sig_blob = gcry_malloc (sig_blob_n);
|
||||
if (! sig_blob)
|
||||
{
|
||||
err = gpg_err_code_from_errno (errno);
|
||||
@ -1048,7 +1060,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
|
||||
|
||||
err = gpg_stream_read (stream, sig_blob, sig_blob_n, &bytes_read);
|
||||
if ((! err) && (sig_blob_n != bytes_read))
|
||||
err = GPG_ERR_INTERNAL; /* violation */
|
||||
err = GPG_ERR_EOF;
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1067,7 +1079,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
|
||||
{
|
||||
gcry_sexp_release (signature_sexp);
|
||||
gcry_sexp_release (sublist);
|
||||
free (sig_blob);
|
||||
gcry_free (sig_blob);
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -1095,7 +1107,7 @@ ssh_handler_sign_request (ctrl_t ctrl,
|
||||
|
||||
/* Receive key. */
|
||||
|
||||
err = gpg_stream_read_string (request, &key_blob, &key_blob_size);
|
||||
err = gpg_stream_read_string (request, 0, &key_blob, &key_blob_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1105,7 +1117,7 @@ ssh_handler_sign_request (ctrl_t ctrl,
|
||||
|
||||
/* Receive data to sign. */
|
||||
|
||||
err = gpg_stream_read_string (request, &data, &data_size);
|
||||
err = gpg_stream_read_string (request, 0, &data, &data_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1161,9 +1173,9 @@ ssh_handler_sign_request (ctrl_t ctrl,
|
||||
else
|
||||
gpg_stream_write_byte (response, SSH_RESPONSE_FAILURE);
|
||||
|
||||
free (key_blob);
|
||||
free (data);
|
||||
free (sig);
|
||||
gcry_free (key_blob);
|
||||
gcry_free (data);
|
||||
gcry_free (sig);
|
||||
}
|
||||
|
||||
static gpg_err_code_t
|
||||
@ -1194,7 +1206,7 @@ ssh_key_to_sexp_buffer (ssh_key_secret_t *key, const char *passphrase,
|
||||
goto out;
|
||||
|
||||
buffer_new_n = gcry_sexp_sprint (key_sexp, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||
buffer_new = malloc (buffer_new_n);
|
||||
buffer_new = gcry_malloc (buffer_new_n);
|
||||
if (! buffer_new)
|
||||
{
|
||||
err = gpg_err_code_from_errno (errno);
|
||||
@ -1209,10 +1221,8 @@ ssh_key_to_sexp_buffer (ssh_key_secret_t *key, const char *passphrase,
|
||||
|
||||
out:
|
||||
|
||||
if (key_sexp)
|
||||
gcry_sexp_release (key_sexp);
|
||||
if (buffer_new)
|
||||
free (buffer_new);
|
||||
gcry_sexp_release (key_sexp);
|
||||
gcry_free (buffer_new);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1254,24 +1264,35 @@ static gpg_err_code_t
|
||||
ssh_identity_register (ssh_key_secret_t *key, int ttl)
|
||||
{
|
||||
gpg_err_code_t err = GPG_ERR_NO_ERROR;
|
||||
unsigned char key_grip[21] = { 0 };
|
||||
unsigned char key_grip_raw[21] = { 0 };
|
||||
unsigned char *buffer = NULL;
|
||||
unsigned int buffer_n = 0;
|
||||
char passphrase[100] = { 0 };
|
||||
char description[] =
|
||||
"Please provide the passphrase, which should "
|
||||
"be used for protecting the received secret key "
|
||||
"`0123456789012345678901234567890123456789':";
|
||||
unsigned int i = 0;
|
||||
char key_grip[41];
|
||||
int ret = 0;
|
||||
|
||||
if (DBG_COMMAND)
|
||||
log_debug ("[ssh-agent] registering identity `%s'\n", key_grip);
|
||||
|
||||
err = ssh_key_grip (NULL, key, key_grip);
|
||||
err = ssh_key_grip (NULL, key, key_grip_raw);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
ret = agent_key_available (key_grip);
|
||||
ret = agent_key_available (key_grip_raw);
|
||||
if (! ret)
|
||||
goto out;
|
||||
|
||||
err = get_passphrase ("foo", sizeof (passphrase), passphrase);
|
||||
for (i = 0; i < 20; i++)
|
||||
sprintf (&key_grip[i * 2], "%02X", key_grip_raw[i]);
|
||||
strncpy (strchr (description, '0'), key_grip, 40);
|
||||
|
||||
err = get_passphrase (description,
|
||||
sizeof (passphrase), passphrase);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1279,11 +1300,11 @@ ssh_identity_register (ssh_key_secret_t *key, int ttl)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = agent_write_private_key (key_grip, buffer, buffer_n, 0);
|
||||
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = agent_put_cache (key_grip, passphrase, ttl);
|
||||
err = agent_put_cache (key_grip_raw, passphrase, ttl);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1332,7 +1353,7 @@ ssh_handler_add_identity (ctrl_t ctrl,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = gpg_stream_read_string (request, &comment, NULL);
|
||||
err = gpg_stream_read_string (request, 0, &comment, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1382,8 +1403,21 @@ ssh_handler_add_identity (ctrl_t ctrl,
|
||||
out:
|
||||
|
||||
free (comment);
|
||||
|
||||
//ssh_key_destroy (key); FIXME
|
||||
|
||||
switch (key.type)
|
||||
{
|
||||
case SSH_KEY_TYPE_RSA:
|
||||
gcry_mpi_release (key.material.rsa.n);
|
||||
gcry_mpi_release (key.material.rsa.e);
|
||||
gcry_mpi_release (key.material.rsa.d);
|
||||
gcry_mpi_release (key.material.rsa.p);
|
||||
gcry_mpi_release (key.material.rsa.q);
|
||||
gcry_mpi_release (key.material.rsa.u);
|
||||
break;
|
||||
|
||||
case SSH_KEY_TYPE_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
gpg_stream_write_byte (response,
|
||||
err
|
||||
@ -1405,7 +1439,7 @@ ssh_handler_remove_identity (ctrl_t ctrl,
|
||||
if (DBG_COMMAND)
|
||||
log_debug ("[ssh-agent] remove identity\n");
|
||||
|
||||
err = gpg_stream_read_string (request, &key_blob, NULL);
|
||||
err = gpg_stream_read_string (request, 0, &key_blob, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1419,7 +1453,7 @@ ssh_handler_remove_identity (ctrl_t ctrl,
|
||||
|
||||
out:
|
||||
|
||||
free (key_blob);
|
||||
gcry_free (key_blob);
|
||||
|
||||
err = gpg_stream_write_byte (response,
|
||||
err
|
||||
@ -1567,9 +1601,25 @@ gpg_stream_eof_p (gpg_stream_t stream, unsigned int *eof)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* FIXME: Libgcrypt should provide this function. */
|
||||
static void *
|
||||
gcry_realloc_secure (void *mem, size_t size)
|
||||
{
|
||||
if (! mem)
|
||||
return gcry_malloc_secure (size);
|
||||
else
|
||||
return gcry_realloc (mem, size);
|
||||
}
|
||||
|
||||
void
|
||||
start_command_handler_ssh (int sock_client)
|
||||
{
|
||||
gpg_stream_spec_mem_t stream_spec_secure = { NULL, 0, 1,
|
||||
gcry_realloc_secure,
|
||||
gcry_free };
|
||||
gpg_stream_spec_mem_t stream_spec = { NULL, 0, 1,
|
||||
gcry_realloc,
|
||||
gcry_free };
|
||||
struct server_control_s ctrl = { NULL };
|
||||
gpg_err_code_t err = GPG_ERR_NO_ERROR;
|
||||
gpg_stream_t stream_sock = NULL;
|
||||
@ -1598,24 +1648,28 @@ start_command_handler_ssh (int sock_client)
|
||||
if (err || eof)
|
||||
break;
|
||||
|
||||
/* Create memory streams for request/response data. */
|
||||
/* Create memory streams for request/response data. The entire
|
||||
request will be stored in secure memory, since it might
|
||||
contain secret key material. The response does not have to
|
||||
be stored in secure memory, since we never give out secret
|
||||
keys. */
|
||||
stream_request = NULL;
|
||||
err = gpg_stream_create (&stream_request, NULL,
|
||||
err = gpg_stream_create (&stream_request, &stream_spec_secure,
|
||||
GPG_STREAM_FLAG_READ | GPG_STREAM_FLAG_WRITE,
|
||||
gpg_stream_functions_mem);
|
||||
if (err)
|
||||
break;
|
||||
stream_response = NULL;
|
||||
err = gpg_stream_create (&stream_response, NULL,
|
||||
err = gpg_stream_create (&stream_response, &stream_spec,
|
||||
GPG_STREAM_FLAG_READ | GPG_STREAM_FLAG_WRITE,
|
||||
gpg_stream_functions_mem);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
/* Retrieve request length. */
|
||||
free (request);
|
||||
gcry_free (request);
|
||||
request = NULL;
|
||||
err = gpg_stream_read_string (stream_sock, &request, &request_size);
|
||||
err = gpg_stream_read_string (stream_sock, 1, &request, &request_size);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1666,7 +1720,7 @@ start_command_handler_ssh (int sock_client)
|
||||
gpg_stream_destroy (stream_sock);
|
||||
gpg_stream_destroy (stream_request);
|
||||
gpg_stream_destroy (stream_response);
|
||||
free (request);
|
||||
gcry_free (request);
|
||||
|
||||
if (DBG_COMMAND)
|
||||
log_debug ("[ssh-agent] Leaving ssh command handler: %s\n", gpg_strerror (err));
|
||||
|
@ -33,10 +33,430 @@
|
||||
|
||||
#include "gpg-stream.h"
|
||||
#include "gpg-stream-config.h"
|
||||
#include "buffer.h"
|
||||
|
||||
|
||||
|
||||
/* Buffer management layer. */
|
||||
|
||||
#define BUFFER_BLOCK_SIZE 1024
|
||||
|
||||
|
||||
|
||||
typedef struct buffer *buffer_t;
|
||||
|
||||
/* Callbacks, necessary for filling/flushing/seeking. */
|
||||
typedef gpg_error_t (*buffer_func_read_t) (void *handle,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read);
|
||||
typedef gpg_error_t (*buffer_func_write_t) (void *handle,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written);
|
||||
typedef gpg_error_t (*buffer_func_seek_t) (void *handle,
|
||||
off_t offset,
|
||||
int whence);
|
||||
|
||||
typedef gpg_error_t (*buffer_func_stat_t) (void *handle,
|
||||
size_t *size);
|
||||
|
||||
typedef struct buffer_functions
|
||||
{
|
||||
buffer_func_read_t func_read; /* Read callback. */
|
||||
buffer_func_write_t func_write; /* Write callback. */
|
||||
buffer_func_seek_t func_seek; /* Seek callback. */
|
||||
buffer_func_stat_t func_stat; /* Stat callback. */
|
||||
} buffer_functions_t;
|
||||
|
||||
/* Buffer context. */
|
||||
struct buffer
|
||||
{
|
||||
void *handle; /* Handle, passed to callbacks. */
|
||||
buffer_functions_t functions; /* Callback functions. */
|
||||
unsigned int flags; /* General flags. */
|
||||
struct buffer_in
|
||||
{
|
||||
char *container; /* Container holding data. */
|
||||
size_t container_size; /* Size of CONTAINER. */
|
||||
size_t data_size; /* Size of data in CONTAINER. */
|
||||
off_t data_offset; /* Offset inside of CONTAINER. */
|
||||
} buffer_in;
|
||||
struct buffer_out
|
||||
{
|
||||
char *container; /* Container holding data. */
|
||||
size_t container_size; /* Size of CONTAINER. */
|
||||
size_t data_size; /* Size of data in CONTAINER. */
|
||||
off_t data_offset; /* Offset inside of CONTAINER. */
|
||||
size_t data_flushed; /* Amount of data already flushed. */
|
||||
} buffer_out;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Buffer contains unflushed data. */
|
||||
#define BUFFER_FLAG_DIRTY (1 << 0)
|
||||
|
||||
|
||||
|
||||
/* Fill buffer. */
|
||||
static gpg_error_t
|
||||
buffer_fill_do (buffer_t buffer)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (! buffer->functions.func_read)
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
else
|
||||
{
|
||||
buffer_func_read_t func_read = buffer->functions.func_read;
|
||||
|
||||
err = (*func_read) (buffer->handle,
|
||||
buffer->buffer_in.container,
|
||||
buffer->buffer_in.container_size,
|
||||
&bytes_read);
|
||||
}
|
||||
|
||||
buffer->buffer_in.data_offset = 0;
|
||||
buffer->buffer_in.data_size = bytes_read;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Empty buffer input. */
|
||||
static gpg_error_t
|
||||
buffer_empty (buffer_t buffer)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
buffer->buffer_in.data_size = 0;
|
||||
buffer->buffer_in.data_offset = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Flush data contained in buffer. */
|
||||
static gpg_error_t
|
||||
buffer_flush_do (buffer_t buffer)
|
||||
{
|
||||
buffer_func_write_t func_write = buffer->functions.func_write;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
if (! func_write)
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
else if (buffer->flags & BUFFER_FLAG_DIRTY)
|
||||
while ((buffer->buffer_out.data_size
|
||||
- buffer->buffer_out.data_flushed) && (! err))
|
||||
{
|
||||
|
||||
err = (*func_write) (buffer->handle,
|
||||
buffer->buffer_out.container
|
||||
+ buffer->buffer_out.data_flushed,
|
||||
buffer->buffer_out.data_size
|
||||
- buffer->buffer_out.data_flushed,
|
||||
&bytes_written);
|
||||
if (! err)
|
||||
{
|
||||
buffer->buffer_out.data_size = 0;
|
||||
buffer->buffer_out.data_offset = 0;
|
||||
buffer->buffer_out.data_flushed = 0;
|
||||
buffer->flags &= ~BUFFER_FLAG_DIRTY;
|
||||
}
|
||||
else
|
||||
buffer->buffer_out.data_flushed += bytes_written;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
buffer_stat_do (buffer_t buffer,
|
||||
size_t *size)
|
||||
{
|
||||
buffer_func_stat_t func_stat = buffer->functions.func_stat;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = (*func_stat) (buffer->handle, size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read from a buffer. */
|
||||
gpg_error_t
|
||||
buffer_read (buffer_t buffer,
|
||||
char *data,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
size_t data_read = 0;
|
||||
size_t data_to_copy = 0;
|
||||
|
||||
if (! (buffer->flags & BUFFER_FLAG_DIRTY))
|
||||
err = buffer_flush_do (buffer);
|
||||
|
||||
while ((bytes_to_read - data_read) && (! err))
|
||||
{
|
||||
if (buffer->buffer_in.data_offset == buffer->buffer_in.data_size)
|
||||
{
|
||||
/* Nothing more to read in current container, try to
|
||||
fill container with new data. */
|
||||
err = buffer_fill_do (buffer);
|
||||
if (! err)
|
||||
if (! buffer->buffer_in.data_size)
|
||||
/* Filling did not result in any data read. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (! err)
|
||||
{
|
||||
if ((bytes_to_read
|
||||
- data_read) > (buffer->buffer_in.data_size
|
||||
- buffer->buffer_in.data_offset))
|
||||
data_to_copy = (buffer->buffer_in.data_size
|
||||
- buffer->buffer_in.data_offset);
|
||||
else
|
||||
data_to_copy = bytes_to_read - data_read;
|
||||
|
||||
memcpy (data + data_read,
|
||||
buffer->buffer_in.container + buffer->buffer_in.data_offset,
|
||||
data_to_copy);
|
||||
buffer->buffer_in.data_offset += data_to_copy;
|
||||
data_read += data_to_copy;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_read)
|
||||
*bytes_read = data_read;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Write to a buffer. */
|
||||
gpg_error_t
|
||||
buffer_write (buffer_t buffer,
|
||||
const char *data,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
size_t data_written = 0;
|
||||
size_t data_to_copy = 0;
|
||||
|
||||
while ((bytes_to_write - data_written) && (! err))
|
||||
{
|
||||
if (buffer->buffer_out.data_offset == buffer->buffer_out.container_size)
|
||||
/* Container full, flush buffer. */
|
||||
err = buffer_flush_do (buffer);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
if ((bytes_to_write
|
||||
- data_written) > (buffer->buffer_out.container_size
|
||||
- buffer->buffer_out.data_offset))
|
||||
data_to_copy = (buffer->buffer_out.container_size
|
||||
- buffer->buffer_out.data_offset);
|
||||
else
|
||||
data_to_copy = bytes_to_write - data_written;
|
||||
|
||||
memcpy (buffer->buffer_out.container
|
||||
+ buffer->buffer_out.data_offset,
|
||||
data + data_written,
|
||||
data_to_copy);
|
||||
if ((buffer->buffer_out.data_offset
|
||||
+ data_to_copy) > buffer->buffer_out.data_size)
|
||||
buffer->buffer_out.data_size = (buffer->buffer_out.data_offset
|
||||
+ data_to_copy);
|
||||
buffer->buffer_out.data_offset += data_to_copy;
|
||||
data_written += data_to_copy;
|
||||
|
||||
if (data_written)
|
||||
if (! (buffer->flags & BUFFER_FLAG_DIRTY))
|
||||
buffer->flags |= BUFFER_FLAG_DIRTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_written)
|
||||
*bytes_written = data_written;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Seek in a buffer. */
|
||||
gpg_error_t
|
||||
buffer_seek (buffer_t buffer,
|
||||
off_t offset,
|
||||
int whence)
|
||||
{
|
||||
buffer_func_seek_t func_seek = buffer->functions.func_seek;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (! func_seek)
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
else
|
||||
{
|
||||
if (buffer->flags & BUFFER_FLAG_DIRTY)
|
||||
/* Flush data first in order to prevent flushing it to the
|
||||
wrong offset. */
|
||||
err = buffer_flush_do (buffer);
|
||||
|
||||
if (! err)
|
||||
err = (*func_seek) (buffer->handle, offset, whence);
|
||||
|
||||
if (! err)
|
||||
err = buffer_empty (buffer);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Return the unread data contained in a buffer. */
|
||||
gpg_error_t
|
||||
buffer_peek (buffer_t buffer,
|
||||
char **data,
|
||||
size_t *data_size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (buffer->buffer_in.data_offset == buffer->buffer_in.data_size)
|
||||
/* Refill container. */
|
||||
err = buffer_fill_do (buffer);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
if (data)
|
||||
*data = buffer->buffer_in.container + buffer->buffer_in.data_offset;
|
||||
if (data_size)
|
||||
*data_size = buffer->buffer_in.data_size - buffer->buffer_in.data_offset;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Skip SIZE bytes of input data contained in buffer. */
|
||||
gpg_error_t
|
||||
buffer_skip (buffer_t buffer,
|
||||
size_t size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (buffer->buffer_in.data_offset + size > buffer->buffer_in.data_size)
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
else
|
||||
buffer->buffer_in.data_offset += size;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a new buffer. */
|
||||
gpg_error_t
|
||||
buffer_create (buffer_t *buffer,
|
||||
void *handle,
|
||||
buffer_functions_t functions)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
/* Allocate memory, initialize. */
|
||||
|
||||
buffer_t buffer_new = NULL;
|
||||
char *container_in_new = NULL;
|
||||
char *container_out_new = NULL;
|
||||
|
||||
buffer_new = malloc (sizeof (*buffer_new));
|
||||
if (! buffer_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
container_in_new = malloc (BUFFER_BLOCK_SIZE);
|
||||
if (! container_in_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
}
|
||||
if (! err)
|
||||
{
|
||||
container_out_new = malloc (BUFFER_BLOCK_SIZE);
|
||||
if (! container_out_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
}
|
||||
|
||||
if (! err)
|
||||
{
|
||||
buffer_new->handle = handle;
|
||||
buffer_new->flags = 0;
|
||||
buffer_new->functions = functions;
|
||||
buffer_new->buffer_in.container = container_in_new;
|
||||
buffer_new->buffer_in.container_size = BUFFER_BLOCK_SIZE;
|
||||
buffer_new->buffer_in.data_size = 0;
|
||||
buffer_new->buffer_in.data_offset = 0;
|
||||
buffer_new->buffer_out.container = container_out_new;
|
||||
buffer_new->buffer_out.container_size = BUFFER_BLOCK_SIZE;
|
||||
buffer_new->buffer_out.data_size = 0;
|
||||
buffer_new->buffer_out.data_offset = 0;
|
||||
buffer_new->buffer_out.data_flushed = 0;
|
||||
*buffer = buffer_new;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (container_in_new)
|
||||
free (container_in_new);
|
||||
if (container_out_new)
|
||||
free (container_out_new);
|
||||
if (buffer_new)
|
||||
free (buffer_new);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Destroy a buffer. */
|
||||
gpg_error_t
|
||||
buffer_destroy (buffer_t buffer)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
err = buffer_flush_do (buffer);
|
||||
free (buffer->buffer_in.container);
|
||||
free (buffer->buffer_out.container);
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Write out unwritten data contained in buffer. */
|
||||
gpg_error_t
|
||||
buffer_flush (buffer_t buffer)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = buffer_flush_do (buffer);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Stat buffer. */
|
||||
gpg_error_t
|
||||
buffer_stat (buffer_t buffer,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = buffer_stat_do (buffer, size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Stream layer. */
|
||||
|
||||
/* A Stream Context. */
|
||||
struct gpg_stream
|
||||
{
|
||||
@ -66,6 +486,9 @@ struct gpg_stream
|
||||
|
||||
/* Implementation of Memory I/O. */
|
||||
|
||||
typedef void *(*mem_func_realloc_t) (void *mem, size_t size);
|
||||
typedef void (*mem_func_free_t) (void *mem);
|
||||
|
||||
typedef struct gpg_stream_handle_mem
|
||||
{
|
||||
char *memory; /* Data. */
|
||||
@ -73,6 +496,8 @@ typedef struct gpg_stream_handle_mem
|
||||
size_t data_size; /* Size of data in MEMORY. */
|
||||
unsigned int grow: 1; /* MEMORY is allowed to grow. */
|
||||
size_t offset; /* Current offset in MEMORY. */
|
||||
mem_func_realloc_t func_realloc;
|
||||
mem_func_free_t func_free;
|
||||
} *gpg_stream_handle_mem_t;
|
||||
|
||||
static gpg_error_t
|
||||
@ -94,6 +519,10 @@ gpg_stream_func_mem_create (void **handle,
|
||||
mem_handle->data_size = 0;
|
||||
mem_handle->grow = mem_spec ? mem_spec->grow : 1;
|
||||
mem_handle->offset = 0;
|
||||
mem_handle->func_realloc = ((mem_spec && mem_spec->func_realloc)
|
||||
? mem_spec->func_realloc : realloc);
|
||||
mem_handle->func_free = ((mem_spec && mem_spec->func_free)
|
||||
? mem_spec->func_free : free);
|
||||
*handle = mem_handle;
|
||||
}
|
||||
|
||||
@ -136,8 +565,9 @@ gpg_stream_func_mem_write (void *handle,
|
||||
|
||||
while (bytes_to_write > mem_handle->memory_size - mem_handle->offset)
|
||||
{
|
||||
memory_new = realloc (mem_handle->memory,
|
||||
mem_handle->memory_size + BUFFER_BLOCK_SIZE);
|
||||
memory_new = (*mem_handle->func_realloc)
|
||||
(mem_handle->memory,
|
||||
mem_handle->memory_size + BUFFER_BLOCK_SIZE);
|
||||
if (! memory_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
@ -216,7 +646,7 @@ gpg_stream_func_mem_destroy (void *handle)
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (mem_handle->memory)
|
||||
free (mem_handle->memory);
|
||||
(*mem_handle->func_free) (mem_handle->memory);
|
||||
free (mem_handle);
|
||||
|
||||
return err;
|
||||
|
@ -129,6 +129,8 @@ typedef struct gpg_stream_spec_mem
|
||||
char *memory;
|
||||
size_t memory_size;
|
||||
unsigned int grow: 1;
|
||||
void *(*func_realloc) (void *mem, size_t size);
|
||||
void (*func_free) (void *mem);
|
||||
} gpg_stream_spec_mem_t;
|
||||
|
||||
extern gpg_stream_functions_t gpg_stream_functions_mem;
|
||||
|
Loading…
x
Reference in New Issue
Block a user