mirror of
git://git.gnupg.org/gnupg.git
synced 2025-02-01 16:33:02 +01:00
2004-07-19 Moritz Schulte <moritz@g10code.com>
* Makefile.am (gpg_agent_SOURCES): Adding: gpg-stream.c, gpg-stream.h, buffer.c, buffer.h, command-ssh.c. * pksign.c (agent_pksign_do): New function, based on code ripped out from agent_pksign. (agent_pksign): Use agent_pksign_do. * query.c (start_pinentry): Accept CTRL being NULL. * agent.h (start_command_handler_ssh): Declare function. (agent_pksign_do): Declare function. (opt): New member: ssh_support. * gpg-agent.c: Include <sys/select.h>. New configuration option: ssh-support. (socket_name_ssh): New variabel. (handle_connections): Additional argument: listen_fd_ssh. Accept connections on both sockets, call start_connection_thread_ssh for connections on listen_fd_ssh. (start_connection_thread_ssh): New function. (cleanup_do): New functions, basically old cleanup function. (cleanup): Call cleanup_do for socket_name and socket_name_ssh. (server_socket_create): New function ... (main): ... use it. (main): Generate environment entries for ssh. * command-ssh.c: New file, implementing the ssh-agent protocol. * gpg-stream.c, gpg-stream.h, buffer.c, buffer.h: Merged Libgpg-stream.
This commit is contained in:
parent
6decea8316
commit
15664a8598
@ -1,3 +1,35 @@
|
||||
2004-07-19 Moritz Schulte <moritz@g10code.com>
|
||||
|
||||
* Makefile.am (gpg_agent_SOURCES): Adding: gpg-stream.c,
|
||||
gpg-stream.h, buffer.c, buffer.h, command-ssh.c.
|
||||
|
||||
* pksign.c (agent_pksign_do): New function, based on code ripped
|
||||
out from agent_pksign.
|
||||
(agent_pksign): Use agent_pksign_do.
|
||||
|
||||
* query.c (start_pinentry): Accept CTRL being NULL.
|
||||
|
||||
* agent.h (start_command_handler_ssh): Declare function.
|
||||
(agent_pksign_do): Declare function.
|
||||
(opt): New member: ssh_support.
|
||||
|
||||
* gpg-agent.c: Include <sys/select.h>.
|
||||
New configuration option: ssh-support.
|
||||
(socket_name_ssh): New variabel.
|
||||
(handle_connections): Additional argument: listen_fd_ssh. Accept
|
||||
connections on both sockets, call start_connection_thread_ssh for
|
||||
connections on listen_fd_ssh.
|
||||
(start_connection_thread_ssh): New function.
|
||||
(cleanup_do): New functions, basically old cleanup function.
|
||||
(cleanup): Call cleanup_do for socket_name and socket_name_ssh.
|
||||
(server_socket_create): New function ...
|
||||
(main): ... use it.
|
||||
(main): Generate environment entries for ssh.
|
||||
|
||||
* command-ssh.c: New file, implementing the ssh-agent protocol.
|
||||
* gpg-stream.c, gpg-stream.h, buffer.c, buffer.h: Merged
|
||||
Libgpg-stream.
|
||||
|
||||
2004-06-20 Moritz Schulte <moritz@g10code.com>
|
||||
|
||||
* gpg-agent.c: Include <sys/stat.h> (build fix for BSD).
|
||||
|
@ -29,7 +29,9 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
|
||||
|
||||
gpg_agent_SOURCES = \
|
||||
gpg-agent.c agent.h \
|
||||
command.c \
|
||||
gpg-stream.c gpg-stream.h gpg-stream-config.h \
|
||||
buffer.c buffer.h \
|
||||
command.c command-ssh.c \
|
||||
query.c \
|
||||
cache.c \
|
||||
trans.c \
|
||||
|
@ -61,6 +61,7 @@ struct {
|
||||
int allow_mark_trusted;
|
||||
int keep_tty; /* don't switch the TTY (for pinentry) on request */
|
||||
int keep_display; /* don't switch the DISPLAY (for pinentry) on request */
|
||||
int ssh_support; /* enable SSH-Agent emulation. */
|
||||
} opt;
|
||||
|
||||
|
||||
@ -130,6 +131,9 @@ void agent_init_default_ctrl (struct server_control_s *ctrl);
|
||||
/*-- command.c --*/
|
||||
void start_command_handler (int, int);
|
||||
|
||||
/*-- command-ssh.c --*/
|
||||
void start_command_handler_ssh (int);
|
||||
|
||||
/*-- findkey.c --*/
|
||||
int agent_write_private_key (const unsigned char *grip,
|
||||
const void *buffer, size_t length, int force);
|
||||
@ -158,6 +162,8 @@ void agent_unlock_cache_entry (void **cache_id);
|
||||
|
||||
|
||||
/*-- pksign.c --*/
|
||||
int agent_pksign_do (CTRL ctrl, const char *desc_text,
|
||||
gcry_sexp_t *signature_sexp, int ignore_cache);
|
||||
int agent_pksign (ctrl_t ctrl, const char *desc_text,
|
||||
FILE *outfp, int ignore_cache);
|
||||
|
||||
|
413
agent/buffer.c
Normal file
413
agent/buffer.c
Normal file
@ -0,0 +1,413 @@
|
||||
/* buffer.c - Buffer management layer
|
||||
Copyright (C) 2004 g10 Code GmbH
|
||||
|
||||
This file is part of libgpg-stream.
|
||||
|
||||
libgpg-stream is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
libgpg-stream is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libgpg-stream; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <gpg-error.h>
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
102
agent/buffer.h
Normal file
102
agent/buffer.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* buffer.h - Buffer management layer
|
||||
Copyright (C) 2004 g10 Code GmbH
|
||||
|
||||
This file is part of libgpg-stream.
|
||||
|
||||
libgpg-stream is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
libgpg-stream is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libgpg-stream; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <gpg-error.h>
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
/* Create a new buffer. */
|
||||
gpg_error_t buffer_create (buffer_t *buffer,
|
||||
void *handle,
|
||||
buffer_functions_t functions);
|
||||
|
||||
/* Destroy a buffer. */
|
||||
gpg_error_t buffer_destroy (buffer_t buffer);
|
||||
|
||||
/* Read from a buffer. */
|
||||
gpg_error_t buffer_read (buffer_t buffer,
|
||||
char *data,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read);
|
||||
|
||||
/* Write to a buffer. */
|
||||
gpg_error_t buffer_write (buffer_t buffer,
|
||||
const char *data,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written);
|
||||
|
||||
/* Seek in a buffer. */
|
||||
gpg_error_t buffer_seek (buffer_t buffer,
|
||||
off_t offset,
|
||||
int whence);
|
||||
|
||||
/* Return the unread data contained in a buffer. */
|
||||
gpg_error_t buffer_peek (buffer_t buffer,
|
||||
char **data,
|
||||
size_t *data_size);
|
||||
|
||||
/* Skip SIZE bytes of input data contained in buffer. */
|
||||
gpg_error_t buffer_skip (buffer_t buffer,
|
||||
size_t size);
|
||||
|
||||
/* Write out unwritten data contained in buffer. */
|
||||
gpg_error_t buffer_flush (buffer_t buffer);
|
||||
|
||||
/* Stat buffer. */
|
||||
gpg_error_t buffer_stat (buffer_t buffer,
|
||||
size_t *size);
|
||||
|
||||
#endif
|
1694
agent/command-ssh.c
Normal file
1694
agent/command-ssh.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
@ -84,8 +85,8 @@ enum cmd_and_opt_values
|
||||
oAllowMarkTrusted,
|
||||
oKeepTTY,
|
||||
oKeepDISPLAY,
|
||||
|
||||
aTest };
|
||||
aTest,
|
||||
oSSHSupport };
|
||||
|
||||
|
||||
|
||||
@ -131,6 +132,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
N_("do not use the PIN cache when signing")},
|
||||
{ oAllowMarkTrusted, "allow-mark-trusted", 0,
|
||||
N_("allow clients to mark keys as \"trusted\"")},
|
||||
{ oSSHSupport, "ssh-support", 0, "Enable SSH-Agent emulation" },
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -149,6 +152,9 @@ static int maybe_setuid = 1;
|
||||
/* Name of the communication socket */
|
||||
static char socket_name[128];
|
||||
|
||||
/* Name of the communication socket used for ssh-agent-emulation. */
|
||||
static char socket_name_ssh[128];
|
||||
|
||||
/* Default values for options passed to the pinentry. */
|
||||
static char *default_display;
|
||||
static char *default_ttyname;
|
||||
@ -169,7 +175,7 @@ static char *current_logfile;
|
||||
/* Local prototypes. */
|
||||
static void create_directories (void);
|
||||
#ifdef USE_GNU_PTH
|
||||
static void handle_connections (int listen_fd);
|
||||
static void handle_connections (int listen_fd, int listen_fd_ssh);
|
||||
|
||||
/* Pth wrapper function definitions. */
|
||||
GCRY_THREAD_OPTION_PTH_IMPL;
|
||||
@ -280,25 +286,30 @@ set_debug (void)
|
||||
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
|
||||
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cleanup_do (char *name)
|
||||
{
|
||||
char *p = NULL;
|
||||
|
||||
remove (name);
|
||||
p = strrchr (name, '/');
|
||||
if (p)
|
||||
{
|
||||
*p = 0;
|
||||
rmdir (name);
|
||||
*p = '/';
|
||||
}
|
||||
*name = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup (void)
|
||||
{
|
||||
if (*socket_name)
|
||||
{
|
||||
char *p;
|
||||
|
||||
remove (socket_name);
|
||||
p = strrchr (socket_name, '/');
|
||||
if (p)
|
||||
{
|
||||
*p = 0;
|
||||
rmdir (socket_name);
|
||||
*p = '/';
|
||||
}
|
||||
*socket_name = 0;
|
||||
}
|
||||
cleanup_do (socket_name);
|
||||
if (*socket_name_ssh)
|
||||
cleanup_do (socket_name_ssh);
|
||||
}
|
||||
|
||||
|
||||
@ -383,6 +394,76 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
static void
|
||||
server_socket_create (int *sock,
|
||||
const char *identifier, char *name, int name_size)
|
||||
{
|
||||
struct sockaddr_un serv_addr;
|
||||
char *p = NULL;
|
||||
int fd = -1;
|
||||
socklen_t len;
|
||||
|
||||
*name = 0;
|
||||
snprintf (name, name_size - 1,
|
||||
"/tmp/gpg-XXXXXX/S.gpg-agent%s",
|
||||
identifier ? identifier : "");
|
||||
name[name_size - 1] = 0;
|
||||
|
||||
if (strchr (name, ':'))
|
||||
{
|
||||
log_error ("colons are not allowed in the socket name\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
p = strrchr (name, '/');
|
||||
if (! p)
|
||||
BUG ();
|
||||
*p = 0;;
|
||||
if (! mkdtemp (name))
|
||||
{
|
||||
log_error ("can't create directory `%s': %s\n",
|
||||
name, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
*p = '/';
|
||||
|
||||
if (strlen (name) + 1 >= sizeof (serv_addr.sun_path))
|
||||
{
|
||||
log_error ("name of socket too long\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
log_error ("can't create socket: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
memset (&serv_addr, 0, sizeof serv_addr);
|
||||
serv_addr.sun_family = AF_UNIX;
|
||||
strcpy (serv_addr.sun_path, name);
|
||||
len = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen (serv_addr.sun_path) + 1);
|
||||
|
||||
if (bind (fd, (struct sockaddr*) &serv_addr, len) == -1)
|
||||
{
|
||||
log_error ("error binding socket to `%s': %s\n",
|
||||
serv_addr.sun_path, strerror (errno));
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (listen (fd, 5) == -1)
|
||||
{
|
||||
log_error ("listen() failed: %s\n", strerror (errno));
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
*sock = fd;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv )
|
||||
@ -568,6 +649,12 @@ main (int argc, char **argv )
|
||||
case oKeepTTY: opt.keep_tty = 1; break;
|
||||
case oKeepDISPLAY: opt.keep_display = 1; break;
|
||||
|
||||
case oSSHSupport:
|
||||
opt.ssh_support = 1;
|
||||
opt.keep_tty = 1;
|
||||
opt.keep_display = 1;
|
||||
break;
|
||||
|
||||
default : pargs.err = configfp? 1:2; break;
|
||||
}
|
||||
}
|
||||
@ -702,12 +789,10 @@ main (int argc, char **argv )
|
||||
else if (!is_daemon)
|
||||
;
|
||||
else
|
||||
{ /* regular server mode */
|
||||
int fd;
|
||||
{ /* regular server mode */
|
||||
int fd = -1, fd_ssh = -1;
|
||||
pid_t pid;
|
||||
int len;
|
||||
struct sockaddr_un serv_addr;
|
||||
char *p;
|
||||
//char *p;
|
||||
|
||||
/* Remove the DISPLAY variable so that a pinentry does not
|
||||
default to a specific display. There is still a default
|
||||
@ -716,65 +801,18 @@ main (int argc, char **argv )
|
||||
if (!opt.keep_display)
|
||||
unsetenv ("DISPLAY");
|
||||
|
||||
*socket_name = 0;
|
||||
snprintf (socket_name, DIM(socket_name)-1,
|
||||
"/tmp/gpg-XXXXXX/S.gpg-agent");
|
||||
socket_name[DIM(socket_name)-1] = 0;
|
||||
p = strrchr (socket_name, '/');
|
||||
if (!p)
|
||||
BUG ();
|
||||
*p = 0;;
|
||||
if (!mkdtemp(socket_name))
|
||||
{
|
||||
log_error ("can't create directory `%s': %s\n",
|
||||
socket_name, strerror(errno) );
|
||||
exit (1);
|
||||
}
|
||||
*p = '/';
|
||||
server_socket_create (&fd, "", socket_name, sizeof (socket_name));
|
||||
if (opt.ssh_support)
|
||||
server_socket_create (&fd_ssh, "-ssh",
|
||||
socket_name_ssh, sizeof (socket_name_ssh));
|
||||
|
||||
if (strchr (socket_name, ':') )
|
||||
{
|
||||
log_error ("colons are not allowed in the socket name\n");
|
||||
exit (1);
|
||||
}
|
||||
if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
|
||||
{
|
||||
log_error ("name of socket too long\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
log_error ("can't create socket: %s\n", strerror(errno) );
|
||||
exit (1);
|
||||
}
|
||||
|
||||
memset (&serv_addr, 0, sizeof serv_addr);
|
||||
serv_addr.sun_family = AF_UNIX;
|
||||
strcpy (serv_addr.sun_path, socket_name);
|
||||
len = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen(serv_addr.sun_path) + 1);
|
||||
|
||||
if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
|
||||
{
|
||||
log_error ("error binding socket to `%s': %s\n",
|
||||
serv_addr.sun_path, strerror (errno) );
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (listen (fd, 5 ) == -1)
|
||||
{
|
||||
log_error ("listen() failed: %s\n", strerror (errno));
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("listening on socket `%s'\n", socket_name );
|
||||
|
||||
{
|
||||
log_info ("listening on socket `%s'\n", socket_name);
|
||||
if (opt.ssh_support)
|
||||
log_info ("listening on socket `%s'\n", socket_name_ssh);
|
||||
}
|
||||
|
||||
fflush (NULL);
|
||||
pid = fork ();
|
||||
@ -785,9 +823,11 @@ main (int argc, char **argv )
|
||||
}
|
||||
else if (pid)
|
||||
{ /* We are the parent */
|
||||
char *infostr;
|
||||
char *infostr, *infostr_ssh_sock, *infostr_ssh_pid;
|
||||
|
||||
close (fd);
|
||||
if (opt.ssh_support)
|
||||
close (fd_ssh);
|
||||
|
||||
/* create the info string: <name>:<pid>:<protocol_version> */
|
||||
if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
|
||||
@ -797,8 +837,28 @@ main (int argc, char **argv )
|
||||
kill (pid, SIGTERM);
|
||||
exit (1);
|
||||
}
|
||||
if (opt.ssh_support)
|
||||
{
|
||||
if (asprintf (&infostr_ssh_sock, "SSH_AUTH_SOCK=%s",
|
||||
socket_name_ssh) < 0)
|
||||
{
|
||||
log_error ("out of core\n");
|
||||
kill (pid, SIGTERM);
|
||||
exit (1);
|
||||
}
|
||||
if (asprintf (&infostr_ssh_pid, "SSH_AGENT_PID=%u",
|
||||
pid) < 0)
|
||||
{
|
||||
log_error ("out of core\n");
|
||||
kill (pid, SIGTERM);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
*socket_name = 0; /* don't let cleanup() remove the socket -
|
||||
the child should do this from now on */
|
||||
*socket_name_ssh = 0;
|
||||
|
||||
if (argc)
|
||||
{ /* run the program given on the commandline */
|
||||
if (putenv (infostr))
|
||||
@ -808,6 +868,20 @@ main (int argc, char **argv )
|
||||
kill (pid, SIGTERM );
|
||||
exit (1);
|
||||
}
|
||||
if (putenv (infostr_ssh_sock))
|
||||
{
|
||||
log_error ("failed to set environment: %s\n",
|
||||
strerror (errno) );
|
||||
kill (pid, SIGTERM );
|
||||
exit (1);
|
||||
}
|
||||
if (putenv (infostr_ssh_pid))
|
||||
{
|
||||
log_error ("failed to set environment: %s\n",
|
||||
strerror (errno) );
|
||||
kill (pid, SIGTERM );
|
||||
exit (1);
|
||||
}
|
||||
execvp (argv[0], argv);
|
||||
log_error ("failed to run the command: %s\n", strerror (errno));
|
||||
kill (pid, SIGTERM);
|
||||
@ -821,12 +895,29 @@ main (int argc, char **argv )
|
||||
{
|
||||
*strchr (infostr, '=') = ' ';
|
||||
printf ( "setenv %s\n", infostr);
|
||||
if (opt.ssh_support)
|
||||
{
|
||||
*strchr (infostr_ssh_sock, '=') = ' ';
|
||||
printf ( "setenv %s\n", infostr_ssh_sock);
|
||||
*strchr (infostr_ssh_pid, '=') = ' ';
|
||||
printf ( "setenv %s\n", infostr_ssh_pid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
|
||||
if (opt.ssh_support)
|
||||
{
|
||||
printf ( "%s; export SSH_AUTH_SOCK;\n", infostr_ssh_sock);
|
||||
printf ( "%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
|
||||
}
|
||||
}
|
||||
free (infostr);
|
||||
if (opt.ssh_support)
|
||||
{
|
||||
free (infostr_ssh_sock);
|
||||
free (infostr_ssh_pid);
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
/*NEVER REACHED*/
|
||||
@ -877,7 +968,7 @@ main (int argc, char **argv )
|
||||
sigemptyset (&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction (SIGPIPE, &sa, NULL);
|
||||
handle_connections (fd);
|
||||
handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
|
||||
}
|
||||
else
|
||||
#endif /*!USE_GNU_PTH*/
|
||||
@ -903,7 +994,7 @@ main (int argc, char **argv )
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1144,24 +1235,40 @@ start_connection_thread (void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
start_connection_thread_ssh (void *arg)
|
||||
{
|
||||
int fd = (int)arg;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("ssh handler for fd %d started\n", fd);
|
||||
|
||||
/* FIXME: Move this housekeeping into a ticker function. Calling it
|
||||
for each connection should work but won't work anymore if our
|
||||
cleints start to keep connections. */
|
||||
agent_trustlist_housekeeping ();
|
||||
|
||||
start_command_handler_ssh (fd);
|
||||
if (opt.verbose)
|
||||
log_info ("ssh handler for fd %d terminated\n", fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_connections (int listen_fd)
|
||||
handle_connections (int listen_fd, int listen_fd_ssh)
|
||||
{
|
||||
pth_attr_t tattr;
|
||||
pth_event_t ev;
|
||||
sigset_t sigs;
|
||||
int signo;
|
||||
struct sockaddr_un paddr;
|
||||
socklen_t plen = sizeof( paddr );
|
||||
pth_attr_t tattr;
|
||||
fd_set fdset, read_fdset;
|
||||
int ret = -1;
|
||||
int fd;
|
||||
|
||||
tattr = pth_attr_new();
|
||||
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
|
||||
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
|
||||
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
|
||||
|
||||
sigemptyset (&sigs );
|
||||
sigemptyset (&sigs);
|
||||
sigaddset (&sigs, SIGHUP);
|
||||
sigaddset (&sigs, SIGUSR1);
|
||||
sigaddset (&sigs, SIGUSR2);
|
||||
@ -1169,6 +1276,16 @@ handle_connections (int listen_fd)
|
||||
sigaddset (&sigs, SIGTERM);
|
||||
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
|
||||
|
||||
tattr = pth_attr_new();
|
||||
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
|
||||
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
|
||||
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
|
||||
|
||||
FD_ZERO (&fdset);
|
||||
FD_SET (listen_fd, &fdset);
|
||||
if (listen_fd_ssh != -1)
|
||||
FD_SET (listen_fd_ssh, &fdset);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (shutdown_pending)
|
||||
@ -1185,28 +1302,67 @@ handle_connections (int listen_fd)
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
|
||||
if (fd == -1)
|
||||
{
|
||||
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
|
||||
if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
|
||||
#else
|
||||
if (pth_event_occurred (ev))
|
||||
#endif
|
||||
{
|
||||
handle_signal (signo);
|
||||
continue;
|
||||
}
|
||||
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
|
||||
pth_sleep(1);
|
||||
continue;
|
||||
read_fdset = fdset;
|
||||
ret = pth_select (FD_SETSIZE, &read_fdset, NULL, NULL, NULL);
|
||||
if (ret == -1)
|
||||
{
|
||||
log_error ("pth_select failed: %s - waiting 1s\n",
|
||||
strerror (errno));
|
||||
pth_sleep (1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
|
||||
{
|
||||
log_error ("error spawning connection handler: %s\n",
|
||||
strerror (errno) );
|
||||
close (fd);
|
||||
if (FD_ISSET (listen_fd, &read_fdset))
|
||||
{
|
||||
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
|
||||
if (fd == -1)
|
||||
{
|
||||
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
|
||||
if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
|
||||
#else
|
||||
if (pth_event_occurred (ev))
|
||||
#endif
|
||||
{
|
||||
handle_signal (signo);
|
||||
continue;
|
||||
}
|
||||
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
|
||||
pth_sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
|
||||
{
|
||||
log_error ("error spawning connection handler: %s\n",
|
||||
strerror (errno) );
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
else if ((listen_fd_ssh != -1) && FD_ISSET (listen_fd_ssh, &read_fdset))
|
||||
{
|
||||
fd = pth_accept_ev (listen_fd_ssh, (struct sockaddr *)&paddr, &plen, ev);
|
||||
if (fd == -1)
|
||||
{
|
||||
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
|
||||
if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
|
||||
#else
|
||||
if (pth_event_occurred (ev))
|
||||
#endif
|
||||
{
|
||||
handle_signal (signo);
|
||||
continue;
|
||||
}
|
||||
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
|
||||
pth_sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
|
||||
{
|
||||
log_error ("error spawning connection handler: %s\n",
|
||||
strerror (errno) );
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
914
agent/gpg-stream.c
Normal file
914
agent/gpg-stream.c
Normal file
@ -0,0 +1,914 @@
|
||||
/* stream.c - Stream I/O/ layer
|
||||
Copyright (C) 2004 g10 Code GmbH
|
||||
|
||||
This file is part of libgpg-stream.
|
||||
|
||||
libgpg-stream is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
libgpg-stream is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libgpg-stream; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gpg-error.h>
|
||||
|
||||
#include "gpg-stream.h"
|
||||
#include "gpg-stream-config.h"
|
||||
#include "buffer.h"
|
||||
|
||||
|
||||
|
||||
/* A Stream Context. */
|
||||
struct gpg_stream
|
||||
{
|
||||
void *handle; /* Handle. */
|
||||
unsigned int flags; /* Flags. */
|
||||
buffer_t buffer; /* Buffer used for I/O. */
|
||||
gpg_stream_functions_t functions; /* Callbacks. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Macros. */
|
||||
|
||||
/* Standard permissions used for creating new files. */
|
||||
#define GPG_STREAM_FILE_PERMISSIONS 0600
|
||||
|
||||
/* Evaluate EXPRESSION, setting VARIABLE to the return code, if
|
||||
VARIABLE is zero. */
|
||||
#define SET_UNLESS_NONZERO(variable, tmp_variable, expression) \
|
||||
do \
|
||||
{ \
|
||||
tmp_variable = expression; \
|
||||
if ((! variable) && tmp_variable) \
|
||||
variable = tmp_variable; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Implementation of Memory I/O. */
|
||||
|
||||
typedef struct gpg_stream_handle_mem
|
||||
{
|
||||
char *memory; /* Data. */
|
||||
size_t memory_size; /* Size of MEMORY. */
|
||||
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. */
|
||||
} *gpg_stream_handle_mem_t;
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_mem_create (void **handle,
|
||||
void *spec,
|
||||
unsigned int flags)
|
||||
{
|
||||
gpg_stream_handle_mem_t mem_handle = NULL;
|
||||
gpg_stream_spec_mem_t *mem_spec = spec;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
mem_handle = malloc (sizeof (*mem_handle));
|
||||
if (! mem_handle)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
{
|
||||
mem_handle->memory = mem_spec ? mem_spec->memory : 0;
|
||||
mem_handle->memory_size = mem_spec ? mem_spec->memory_size : 0;
|
||||
mem_handle->data_size = 0;
|
||||
mem_handle->grow = mem_spec ? mem_spec->grow : 1;
|
||||
mem_handle->offset = 0;
|
||||
*handle = mem_handle;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_mem_read (void *handle,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
gpg_stream_handle_mem_t mem_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (bytes_to_read > mem_handle->data_size - mem_handle->offset)
|
||||
bytes_to_read = mem_handle->data_size - mem_handle->offset;
|
||||
|
||||
memcpy (buffer, mem_handle->memory + mem_handle->offset,
|
||||
bytes_to_read);
|
||||
mem_handle->offset += bytes_to_read;
|
||||
*bytes_read = bytes_to_read;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_mem_write (void *handle,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written)
|
||||
{
|
||||
gpg_stream_handle_mem_t mem_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
char *memory_new = NULL;
|
||||
|
||||
if (! mem_handle->grow)
|
||||
if (bytes_to_write > mem_handle->memory_size - mem_handle->offset)
|
||||
bytes_to_write = mem_handle->memory_size - mem_handle->offset;
|
||||
|
||||
while (bytes_to_write > mem_handle->memory_size - mem_handle->offset)
|
||||
{
|
||||
memory_new = realloc (mem_handle->memory,
|
||||
mem_handle->memory_size + BUFFER_BLOCK_SIZE);
|
||||
if (! memory_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
{
|
||||
if (mem_handle->memory != memory_new)
|
||||
mem_handle->memory = memory_new;
|
||||
mem_handle->memory_size += BUFFER_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if (! err)
|
||||
{
|
||||
memcpy (mem_handle->memory + mem_handle->offset, buffer,
|
||||
bytes_to_write);
|
||||
if (mem_handle->offset + bytes_to_write > mem_handle->data_size)
|
||||
mem_handle->data_size = mem_handle->offset + bytes_to_write;
|
||||
mem_handle->offset += bytes_to_write;
|
||||
}
|
||||
*bytes_written = bytes_to_write;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_func_mem_seek (void *handle,
|
||||
off_t offset,
|
||||
int whence)
|
||||
{
|
||||
gpg_stream_handle_mem_t mem_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
if ((offset < 0) || (offset > mem_handle->data_size))
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
else
|
||||
mem_handle->offset = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if ((mem_handle->offset + offset < 0)
|
||||
|| (mem_handle->offset + offset > mem_handle->data_size))
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
else
|
||||
mem_handle->offset += offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if ((mem_handle->data_size + offset < 0)
|
||||
|| (mem_handle->data_size + offset > mem_handle->data_size))
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
else
|
||||
mem_handle->offset += offset;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_mem_stat (void *handle,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_stream_handle_mem_t mem_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
*size = mem_handle->data_size;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_mem_destroy (void *handle)
|
||||
{
|
||||
gpg_stream_handle_mem_t mem_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (mem_handle->memory)
|
||||
free (mem_handle->memory);
|
||||
free (mem_handle);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_stream_functions_t gpg_stream_functions_mem =
|
||||
{
|
||||
gpg_stream_func_mem_create,
|
||||
gpg_stream_func_mem_read,
|
||||
gpg_stream_func_mem_write,
|
||||
gpg_stream_func_mem_seek,
|
||||
gpg_stream_func_mem_stat,
|
||||
gpg_stream_func_mem_destroy
|
||||
};
|
||||
|
||||
/* Implementation of FD I/O. */
|
||||
|
||||
typedef struct gpg_stream_handle_fd
|
||||
{
|
||||
int fd;
|
||||
} *gpg_stream_handle_fd_t;
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_fd_create (void **handle,
|
||||
void *spec,
|
||||
unsigned int flags)
|
||||
{
|
||||
gpg_stream_handle_fd_t fd_handle = NULL;
|
||||
gpg_stream_spec_fd_t *fd_spec = spec;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
fd_handle = malloc (sizeof (*fd_handle));
|
||||
if (! fd_handle)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
{
|
||||
fd_handle->fd = fd_spec->fd;
|
||||
*handle = fd_handle;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_fd_read (void *handle,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read)
|
||||
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
ssize_t ret = -1;
|
||||
|
||||
ret = READ (file_handle->fd, buffer, bytes_to_read);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
*bytes_read = ret;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_fd_write (void *handle,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written)
|
||||
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
ssize_t ret = -1;
|
||||
|
||||
ret = WRITE (file_handle->fd, buffer, bytes_to_write);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
*bytes_written = ret;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_fd_seek (void *handle,
|
||||
off_t pos,
|
||||
int whence)
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
off_t ret = -1;
|
||||
|
||||
ret = lseek (file_handle->fd, pos, whence);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_fd_stat (void *handle,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
struct stat statbuf;
|
||||
int ret = 0;
|
||||
|
||||
ret = fstat (file_handle->fd, &statbuf);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
else
|
||||
*size = statbuf.st_size;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_fd_destroy (void *handle)
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
free (file_handle);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_stream_functions_t gpg_stream_functions_fd =
|
||||
{
|
||||
gpg_stream_func_fd_create,
|
||||
gpg_stream_func_fd_read,
|
||||
gpg_stream_func_fd_write,
|
||||
gpg_stream_func_fd_seek,
|
||||
gpg_stream_func_fd_stat,
|
||||
gpg_stream_func_fd_destroy
|
||||
};
|
||||
|
||||
|
||||
/* Implementation of File I/O. */
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_file_create (void **handle,
|
||||
void *spec,
|
||||
unsigned int flags)
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = NULL;
|
||||
gpg_stream_spec_file_t *file_spec = spec;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
int open_flags = 0;
|
||||
int fd = -1;
|
||||
|
||||
file_handle = malloc (sizeof (*file_handle));
|
||||
if (! file_handle)
|
||||
err = gpg_error_from_errno (errno);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
struct flag_mapping
|
||||
{
|
||||
unsigned int gpg_stream;
|
||||
unsigned int sys;
|
||||
} flag_mappings[] = { { GPG_STREAM_FLAG_READ,
|
||||
O_RDONLY },
|
||||
{ GPG_STREAM_FLAG_WRITE,
|
||||
O_WRONLY },
|
||||
{ GPG_STREAM_FLAG_EXCLUSIVE,
|
||||
O_EXCL },
|
||||
{ GPG_STREAM_FLAG_APPEND,
|
||||
O_APPEND },
|
||||
{ GPG_STREAM_FLAG_CREATE,
|
||||
O_CREAT },
|
||||
{ GPG_STREAM_FLAG_NONBLOCK,
|
||||
O_NONBLOCK },
|
||||
{ GPG_STREAM_FLAG_TRUNCATE,
|
||||
O_TRUNC } };
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < (sizeof (flag_mappings) / sizeof (*flag_mappings)); i++)
|
||||
if (flags & flag_mappings[i].gpg_stream)
|
||||
open_flags |= flag_mappings[i].sys;
|
||||
|
||||
fd = open (file_spec->filename, open_flags, file_spec->mode);
|
||||
if (fd == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
}
|
||||
|
||||
if (! err)
|
||||
{
|
||||
file_handle->fd = fd;
|
||||
*handle = file_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file_handle)
|
||||
free (file_handle);
|
||||
if (fd != -1)
|
||||
close (fd);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_func_file_destroy (void *handle)
|
||||
{
|
||||
gpg_stream_handle_fd_t file_handle = handle;
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
int ret = 0;
|
||||
|
||||
if (file_handle)
|
||||
{
|
||||
ret = close (file_handle->fd);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
free (file_handle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_stream_functions_t gpg_stream_functions_file =
|
||||
{
|
||||
gpg_stream_func_file_create,
|
||||
gpg_stream_func_fd_read,
|
||||
gpg_stream_func_fd_write,
|
||||
gpg_stream_func_fd_seek,
|
||||
gpg_stream_func_fd_stat,
|
||||
gpg_stream_func_file_destroy
|
||||
};
|
||||
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_create_do (gpg_stream_t *stream,
|
||||
void *spec,
|
||||
unsigned int flags,
|
||||
gpg_stream_functions_t functions)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (! (1
|
||||
&& (0
|
||||
|| ((flags & GPG_STREAM_FLAG_READ) && functions.func_read)
|
||||
|| ((flags & GPG_STREAM_FLAG_WRITE) && functions.func_write))))
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
else
|
||||
{
|
||||
buffer_functions_t buffer_fncs = { functions.func_read,
|
||||
functions.func_write,
|
||||
functions.func_seek,
|
||||
functions.func_stat };
|
||||
gpg_stream_t stream_new = NULL;
|
||||
buffer_t buffer = NULL;
|
||||
void *handle = NULL;
|
||||
|
||||
stream_new = malloc (sizeof (*stream_new));
|
||||
if (! stream_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
|
||||
if (! err)
|
||||
if (functions.func_create)
|
||||
err = (*functions.func_create) (&handle, spec, flags);
|
||||
|
||||
if (! err)
|
||||
err = buffer_create (&buffer, handle, buffer_fncs);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
stream_new->handle = handle;
|
||||
stream_new->flags = flags;
|
||||
stream_new->buffer = buffer;
|
||||
stream_new->functions = functions;
|
||||
*stream = stream_new;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (functions.func_destroy)
|
||||
(*functions.func_destroy) (handle);
|
||||
if (buffer)
|
||||
buffer_destroy (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_create (gpg_stream_t *stream,
|
||||
void *spec,
|
||||
unsigned int flags,
|
||||
gpg_stream_functions_t functions)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_create_do (stream, spec, flags, functions);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_create_file (gpg_stream_t *stream,
|
||||
const char *filename,
|
||||
unsigned int flags)
|
||||
{
|
||||
gpg_stream_spec_file_t spec = { filename, GPG_STREAM_FILE_PERMISSIONS };
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_create_do (stream, &spec, flags, gpg_stream_functions_file);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_create_fd (gpg_stream_t *stream,
|
||||
int fd,
|
||||
unsigned int flags)
|
||||
{
|
||||
gpg_stream_spec_fd_t spec = { fd };
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_create_do (stream, &spec, flags, gpg_stream_functions_fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_destroy (gpg_stream_t stream)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR, tmp_err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (stream)
|
||||
{
|
||||
SET_UNLESS_NONZERO (err, tmp_err, buffer_destroy (stream->buffer));
|
||||
if (stream->functions.func_destroy)
|
||||
SET_UNLESS_NONZERO (err, tmp_err, \
|
||||
(*stream->functions.func_destroy) (stream->handle));
|
||||
free (stream);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_read_do (gpg_stream_t stream,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (! (stream->flags & GPG_STREAM_FLAG_READ))
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
err = buffer_read (stream->buffer,
|
||||
buffer, bytes_to_read, bytes_read);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_read (gpg_stream_t stream,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_read_do (stream, buffer, bytes_to_read, bytes_read);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_write_do (gpg_stream_t stream,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (! (stream->flags & GPG_STREAM_FLAG_WRITE))
|
||||
err = GPG_ERR_NOT_SUPPORTED;
|
||||
else
|
||||
err = buffer_write (stream->buffer,
|
||||
buffer, bytes_to_write, bytes_written);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_write (gpg_stream_t stream,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_write_do (stream, buffer, bytes_to_write, bytes_written);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_read_line_do (gpg_stream_t stream,
|
||||
char **line,
|
||||
size_t *line_length)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
if (! (stream->flags & GPG_STREAM_FLAG_READ))
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
{
|
||||
buffer_functions_t buffer_fncs_mem = { gpg_stream_func_mem_read,
|
||||
gpg_stream_func_mem_write,
|
||||
gpg_stream_func_mem_seek };
|
||||
void *handle = NULL;
|
||||
char *line_new = NULL;
|
||||
buffer_t line_buffer = NULL;
|
||||
char *newline = NULL;
|
||||
size_t data_size = 0;
|
||||
char *data = NULL;
|
||||
size_t line_size = 0;
|
||||
|
||||
err = gpg_stream_func_mem_create (&handle, NULL, 0);
|
||||
if (! err)
|
||||
err = buffer_create (&line_buffer, handle, buffer_fncs_mem);
|
||||
if (! err)
|
||||
do
|
||||
{
|
||||
err = buffer_peek (stream->buffer, &data, &data_size);
|
||||
if (! err)
|
||||
{
|
||||
size_t bytes_written = 0;
|
||||
|
||||
newline = memchr (data, '\n', data_size);
|
||||
if (newline)
|
||||
{
|
||||
/* Write until newline. */
|
||||
line_size += newline - data + 1;
|
||||
err = buffer_write (line_buffer, data, newline - data + 1,
|
||||
&bytes_written);
|
||||
if (! err)
|
||||
err = buffer_skip (stream->buffer, bytes_written);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write whole block. */
|
||||
line_size += data_size;
|
||||
err = buffer_write (line_buffer, data, data_size,
|
||||
&bytes_written);
|
||||
if (! err)
|
||||
err = buffer_skip (stream->buffer, bytes_written);
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((! err) && data_size);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
/* Complete line has been written to line_buffer. */
|
||||
if (line_size)
|
||||
{
|
||||
err = buffer_seek (line_buffer, 0, SEEK_SET);
|
||||
if (! err)
|
||||
{
|
||||
line_new = malloc (line_size + 1);
|
||||
if (! line_new)
|
||||
err = gpg_error_from_errno (errno);
|
||||
}
|
||||
if (! err)
|
||||
{
|
||||
size_t bytes_written = 0, written = 0;
|
||||
|
||||
while ((bytes_written < line_size) && (! err))
|
||||
{
|
||||
err = buffer_read (line_buffer, line_new + bytes_written,
|
||||
line_size - bytes_written, &written);
|
||||
bytes_written += written;
|
||||
}
|
||||
if (! err)
|
||||
line_new[line_size] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line_buffer)
|
||||
buffer_destroy (line_buffer);
|
||||
if (handle)
|
||||
gpg_stream_func_mem_destroy (handle);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
*line = line_new;
|
||||
if (line_length)
|
||||
*line_length = line_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line_new)
|
||||
free (line_new);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_read_line (gpg_stream_t stream,
|
||||
char **line,
|
||||
size_t *line_length)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_read_line_do (stream, line, line_length);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_print_va_do (gpg_stream_t stream,
|
||||
const char *format,
|
||||
va_list ap)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
FILE *tmp_stream = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (! (stream->flags & GPG_STREAM_FLAG_WRITE))
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
else
|
||||
{
|
||||
tmp_stream = tmpfile ();
|
||||
if (! tmp_stream)
|
||||
err = gpg_error_from_errno (errno);
|
||||
|
||||
if (! err)
|
||||
{
|
||||
ret = vfprintf (tmp_stream, format, ap);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
}
|
||||
|
||||
if (! err)
|
||||
{
|
||||
ret = fseek (tmp_stream, 0, SEEK_SET);
|
||||
if (ret == -1)
|
||||
err = gpg_error_from_errno (errno);
|
||||
}
|
||||
|
||||
if (! err)
|
||||
{
|
||||
size_t bytes_read = 0, bytes_written = 0;
|
||||
char data[BUFFER_BLOCK_SIZE];
|
||||
|
||||
while (! err)
|
||||
{
|
||||
bytes_read = fread (data, 1, sizeof (data), tmp_stream);
|
||||
if (ferror (tmp_stream))
|
||||
err = gpg_error_from_errno (errno);
|
||||
if (! err)
|
||||
err = gpg_stream_write_do (stream, data,
|
||||
bytes_read, &bytes_written);
|
||||
if (! err)
|
||||
if (feof (tmp_stream))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_stream)
|
||||
fclose (tmp_stream);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_print_va (gpg_stream_t stream,
|
||||
const char *format,
|
||||
va_list ap)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_print_va_do (stream, format, ap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_print (gpg_stream_t stream,
|
||||
const char *format,
|
||||
...)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, format);
|
||||
err = gpg_stream_print_va (stream, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_flush_do (gpg_stream_t stream)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = buffer_flush (stream->buffer);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_flush (gpg_stream_t stream)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_flush_do (stream);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_peek_do (gpg_stream_t stream,
|
||||
char **buffer,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = buffer_peek (stream->buffer, buffer, size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_peek (gpg_stream_t stream,
|
||||
char **buffer,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_peek_do (stream, buffer, size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_seek_do (gpg_stream_t stream,
|
||||
off_t offset,
|
||||
int whence)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = buffer_seek (stream->buffer, offset, whence);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_seek (gpg_stream_t stream,
|
||||
off_t offset,
|
||||
int whence)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_seek_do (stream, offset, whence);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static gpg_error_t
|
||||
gpg_stream_stat_do (gpg_stream_t stream,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = buffer_stat (stream->buffer, size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
gpg_stream_stat (gpg_stream_t stream,
|
||||
size_t *size)
|
||||
{
|
||||
gpg_error_t err = GPG_ERR_NO_ERROR;
|
||||
|
||||
err = gpg_stream_stat_do (stream, size);
|
||||
|
||||
return err;
|
||||
}
|
148
agent/gpg-stream.h
Normal file
148
agent/gpg-stream.h
Normal file
@ -0,0 +1,148 @@
|
||||
/* stream.h - Stream I/O layer
|
||||
Copyright (C) 2004 g10 Code GmbH
|
||||
|
||||
This file is part of libgpg-stream.
|
||||
|
||||
libgpg-stream is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
libgpg-stream is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libgpg-stream; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#ifndef GPG_STREAM_H
|
||||
#define GPG_STREAM_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <gpg-error.h>
|
||||
|
||||
|
||||
|
||||
#define STREAM_BLOCK_SIZE 1024
|
||||
|
||||
|
||||
|
||||
typedef struct gpg_stream *gpg_stream_t;
|
||||
|
||||
typedef gpg_error_t (*gpg_stream_func_create_t) (void **handle,
|
||||
void *spec,
|
||||
unsigned int flags);
|
||||
typedef gpg_error_t (*gpg_stream_func_read_t) (void *handle,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read);
|
||||
typedef gpg_error_t (*gpg_stream_func_write_t) (void *handle,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written);
|
||||
typedef gpg_error_t (*gpg_stream_func_seek_t) (void *handle,
|
||||
off_t pos,
|
||||
int whence);
|
||||
typedef gpg_error_t (*gpg_stream_func_stat_t) (void *handle,
|
||||
size_t *size);
|
||||
typedef gpg_error_t (*gpg_stream_func_destroy_t) (void *handle);
|
||||
|
||||
typedef struct gpg_stream_functions
|
||||
{
|
||||
gpg_stream_func_create_t func_create;
|
||||
gpg_stream_func_read_t func_read;
|
||||
gpg_stream_func_write_t func_write;
|
||||
gpg_stream_func_seek_t func_seek;
|
||||
gpg_stream_func_stat_t func_stat;
|
||||
gpg_stream_func_destroy_t func_destroy;
|
||||
} gpg_stream_functions_t;
|
||||
|
||||
#define GPG_STREAM_FLAG_READ (1 << 0)
|
||||
#define GPG_STREAM_FLAG_WRITE (1 << 1)
|
||||
#define GPG_STREAM_FLAG_EXCLUSIVE (1 << 2)
|
||||
#define GPG_STREAM_FLAG_APPEND (1 << 3)
|
||||
#define GPG_STREAM_FLAG_CREATE (1 << 4)
|
||||
#define GPG_STREAM_FLAG_NONBLOCK (1 << 5)
|
||||
#define GPG_STREAM_FLAG_TRUNCATE (1 << 6)
|
||||
#define GPG_STREAM_FLAG_BINARY (1 << 7)
|
||||
|
||||
gpg_error_t gpg_stream_create (gpg_stream_t *stream,
|
||||
void *spec,
|
||||
unsigned int flags,
|
||||
gpg_stream_functions_t functions);
|
||||
|
||||
gpg_error_t gpg_stream_create_file (gpg_stream_t *stream,
|
||||
const char *filename,
|
||||
unsigned int flags);
|
||||
|
||||
gpg_error_t gpg_stream_create_fd (gpg_stream_t *stream,
|
||||
int fd,
|
||||
unsigned int flags);
|
||||
|
||||
gpg_error_t gpg_stream_destroy (gpg_stream_t stream);
|
||||
|
||||
gpg_error_t gpg_stream_read (gpg_stream_t stream,
|
||||
char *buffer,
|
||||
size_t bytes_to_read,
|
||||
size_t *bytes_read);
|
||||
|
||||
gpg_error_t gpg_stream_write (gpg_stream_t stream,
|
||||
const char *buffer,
|
||||
size_t bytes_to_write,
|
||||
size_t *bytes_written);
|
||||
|
||||
gpg_error_t gpg_stream_read_line (gpg_stream_t stream,
|
||||
char **line,
|
||||
size_t *line_length);
|
||||
|
||||
gpg_error_t gpg_stream_print_va (gpg_stream_t stream,
|
||||
const char *format,
|
||||
va_list ap);
|
||||
|
||||
gpg_error_t gpg_stream_print (gpg_stream_t stream,
|
||||
const char *format,
|
||||
...);
|
||||
|
||||
gpg_error_t gpg_stream_flush (gpg_stream_t stream);
|
||||
|
||||
gpg_error_t gpg_stream_peek (gpg_stream_t stream,
|
||||
char **buffer,
|
||||
size_t *size);
|
||||
|
||||
gpg_error_t gpg_stream_seek (gpg_stream_t stream,
|
||||
off_t offset,
|
||||
int whence);
|
||||
|
||||
gpg_error_t gpg_stream_stat (gpg_stream_t stream,
|
||||
size_t *size);
|
||||
|
||||
typedef struct gpg_stream_spec_mem
|
||||
{
|
||||
char *memory;
|
||||
size_t memory_size;
|
||||
unsigned int grow: 1;
|
||||
} gpg_stream_spec_mem_t;
|
||||
|
||||
extern gpg_stream_functions_t gpg_stream_functions_mem;
|
||||
|
||||
typedef struct gpg_stream_spec_file
|
||||
{
|
||||
const char *filename;
|
||||
mode_t mode;
|
||||
} gpg_stream_spec_file_t;
|
||||
|
||||
extern gpg_stream_functions_t gpg_stream_functions_file;
|
||||
|
||||
typedef struct gpg_stream_spec_fd
|
||||
{
|
||||
int fd;
|
||||
} gpg_stream_spec_fd_t;
|
||||
|
||||
extern gpg_stream_functions_t gpg_stream_functions_fd;
|
||||
|
||||
#endif
|
@ -55,18 +55,17 @@ do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash)
|
||||
}
|
||||
|
||||
|
||||
/* SIGN whatever information we have accumulated in CTRL and write it
|
||||
back to OUTFP. */
|
||||
/* SIGN whatever information we have accumulated in CTRL and return
|
||||
the signature S-Expression. */
|
||||
int
|
||||
agent_pksign (CTRL ctrl, const char *desc_text, FILE *outfp, int ignore_cache)
|
||||
agent_pksign_do (CTRL ctrl, const char *desc_text,
|
||||
gcry_sexp_t *signature_sexp, int ignore_cache)
|
||||
{
|
||||
gcry_sexp_t s_skey = NULL, s_hash = NULL, s_sig = NULL;
|
||||
gcry_sexp_t s_skey = NULL, s_sig = NULL;
|
||||
unsigned char *shadow_info = NULL;
|
||||
int rc;
|
||||
char *buf = NULL;
|
||||
size_t len;
|
||||
unsigned int rc = 0; /* FIXME: gpg-error? */
|
||||
|
||||
if (!ctrl->have_keygrip)
|
||||
if (! ctrl->have_keygrip)
|
||||
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||
|
||||
rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
|
||||
@ -77,26 +76,40 @@ agent_pksign (CTRL ctrl, const char *desc_text, FILE *outfp, int ignore_cache)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!s_skey)
|
||||
{ /* divert operation to the smartcard */
|
||||
unsigned char *sigbuf;
|
||||
if (! s_skey)
|
||||
{
|
||||
/* divert operation to the smartcard */
|
||||
|
||||
unsigned char *buf = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
rc = divert_pksign (ctrl,
|
||||
ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
ctrl->digest.algo,
|
||||
shadow_info, &sigbuf);
|
||||
shadow_info, &buf);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
len = gcry_sexp_canon_len (sigbuf, 0, NULL, NULL);
|
||||
len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
|
||||
assert (len);
|
||||
buf = sigbuf;
|
||||
|
||||
rc = gcry_sexp_sscan (&s_sig, NULL, buf, len);
|
||||
xfree (buf);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to convert sigbuf returned by divert_pksign "
|
||||
"into S-Exp: %s", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* no smartcard, but a private key */
|
||||
{
|
||||
/* no smartcard, but a private key */
|
||||
|
||||
gcry_sexp_t s_hash = NULL;
|
||||
|
||||
/* put the hash into a sexp */
|
||||
rc = do_encode_md (ctrl->digest.value,
|
||||
@ -114,6 +127,7 @@ agent_pksign (CTRL ctrl, const char *desc_text, FILE *outfp, int ignore_cache)
|
||||
|
||||
/* sign */
|
||||
rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
|
||||
gcry_sexp_release (s_hash);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("signing failed: %s\n", gpg_strerror (rc));
|
||||
@ -125,26 +139,47 @@ agent_pksign (CTRL ctrl, const char *desc_text, FILE *outfp, int ignore_cache)
|
||||
log_debug ("result: ");
|
||||
gcry_sexp_dump (s_sig);
|
||||
}
|
||||
|
||||
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||
assert (len);
|
||||
buf = xmalloc (len);
|
||||
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
|
||||
assert (len);
|
||||
}
|
||||
|
||||
leave:
|
||||
|
||||
if (! rc)
|
||||
*signature_sexp = s_sig;
|
||||
|
||||
gcry_sexp_release (s_skey);
|
||||
xfree (shadow_info);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* SIGN whatever information we have accumulated in CTRL and write it
|
||||
back to OUTFP. */
|
||||
int
|
||||
agent_pksign (CTRL ctrl, const char *desc_text, FILE *outfp, int ignore_cache)
|
||||
{
|
||||
gcry_sexp_t s_sig = NULL;
|
||||
char *buf = NULL;
|
||||
size_t len = 0;
|
||||
int rc = 0;
|
||||
|
||||
rc = agent_pksign_do (ctrl, desc_text, &s_sig, ignore_cache);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||
assert (len);
|
||||
buf = xmalloc (len);
|
||||
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
|
||||
assert (len);
|
||||
|
||||
/* FIXME: we must make sure that no buffering takes place or we are
|
||||
in full control of the buffer memory (easy to do) - should go
|
||||
into assuan. */
|
||||
fwrite (buf, 1, len, outfp);
|
||||
|
||||
leave:
|
||||
gcry_sexp_release (s_skey);
|
||||
gcry_sexp_release (s_hash);
|
||||
gcry_sexp_release (s_sig);
|
||||
xfree (buf);
|
||||
xfree (shadow_info);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -132,7 +132,7 @@ start_pinentry (CTRL ctrl)
|
||||
pgmname++;
|
||||
|
||||
argv[0] = pgmname;
|
||||
if (ctrl->display && !opt.keep_display)
|
||||
if ((ctrl && ctrl->display) && !opt.keep_display)
|
||||
{
|
||||
argv[1] = "--display";
|
||||
argv[2] = ctrl->display;
|
||||
@ -169,7 +169,7 @@ start_pinentry (CTRL ctrl)
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
if (ctrl->ttyname)
|
||||
if (ctrl && ctrl->ttyname)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
|
||||
@ -180,7 +180,7 @@ start_pinentry (CTRL ctrl)
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (ctrl->ttytype)
|
||||
if (ctrl && ctrl->ttytype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
|
||||
@ -190,7 +190,7 @@ start_pinentry (CTRL ctrl)
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (ctrl->lc_ctype)
|
||||
if (ctrl && ctrl->lc_ctype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
|
||||
@ -200,7 +200,7 @@ start_pinentry (CTRL ctrl)
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (ctrl->lc_messages)
|
||||
if (ctrl && ctrl->lc_messages)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
|
||||
|
Loading…
x
Reference in New Issue
Block a user