1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

* AUTHORS: Copied from 1.4 and edited to refelct the changes in

1.9.

* agent.h (agent_exit): Add JNLIB_GCC_A_NR to indicate that this
function won't return.

* gpg-agent.c (check_for_running_agent): Initialize pid to a
default value if not needed.

* command-ssh.c: Removed stdint.h.  s/byte_t/unsigned char/,
s/uint32/u32/ becuase that is what we have always used in GnuPG.
(ssh_request_specs): Moved to top of file.
(ssh_key_types): Ditto.
(make_cstring): Ditto.
(data_sign): Don't use a variable for the passphrase prompt, make
it translatable.
(ssh_request_process):

* findkey.c (modify_description): Renamed arguments for clarity,
polished documentation.  Make comment a C-string.  Fixed case of
DESCRIPTION being just "%".
(agent_key_from_file): Make sure comment string to a C-string.

* gpg-agent.c (create_socket_name): Cleanup the implemntation, use
DIMof, agent_exit, removed superflous args and return the
allocated string as value.  Documented.  Changed callers.
(create_server_socket): Cleanups similar to above.  Changed callers.
(cleanup_do): Renamed to ..
(remove_socket): .. this.  Changed caller.
(handle_connections): The signals are to be handled in the select
and not in the accept.  Test all FDs after returning from a
select.  Remove the event tests from the accept calls.  The select
already assured that the accept won't block.
This commit is contained in:
Werner Koch 2005-02-03 17:40:02 +00:00
parent 625bafa4da
commit b326996b78
8 changed files with 728 additions and 418 deletions

140
AUTHORS
View File

@ -0,0 +1,140 @@
Program: GnuPG
Maintainer: Werner Koch <wk@gnupg.org>
Bug reports: <bug-gnupg@gnu.org>
Security related bug reports: <security@gnupg.org>
Please note that this file is for the 1.9 branch of GnuPG.
Authors
=======
Ales Nyakhaychyk <nyakhaychyk@i1fn.linux.by> Translations [be]
Birger Langkjer <birger.langkjer@image.dk> Translations [da]
Maxim Britov <maxbritov@tut.by> Translations [ru]
Daniel Resare <daniel@resare.com> Translations [sv]
Per Tunedal <per@clipanish.com> Translations [sv]
David Shaw <dshaw@jabberwocky.com> Assigns past and future changes.
(all in keyserver/,
a lot of changes in g10/ see the ChangeLog,
bug fixes here and there)
Dokianakis Theofanis <madf@hellug.gr> Translations [el]
Edmund GRIMLEY EVANS <edmundo@rano.org> Translations [eo]
Florian Weimer <fw@deneb.enyo.de> Assigns past and future changes
(changed:g10/parse-packet.c, include/iobuf.h, util/iobuf.c)
g10 Code GmbH <info@g10code.com> Assigns past and future changes
(all work since 2001 as indicated by mail addresses in ChangeLogs)
Gaël Quéri <gael@lautre.net> Translations [fr]
(fixed a lot of typos)
Gregory Steuck <steuck@iname.com> Translations [ru]
Nagy Ferenc László <nfl@nfllab.com> Translations [hu]
Ivo Timmermans <itimmermans@bigfoot.com> Translations [nl]
Jacobo Tarri'o Barreiro <jtarrio@iname.com> Translations [gl]
Janusz Aleksander Urbanowicz <alex@bofh.torun.pl> Translations [po]
Jedi Lin <Jedi@idej.org> Translations [zh-tw]
Jouni Hiltunen <jouni.hiltunen@kolumbus.fi> Translations [fi]
Tommi Vainikainen <Tommi.Vainikainen@iki.fi> Translations [fi]
Laurentiu Buzdugan <lbgnupg@rolix.org> Translations [ro]
Magda Procha'zkova' <magda@math.muni.cz> Translations [cs]
Michael Roth <mroth@nessie.de> Assigns changes.
(wrote cipher/des.c., changes and bug fixes all over the place)
Michal Majer <mmajer@econ.umb.sk> Translations [sk]
Marco d'Itri <md@linux.it> Translations [it]
Marcus Brinkmann <marcus@g10code.de>
(gpgconf and fixes all over the place)
Matthew Skala <mskala@ansuz.sooke.bc.ca> Disclaimer
(wrote cipher/twofish.c)
Moritz Schulte <moritz@g10code.com>
(ssh support gpg-agent)
Niklas Hernaeus <nh@df.lth.se> Disclaimer
(weak key patches)
Nilgun Belma Buguner <nilgun@technologist.com> Translations [tr]
Nils Ellmenreich <nils 'at' infosun.fmi.uni-passau.de>
Assigns past and future changes
(configure.in, cipher/rndlinux.c, FAQ)
Paul Eggert <eggert@twinsun.com>
(configuration macros for LFS)
Pavel I. Shajdo <zwon@severodvinsk.ru> Translations [ru]
(man pages)
Pedro Morais <morais@poli.org> Translations [pt_PT]
Rémi Guyomarch <rguyom@mail.dotcom.fr> Assigns past and future changes.
(g10/compress.c, g10/encr-data.c,
g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c)
Stefan Bellon <sbellon@sbellon.de> Assigns past and future changes.
(All patches to support RISC OS)
Timo Schulz <twoaday@freakmail.de> Assigns past and future changes.
(util/w32reg.c, g10/passphrase.c, g10/hkp.c)
Tedi Heriyanto <tedi_h@gmx.net> Translations [id]
Thiago Jung Bauermann <jungmann@cwb.matrix.com.br> Translations [pt_BR]
Rafael Caetano dos Santos <rcaetano@linux.ime.usp.br> Translations [pt_BR]
Toomas Soome <tsoome@ut.ee> Translations [et]
Urko Lusa <ulusa@euskalnet.net> Translations [es_ES]
Walter Koch <koch@u32.de> Translations [de]
Werner Koch <wk@gnupg.org> Assigns GNU Privacy Guard and future changes.
(started the whole thing, wrote the S/MIME extensions, the
smartcard daemon and the gpg-agent)
Yosiaki IIDA <iida@ring.gr.jp> Translations [ja]
Other authors
=============
The files common/libestream.[ch] are maintained as a separate project
by g10 Code GmbH. These files, as used here, are considered part of
GnuPG.
The RPM specs file scripts/gnupg.spec has been contributed by
several people.
Copyright 1998, 1999, 2000, 2001, 2002, 2004,
2005 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

View File

@ -1,3 +1,8 @@
2005-02-03 Werner Koch <wk@g10code.com>
* AUTHORS: Copied from 1.4 and edited to refelct the changes in
1.9.
2005-01-17 Werner Koch <wk@g10code.com> 2005-01-17 Werner Koch <wk@g10code.com>
* configure.ac: Make --without-included-regex work as expected. * configure.ac: Make --without-included-regex work as expected.

View File

@ -1,3 +1,37 @@
2005-02-03 Werner Koch <wk@g10code.com>
* agent.h (agent_exit): Add JNLIB_GCC_A_NR to indicate that this
function won't return.
* gpg-agent.c (check_for_running_agent): Initialize pid to a
default value if not needed.
* command-ssh.c: Removed stdint.h. s/byte_t/unsigned char/,
s/uint32/u32/ becuase that is what we have always used in GnuPG.
(ssh_request_specs): Moved to top of file.
(ssh_key_types): Ditto.
(make_cstring): Ditto.
(data_sign): Don't use a variable for the passphrase prompt, make
it translatable.
(ssh_request_process):
* findkey.c (modify_description): Renamed arguments for clarity,
polished documentation. Make comment a C-string. Fixed case of
DESCRIPTION being just "%".
(agent_key_from_file): Make sure comment string to a C-string.
* gpg-agent.c (create_socket_name): Cleanup the implemntation, use
DIMof, agent_exit, removed superflous args and return the
allocated string as value. Documented. Changed callers.
(create_server_socket): Cleanups similar to above. Changed callers.
(cleanup_do): Renamed to ..
(remove_socket): .. this. Changed caller.
(handle_connections): The signals are to be handled in the select
and not in the accept. Test all FDs after returning from a
select. Remove the event tests from the accept calls. The select
already assured that the accept won't block.
2005-01-29 Moritz Schulte <moritz@g10code.com> 2005-01-29 Moritz Schulte <moritz@g10code.com>
* command-ssh.c (ssh_handler_request_identities) * command-ssh.c (ssh_handler_request_identities)
@ -67,7 +101,7 @@
and ssh-agent protocol. and ssh-agent protocol.
* agent.h (struct opt): New member: ssh_support. * agent.h (struct opt): New member: ssh_support.
Declare function: start_command_handler_ssh. (start_command_handler_ssh): Add prototype.
2005-01-04 Werner Koch <wk@g10code.com> 2005-01-04 Werner Koch <wk@g10code.com>

View File

@ -47,25 +47,27 @@ out_of_core (void)
/* A large struct name "opt" to keep global flags */ /* A large struct name "opt" to keep global flags */
struct { struct {
unsigned int debug; /* debug flags (DBG_foo_VALUE) */ unsigned int debug; /* Debug flags (DBG_foo_VALUE) */
int verbose; /* verbosity level */ int verbose; /* Verbosity level */
int quiet; /* be as quiet as possible */ int quiet; /* Be as quiet as possible */
int dry_run; /* don't change any persistent data */ int dry_run; /* Don't change any persistent data */
int batch; /* batch mode */ int batch; /* Batch mode */
const char *homedir; /* configuration directory name */ const char *homedir; /* Configuration directory name */
const char *pinentry_program; const char *pinentry_program; /* Filename of the program to start as
const char *scdaemon_program; pinentry. */
int no_grab; /* don't let the pinentry grab the keyboard */ const char *scdaemon_program; /* Filename of the program to handle
smartcard tasks. */
int no_grab; /* Don't let the pinentry grab the keyboard */
unsigned long def_cache_ttl; unsigned long def_cache_ttl;
unsigned long max_cache_ttl; unsigned long max_cache_ttl;
int running_detached; /* we are running detached from the tty. */ int running_detached; /* We are running detached from the tty. */
int ignore_cache_for_signing; int ignore_cache_for_signing;
int allow_mark_trusted; int allow_mark_trusted;
int allow_preset_passphrase; int allow_preset_passphrase;
int keep_tty; /* don't switch the TTY (for pinentry) on request */ 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 keep_display; /* Don't switch the DISPLAY (for pinentry) on request */
int ssh_support; /* Enable ssh-agent emulation. */ int ssh_support; /* Enable ssh-agent emulation. */
} opt; } opt;
@ -131,7 +133,7 @@ enum {
}; };
/*-- gpg-agent.c --*/ /*-- gpg-agent.c --*/
void agent_exit (int rc); /* also implemented in other tools */ void agent_exit (int rc) JNLIB_GCC_A_NR; /* Also implemented in other tools */
void agent_init_default_ctrl (struct server_control_s *ctrl); void agent_init_default_ctrl (struct server_control_s *ctrl);
/*-- command.c --*/ /*-- command.c --*/

View File

@ -22,7 +22,7 @@
/* Only v2 of the ssh-agent protocol is implemented. */ /* Only v2 of the ssh-agent protocol is implemented. */
#include <config.h> #include <config.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -33,9 +33,8 @@
#include "agent.h" #include "agent.h"
#include <gcrypt.h>
#include "estream.h" #include "estream.h"
#include "i18n.h"
@ -59,26 +58,31 @@
#define SSH_RESPONSE_IDENTITIES_ANSWER 12 #define SSH_RESPONSE_IDENTITIES_ANSWER 12
#define SSH_RESPONSE_SIGN_RESPONSE 14 #define SSH_RESPONSE_SIGN_RESPONSE 14
/* Other constants. */
#define SSH_DSA_SIGNATURE_PADDING 20
#define SSH_DSA_SIGNATURE_ELEMS 2
#define SPEC_FLAG_USE_PKCS1V2 (1 << 0)
/* Basic types. */ /* Basic types. */
/* A "byte". */
typedef unsigned char byte_t;
typedef gpg_error_t (*ssh_request_handler_t) (ctrl_t ctrl, typedef gpg_error_t (*ssh_request_handler_t) (ctrl_t ctrl,
estream_t request, estream_t request,
estream_t response); estream_t response);
typedef struct ssh_request_spec typedef struct ssh_request_spec
{ {
byte_t type; unsigned char type;
ssh_request_handler_t handler; ssh_request_handler_t handler;
const char *identifier; const char *identifier;
} ssh_request_spec_t; } ssh_request_spec_t;
typedef gpg_error_t (*ssh_key_modifier_t) (const char *elems, gcry_mpi_t *mpis); typedef gpg_error_t (*ssh_key_modifier_t) (const char *elems,
gcry_mpi_t *mpis);
typedef gpg_error_t (*ssh_signature_encoder_t) (estream_t signature_blob, typedef gpg_error_t (*ssh_signature_encoder_t) (estream_t signature_blob,
gcry_mpi_t *mpis); gcry_mpi_t *mpis);
@ -96,10 +100,91 @@ typedef struct ssh_key_type_spec
unsigned int flags; unsigned int flags;
} ssh_key_type_spec_t; } ssh_key_type_spec_t;
/* Prototypes. */
static gpg_error_t ssh_handler_request_identities (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_handler_sign_request (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_handler_add_identity (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_handler_remove_identity (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_handler_remove_all_identities (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_handler_lock (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_handler_unlock (ctrl_t ctrl,
estream_t request,
estream_t response);
static gpg_error_t ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis);
static gpg_error_t ssh_signature_encoder_rsa (estream_t signature_blob,
gcry_mpi_t *mpis);
static gpg_error_t ssh_signature_encoder_dsa (estream_t signature_blob,
gcry_mpi_t *mpis);
/* Global variables. */
/* Associating request types with the corresponding request
handlers. */
#define REQUEST_SPEC_DEFINE(id, name) \
{ SSH_REQUEST_##id, ssh_handler_##name, #name }
static ssh_request_spec_t request_specs[] =
{
REQUEST_SPEC_DEFINE (REQUEST_IDENTITIES, request_identities),
REQUEST_SPEC_DEFINE (SIGN_REQUEST, sign_request),
REQUEST_SPEC_DEFINE (ADD_IDENTITY, add_identity),
REQUEST_SPEC_DEFINE (ADD_ID_CONSTRAINED, add_identity),
REQUEST_SPEC_DEFINE (REMOVE_IDENTITY, remove_identity),
REQUEST_SPEC_DEFINE (REMOVE_ALL_IDENTITIES, remove_all_identities),
REQUEST_SPEC_DEFINE (LOCK, lock),
REQUEST_SPEC_DEFINE (UNLOCK, unlock)
};
#undef REQUEST_SPEC_DEFINE
/* Table holding key type specifications. */
static ssh_key_type_spec_t ssh_key_types[] =
{
{
"ssh-rsa", "rsa", "nedupq", "en", "dupq", "s", "nedpqu",
ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
SPEC_FLAG_USE_PKCS1V2
},
{
"ssh-dss", "dsa", "pqgyx", "pqgy", "x", "rs", "pqgyx",
NULL, ssh_signature_encoder_dsa,
0
},
};
/* General utility functions. */
/*
General utility functions.
*/
/* A secure realloc, i.e. it amkese sure to allocate secure memory if
A is NULL. This is required becuase the standard gcry_realloc does
not know whether to allocate secure or normal if NULL is passed as
existing buffer. */
static void * static void *
realloc_secure (void *a, size_t n) realloc_secure (void *a, size_t n)
{ {
@ -113,10 +198,39 @@ realloc_secure (void *a, size_t n)
return p; return p;
} }
/* Primitive I/O functions. */
static char *
make_cstring (const char *data, size_t data_n)
{
char *s;
s = xtrymalloc (data_n + 1);
if (s)
{
strncpy (s, data, data_n);
s[data_n] = 0;
}
return s;
}
/*
Primitive I/O functions.
FIXME: Needs documentation.
Why are all these functions prefixed with es_ ? They are not part
of libestream, thus they should not use this prefix.
*/
static gpg_error_t static gpg_error_t
es_read_byte (estream_t stream, byte_t *b) es_read_byte (estream_t stream, unsigned char *b)
{ {
gpg_error_t err; gpg_error_t err;
int ret; int ret;
@ -138,8 +252,9 @@ es_read_byte (estream_t stream, byte_t *b)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_write_byte (estream_t stream, byte_t b) es_write_byte (estream_t stream, unsigned char b)
{ {
gpg_error_t err; gpg_error_t err;
int ret; int ret;
@ -153,8 +268,9 @@ es_write_byte (estream_t stream, byte_t b)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_read_uint32 (estream_t stream, uint32_t *uint32) es_read_uint32 (estream_t stream, u32 *uint32)
{ {
unsigned char buffer[4]; unsigned char buffer[4];
size_t bytes_read; size_t bytes_read;
@ -170,13 +286,20 @@ es_read_uint32 (estream_t stream, uint32_t *uint32)
err = gpg_error (GPG_ERR_EOF); err = gpg_error (GPG_ERR_EOF);
else else
{ {
uint32_t n; u32 n;
/* FIXME: For what is the cast good for? The proper way of
wrinting it - assuming an unsigned buffer - is:
n = (buffer[0]<< 24)|(buffer[0]<< 16)|(buffer[0]<<8)|(buffer[0]);
-wk
*/
n = (0 n = (0
| ((uint32_t) (buffer[0] << 24)) | ((u32) (buffer[0] << 24))
| ((uint32_t) (buffer[1] << 16)) | ((u32) (buffer[1] << 16))
| ((uint32_t) (buffer[2] << 8)) | ((u32) (buffer[2] << 8))
| ((uint32_t) (buffer[3] << 0))); | ((u32) (buffer[3] << 0)));
*uint32 = n; *uint32 = n;
err = 0; err = 0;
} }
@ -185,13 +308,15 @@ es_read_uint32 (estream_t stream, uint32_t *uint32)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_write_uint32 (estream_t stream, uint32_t uint32) es_write_uint32 (estream_t stream, u32 uint32)
{ {
unsigned char buffer[4]; unsigned char buffer[4];
gpg_error_t err; gpg_error_t err;
int ret; int ret;
/* Fixme: The 0xFF mask is superfluous. */
buffer[0] = (uint32 >> 24) & 0xFF; buffer[0] = (uint32 >> 24) & 0xFF;
buffer[1] = (uint32 >> 16) & 0xFF; buffer[1] = (uint32 >> 16) & 0xFF;
buffer[2] = (uint32 >> 8) & 0xFF; buffer[2] = (uint32 >> 8) & 0xFF;
@ -206,6 +331,7 @@ es_write_uint32 (estream_t stream, uint32_t uint32)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_read_data (estream_t stream, unsigned char *buffer, size_t size) es_read_data (estream_t stream, unsigned char *buffer, size_t size)
{ {
@ -227,6 +353,7 @@ es_read_data (estream_t stream, unsigned char *buffer, size_t size)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_write_data (estream_t stream, const unsigned char *buffer, size_t size) es_write_data (estream_t stream, const unsigned char *buffer, size_t size)
{ {
@ -242,13 +369,14 @@ es_write_data (estream_t stream, const unsigned char *buffer, size_t size)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_read_string (estream_t stream, unsigned int secure, es_read_string (estream_t stream, unsigned int secure,
unsigned char **string, uint32_t *string_size) unsigned char **string, u32 *string_size)
{ {
gpg_error_t err; gpg_error_t err;
unsigned char *buffer; unsigned char *buffer;
uint32_t length; u32 length;
buffer = NULL; buffer = NULL;
@ -289,6 +417,7 @@ es_read_string (estream_t stream, unsigned int secure,
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_read_cstring (estream_t stream, char **string) es_read_cstring (estream_t stream, char **string)
{ {
@ -306,9 +435,11 @@ es_read_cstring (estream_t stream, char **string)
return err; return err;
} }
/* FIXME: Needs documentation. */
static gpg_error_t static gpg_error_t
es_write_string (estream_t stream, es_write_string (estream_t stream,
const unsigned char *string, uint32_t string_n) const unsigned char *string, u32 string_n)
{ {
gpg_error_t err; gpg_error_t err;
@ -323,6 +454,7 @@ es_write_string (estream_t stream,
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_write_cstring (estream_t stream, const char *string) es_write_cstring (estream_t stream, const char *string)
{ {
@ -334,11 +466,12 @@ es_write_cstring (estream_t stream, const char *string)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_read_mpi (estream_t stream, unsigned int secure, gcry_mpi_t *mpint) es_read_mpi (estream_t stream, unsigned int secure, gcry_mpi_t *mpint)
{ {
unsigned char *mpi_data; unsigned char *mpi_data;
uint32_t mpi_data_size; u32 mpi_data_size;
gpg_error_t err; gpg_error_t err;
gcry_mpi_t mpi; gcry_mpi_t mpi;
@ -361,6 +494,7 @@ es_read_mpi (estream_t stream, unsigned int secure, gcry_mpi_t *mpint)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_write_mpi (estream_t stream, gcry_mpi_t mpint) es_write_mpi (estream_t stream, gcry_mpi_t mpint)
{ {
@ -383,6 +517,7 @@ es_write_mpi (estream_t stream, gcry_mpi_t mpint)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_read_file (const char *filename, unsigned char **buffer, size_t *buffer_n) es_read_file (const char *filename, unsigned char **buffer, size_t *buffer_n)
{ {
@ -434,6 +569,7 @@ es_read_file (const char *filename, unsigned char **buffer, size_t *buffer_n)
return err; return err;
} }
static gpg_error_t static gpg_error_t
es_copy (estream_t dst, estream_t src) es_copy (estream_t dst, estream_t src)
{ {
@ -463,9 +599,14 @@ es_copy (estream_t dst, estream_t src)
return err; return err;
} }
/* MPI lists. */ /*
MPI lists.
*/
static void static void
mpint_list_free (gcry_mpi_t *mpi_list) mpint_list_free (gcry_mpi_t *mpi_list)
@ -480,6 +621,7 @@ mpint_list_free (gcry_mpi_t *mpi_list)
} }
} }
static gpg_error_t static gpg_error_t
ssh_receive_mpint_list (estream_t stream, int secret, ssh_receive_mpint_list (estream_t stream, int secret,
ssh_key_type_spec_t key_spec, gcry_mpi_t **mpi_list) ssh_key_type_spec_t key_spec, gcry_mpi_t **mpi_list)
@ -593,8 +735,7 @@ ssh_signature_encoder_rsa (estream_t signature_blob, gcry_mpi_t *mpis)
return err; return err;
} }
#define SSH_DSA_SIGNATURE_PADDING 20
#define SSH_DSA_SIGNATURE_ELEMS 2
static gpg_error_t static gpg_error_t
ssh_signature_encoder_dsa (estream_t signature_blob, gcry_mpi_t *mpis) ssh_signature_encoder_dsa (estream_t signature_blob, gcry_mpi_t *mpis)
@ -639,27 +780,9 @@ ssh_signature_encoder_dsa (estream_t signature_blob, gcry_mpi_t *mpis)
return err; return err;
} }
#define SPEC_FLAG_USE_PKCS1V2 (1 << 0) /*
S-Expressions.
*/
/* Table holding key type specifications. */
static ssh_key_type_spec_t ssh_key_types[] =
{
{
"ssh-rsa", "rsa", "nedupq", "en", "dupq", "s", "nedpqu",
ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
SPEC_FLAG_USE_PKCS1V2
},
{
"ssh-dss", "dsa", "pqgyx", "pqgy", "x", "rs", "pqgyx",
NULL, ssh_signature_encoder_dsa,
0
},
};
/* S-Expressions. */
static gpg_error_t static gpg_error_t
ssh_sexp_construct (gcry_sexp_t *sexp, ssh_sexp_construct (gcry_sexp_t *sexp,
@ -685,7 +808,9 @@ ssh_sexp_construct (gcry_sexp_t *sexp,
elems = key_spec.elems_key_public; elems = key_spec.elems_key_public;
elems_n = strlen (elems); elems_n = strlen (elems);
sexp_template_n = 33 + strlen (key_spec.identifier) + (elems_n * 6) - (! secret); /* FIXME: Why 33? -wk */
sexp_template_n = (33 + strlen (key_spec.identifier)
+ (elems_n * 6) - (!secret));
sexp_template = xtrymalloc (sexp_template_n); sexp_template = xtrymalloc (sexp_template_n);
if (! sexp_template) if (! sexp_template)
{ {
@ -765,13 +890,13 @@ ssh_sexp_extract (gcry_sexp_t sexp,
goto out; goto out;
} }
if ((data_n == 10) && (! strncmp (data, "public-key", 10))) if (data_n == 10 && !strncmp (data, "public-key", 10))
{ {
is_secret = 0; is_secret = 0;
elems = key_spec.elems_key_public; elems = key_spec.elems_key_public;
} }
else if (((data_n == 11) && (! strncmp (data, "private-key", 11))) else if ((data_n == 11 && !strncmp (data, "private-key", 11))
|| ((data_n == 21) && (! strncmp (data, "protected-private-key", 21)))) || (data_n == 21 && !strncmp (data, "protected-private-key", 21)))
{ {
is_secret = 1; is_secret = 1;
elems = key_spec.elems_key_secret; elems = key_spec.elems_key_secret;
@ -934,8 +1059,8 @@ ssh_key_type_lookup (const char *ssh_name, const char *name,
} }
static gpg_error_t static gpg_error_t
ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret, int read_comment, ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
ssh_key_type_spec_t *key_spec) int read_comment, ssh_key_type_spec_t *key_spec)
{ {
gpg_error_t err; gpg_error_t err;
char *key_type; char *key_type;
@ -1093,7 +1218,8 @@ ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
if (err) if (err)
goto out; goto out;
err = ssh_convert_key_to_blob (&blob, &blob_n, spec.ssh_identifier, mpi_list); err = ssh_convert_key_to_blob (&blob, &blob_n,
spec.ssh_identifier, mpi_list);
if (err) if (err)
goto out; goto out;
@ -1268,27 +1394,13 @@ key_secret_to_public (gcry_sexp_t *key_public,
static char * /*
make_cstring (const char *data, size_t data_n) Request handler.
{ */
char *s;
s = xtrymalloc (data_n + 1);
if (s)
{
strncpy (s, data, data_n);
s[data_n] = 0;
}
return s;
}
/* Request handler. */
static gpg_error_t static gpg_error_t
ssh_handler_request_identities (ctrl_t ctrl, estream_t request, estream_t response) ssh_handler_request_identities (ctrl_t ctrl,
estream_t request, estream_t response)
{ {
const char *key_type; const char *key_type;
ssh_key_type_spec_t spec; ssh_key_type_spec_t spec;
@ -1298,7 +1410,7 @@ ssh_handler_request_identities (ctrl_t ctrl, estream_t request, estream_t respon
char *key_path; char *key_path;
unsigned char *buffer; unsigned char *buffer;
size_t buffer_n; size_t buffer_n;
uint32_t key_counter; u32 key_counter;
estream_t key_blobs; estream_t key_blobs;
gcry_sexp_t key_secret; gcry_sexp_t key_secret;
gcry_sexp_t key_public; gcry_sexp_t key_public;
@ -1468,11 +1580,11 @@ data_hash (unsigned char *data, size_t data_n,
return 0; return 0;
} }
static gpg_error_t static gpg_error_t
data_sign (CTRL ctrl, ssh_signature_encoder_t sig_encoder, data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder,
unsigned char **sig, size_t *sig_n) unsigned char **sig, size_t *sig_n)
{ {
char description[] = "Please provide the passphrase for key `%c':";
gpg_error_t err; gpg_error_t err;
gcry_sexp_t signature_sexp; gcry_sexp_t signature_sexp;
estream_t stream; estream_t stream;
@ -1501,7 +1613,9 @@ data_sign (CTRL ctrl, ssh_signature_encoder_t sig_encoder,
sig_value = NULL; sig_value = NULL;
mpis = NULL; mpis = NULL;
err = agent_pksign_do (ctrl, description, &signature_sexp, 0); err = agent_pksign_do (ctrl,
_("Please provide the passphrase "
"for the ssh key `%c':"), &signature_sexp, 0);
if (err) if (err)
goto out; goto out;
@ -1632,12 +1746,12 @@ ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response)
unsigned int hash_n; unsigned int hash_n;
unsigned char key_grip[20]; unsigned char key_grip[20];
unsigned char *key_blob; unsigned char *key_blob;
uint32_t key_blob_size; u32 key_blob_size;
unsigned char *data; unsigned char *data;
unsigned char *sig; unsigned char *sig;
size_t sig_n; size_t sig_n;
uint32_t data_size; u32 data_size;
uint32_t flags; u32 flags;
const void *p; const void *p;
gpg_error_t err; gpg_error_t err;
gpg_error_t ret_err; gpg_error_t ret_err;
@ -1886,6 +2000,11 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
if (err) if (err)
goto out; goto out;
/* FIXME: What the hell is that: Never have use sprintf in that way.
When marking a string translatbale you might get a buffer
overflow. We have never done this elsewhere. Using [x]asprintf
is the right way!! */
description_length = 95 + (comment ? strlen (comment) : 0); description_length = 95 + (comment ? strlen (comment) : 0);
description = malloc (description_length); description = malloc (description_length);
if (! description) if (! description)
@ -1954,7 +2073,7 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
gpg_error_t ret_err; gpg_error_t ret_err;
gpg_error_t err; gpg_error_t err;
gcry_sexp_t key; gcry_sexp_t key;
byte_t b; unsigned char b;
int confirm; int confirm;
int ttl; int ttl;
@ -1980,7 +2099,7 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
{ {
case SSH_OPT_CONSTRAIN_LIFETIME: case SSH_OPT_CONSTRAIN_LIFETIME:
{ {
uint32_t n = 0; u32 n = 0;
err = es_read_uint32 (request, &n); err = es_read_uint32 (request, &n);
if (! err) if (! err)
@ -2017,10 +2136,11 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
} }
static gpg_error_t static gpg_error_t
ssh_handler_remove_identity (ctrl_t ctrl, estream_t request, estream_t response) ssh_handler_remove_identity (ctrl_t ctrl, estream_t request,
estream_t response)
{ {
unsigned char *key_blob; unsigned char *key_blob;
uint32_t key_blob_size; u32 key_blob_size;
gcry_sexp_t key; gcry_sexp_t key;
gpg_error_t ret_err; gpg_error_t ret_err;
gpg_error_t err; gpg_error_t err;
@ -2065,7 +2185,8 @@ ssh_identities_remove_all (void)
} }
static gpg_error_t static gpg_error_t
ssh_handler_remove_all_identities (ctrl_t ctrl, estream_t request, estream_t response) ssh_handler_remove_all_identities (ctrl_t ctrl, estream_t request,
estream_t response)
{ {
gpg_error_t ret_err; gpg_error_t ret_err;
gpg_error_t err; gpg_error_t err;
@ -2083,7 +2204,7 @@ ssh_lock (void)
gpg_error_t err; gpg_error_t err;
/* FIXME */ /* FIXME */
log_error ("[gpg-agent/ssh] lock command is not implemented\n"); log_error (_("lock command is not implemented\n"));
err = 0; err = 0;
return err; return err;
@ -2094,7 +2215,7 @@ ssh_unlock (void)
{ {
gpg_error_t err; gpg_error_t err;
log_error ("[gpg-agent/ssh] unlock command is not implemented\n"); log_error (_("unlock command is not implemented\n"));
err = 0; err = 0;
return err; return err;
@ -2128,39 +2249,19 @@ ssh_handler_unlock (ctrl_t ctrl, estream_t request, estream_t response)
/* Associating request types with the corresponding request
handlers. */
#define REQUEST_SPEC_DEFINE(id, name) \
{ SSH_REQUEST_##id, ssh_handler_##name, #name }
static ssh_request_spec_t request_specs[] =
{
REQUEST_SPEC_DEFINE (REQUEST_IDENTITIES, request_identities),
REQUEST_SPEC_DEFINE (SIGN_REQUEST, sign_request),
REQUEST_SPEC_DEFINE (ADD_IDENTITY, add_identity),
REQUEST_SPEC_DEFINE (ADD_ID_CONSTRAINED, add_identity),
REQUEST_SPEC_DEFINE (REMOVE_IDENTITY, remove_identity),
REQUEST_SPEC_DEFINE (REMOVE_ALL_IDENTITIES, remove_all_identities),
REQUEST_SPEC_DEFINE (LOCK, lock),
REQUEST_SPEC_DEFINE (UNLOCK, unlock)
};
static int static int
ssh_request_process (ctrl_t ctrl, estream_t stream_sock) ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
{ {
estream_t response; estream_t response;
estream_t request; estream_t request;
byte_t request_type; unsigned char request_type;
gpg_error_t err; gpg_error_t err;
unsigned int i; unsigned int i;
int send_err; int send_err;
int ret; int ret;
unsigned char *request_data; unsigned char *request_data;
uint32_t request_data_size; u32 request_data_size;
uint32_t response_size; u32 response_size;
request_data = NULL; request_data = NULL;
response = NULL; response = NULL;
@ -2170,15 +2271,22 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
/* Create memory streams for request/response data. The entire /* Create memory streams for request/response data. The entire
request will be stored in secure memory, since it might contain request will be stored in secure memory, since it might contain
secret key material. The response does not have to be stored in secret key material. The response does not have to be stored in
secure memory, since we never give out secret keys. */ secure memory, since we never give out secret keys.
FIXME: This is a pretty good DoS. We only have a limited amount
of secure memory, we can't trhow hin everything we get from a
client -wk */
/* Retrieve request. */ /* Retrieve request. */
err = es_read_string (stream_sock, 1, &request_data, &request_data_size); err = es_read_string (stream_sock, 1, &request_data, &request_data_size);
if (err) if (err)
goto out; goto out;
if (opt.verbose) if (opt.verbose) /* FIXME: using log_debug is not good with
log_debug ("[gpg-agent/ssh] Received request of length: %u\n", verbose. log_debug should only be used in
debugging mode or in sitattions which are
unexpected. */
log_debug ("received request of length: %u\n",
request_data_size); request_data_size);
request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+"); request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+");
@ -2217,14 +2325,14 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
break; break;
if (i == DIM (request_specs)) if (i == DIM (request_specs))
{ {
log_debug ("[gpg-agent/ssh] request %u is not supported\n", log_debug ("request %u is not supported\n",
request_type); request_type);
send_err = 1; send_err = 1;
goto out; goto out;
} }
if (opt.verbose) if (opt.verbose)
log_debug ("[gpg-agent/ssh] Executing request handler: %s (%u)\n", log_debug ("executing request handler: %s (%u)\n",
request_specs[i].identifier, request_specs[i].type); request_specs[i].identifier, request_specs[i].type);
err = (*request_specs[i].handler) (ctrl, request, response); err = (*request_specs[i].handler) (ctrl, request, response);
@ -2260,7 +2368,7 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
out: out:
if (err && es_feof (stream_sock)) if (err && es_feof (stream_sock))
log_error ("[gpg-agent/ssh] Error occured while processing request: %s\n", log_error ("error occured while processing request: %s\n",
gpg_strerror (err)); gpg_strerror (err));
if (send_err) if (send_err)
@ -2304,7 +2412,7 @@ start_command_handler_ssh (int sock_client)
if (!stream_sock) if (!stream_sock)
{ {
err = gpg_error_from_errno (errno); err = gpg_error_from_errno (errno);
log_error ("[gpg-agent/ssh] Failed to create stream from socket: %s\n", log_error (_("failed to create stream from socket: %s\n"),
gpg_strerror (err)); gpg_strerror (err));
goto out; goto out;
} }
@ -2314,14 +2422,13 @@ start_command_handler_ssh (int sock_client)
if (ret) if (ret)
{ {
err = gpg_error_from_errno (errno); err = gpg_error_from_errno (errno);
log_error ("[gpg-agent/ssh] Failed to disable buffering " log_error (_("failed to disable buffering "
"on socket stream: %s\n", gpg_strerror (err)); "on socket stream: %s\n"), gpg_strerror (err));
goto out; goto out;
} }
while (1) while (1)
{ {
/* Process request. */
bad = ssh_request_process (&ctrl, stream_sock); bad = ssh_request_process (&ctrl, stream_sock);
if (bad) if (bad)
break; break;

View File

@ -143,101 +143,79 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
/* Modify a Key description, replacing certain special format /* Modify a Key description, replacing certain special format
characters. List of currently supported replacements: characters. List of currently supported replacements:
%% -> % %% - Replaced by a single %
%c -> <COMMENT>. */ %c - Replaced by the content of COMMENT.
static int
modify_description (const char *description, The functions returns 0 on success or an error code. On success a
const char *comment, size_t comment_length, newly allocated string is stored at the address of RESULT.
char **description_modified) */
static gpg_error_t
modify_description (const char *in, const char *comment, char **result)
{ {
size_t description_length; size_t comment_length;
size_t description_new_length; size_t in_len;
gpg_error_t err; size_t out_len;
char *description_new; char *out;
unsigned int i, j; size_t i;
unsigned int special; int special, pass;
description_length = strlen (description); comment_length = strlen (comment);
description_new_length = description_length; in_len = strlen (in);
description_new = NULL;
/* Calculate length. */ /* First pass calculates the length, second pass does the actual
copying. */
out = NULL;
out_len = 0;
for (pass=0; pass < 2; pass++)
{
special = 0; special = 0;
for (i = 0; i < description_length; i++) for (i = 0; i < in_len; i++)
{ {
if (description[i] == '%') if (in[i] == '%')
special = 1; special = 1;
else else if (special)
{ {
if (special)
{
description_new_length -= 2;
switch (description[i])
{
case 'c':
/* Comment. */
description_new_length += comment_length;
break;
case '%':
description_new_length += 1;
break;
}
special = 0; special = 0;
} switch (in[i])
}
}
/* Allocate. */
description_new = xtrymalloc (description_new_length + 1);
if (! description_new)
{ {
err = gpg_error_from_errno (errno);
goto out;
}
/* Fill. */
for (i = j = 0; i < description_length; i++)
{
if (description[i] == '%')
special = 1;
else
{
if (special)
{
switch (description[i])
{
case 'c':
/* Comment. */
if (comment)
{
strncpy (description_new + j, comment, comment_length);
j += comment_length;
}
break;
case '%': case '%':
description_new[j] = '%'; out_len++;
j++; if (out)
*out++ = '%';
break;
case 'c': /* Comment. */
out_len += comment_length;
if (out && comment_length)
{
memcpy (out, comment, comment_length);
out += comment_length;
}
break;
default: /* Invalid special sequences are ignored. */
break; break;
} }
special = 0;
} }
else else
{ {
description_new[j] = description[i]; out_len++;
j++; if (out)
} *out++ = in[i];
} }
} }
description_new[j] = 0; if (!pass)
*description_modified = description_new; {
err = 0; *result = out = xtrymalloc (out_len + 1);
if (!out)
return gpg_error_from_errno (errno);
}
}
out: *out = 0;
assert (*result + out_len == out);
return err; return 0;
} }
@ -398,26 +376,42 @@ agent_key_from_file (CTRL ctrl, const char *desc_text,
gcry_sexp_t comment_sexp; gcry_sexp_t comment_sexp;
size_t comment_length; size_t comment_length;
char *desc_text_final; char *desc_text_final;
const char *comment; const char *comment = NULL;
/* Note, that we will take the comment as a C styring for
display purposes; i.e. all stuff beyond a Nul character is
ignored. */
comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
if (comment_sexp) if (comment_sexp)
comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length); comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
else if (!comment)
{ {
comment = NULL; comment = "";
comment_length = 0; comment_length = 0;
} }
desc_text_final = NULL;
if (desc_text) if (desc_text)
{ {
rc = modify_description (desc_text, if (comment[comment_length])
comment, comment_length, &desc_text_final); {
if (rc) /* Not a C-string; create one. We might here allocate
log_error ("failed to modify description: %s\n", gpg_strerror (rc)); more than actually displayed but well, that
shouldn't be a problem. */
char *tmp = xtrymalloc (comment_length+1);
if (!tmp)
rc = gpg_error_from_errno (errno);
else
{
memcpy (tmp, comment, comment_length);
tmp[comment_length] = 0;
rc = modify_description (desc_text, tmp, &desc_text_final);
xfree (tmp);
}
} }
else else
desc_text_final = NULL; rc = modify_description (desc_text, comment, &desc_text_final);
}
if (!rc) if (!rc)
{ {

View File

@ -51,6 +51,7 @@
#include "../jnlib/w32-afunix.h" #include "../jnlib/w32-afunix.h"
#endif #endif
enum cmd_and_opt_values enum cmd_and_opt_values
{ aNull = 0, { aNull = 0,
oCsh = 'c', oCsh = 'c',
@ -146,7 +147,7 @@ static ARGPARSE_OPTS opts[] = {
N_("allow clients to mark keys as \"trusted\"")}, N_("allow clients to mark keys as \"trusted\"")},
{ oAllowPresetPassphrase, "allow-preset-passphrase", 0, { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
N_("allow presetting passphrase")}, N_("allow presetting passphrase")},
{ oSSHSupport, "ssh-support", 0, "Enable SSH-Agent emulation" }, { oSSHSupport, "ssh-support", 0, N_("enable secure ssh-agent emulation") },
{0} {0}
}; };
@ -163,7 +164,7 @@ static int shutdown_pending;
/* It is possible that we are currently running under setuid permissions */ /* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1; static int maybe_setuid = 1;
/* Name of the communication socket */ /* Name of the communication socket used for native gpg-agent requests. */
static char *socket_name; static char *socket_name;
/* Name of the communication socket used for ssh-agent-emulation. */ /* Name of the communication socket used for ssh-agent-emulation. */
@ -186,8 +187,15 @@ static const char *debug_level;
the log file after a SIGHUP if it didn't changed. Malloced. */ the log file after a SIGHUP if it didn't changed. Malloced. */
static char *current_logfile; static char *current_logfile;
/* Local prototypes. */ /*
Local prototypes.
*/
static char *create_socket_name (int use_standard_socket,
char *standard_name, char *template);
static int create_server_socket (int is_standard_name, const char *name);
static void create_directories (void); static void create_directories (void);
#ifdef USE_GNU_PTH #ifdef USE_GNU_PTH
static void handle_connections (int listen_fd, int listen_fd_ssh); static void handle_connections (int listen_fd, int listen_fd_ssh);
/* Pth wrapper function definitions. */ /* Pth wrapper function definitions. */
@ -198,6 +206,12 @@ static int check_for_running_agent (int);
/*
Functions.
*/
static const char * static const char *
my_strusage (int level) my_strusage (int level)
{ {
@ -302,8 +316,9 @@ set_debug (void)
} }
/* Helper for cleanup to remove one socket with NAME. */
static void static void
cleanup_do (char *name) remove_socket (char *name)
{ {
if (name && *name) if (name && *name)
{ {
@ -324,8 +339,8 @@ cleanup_do (char *name)
static void static void
cleanup (void) cleanup (void)
{ {
cleanup_do (socket_name); remove_socket (socket_name);
cleanup_do (socket_name_ssh); remove_socket (socket_name_ssh);
} }
@ -417,105 +432,6 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
} }
static void
create_socket_name (char **name, int standard_socket,
struct sockaddr_un *serv_addr,
char *standard_identifier, char *identifier)
{
char *p;
if (standard_socket)
*name = make_filename (opt.homedir, standard_identifier, NULL);
else
{
*name = xstrdup (identifier);
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 (strchr (*name, PATHSEP_C))
{
log_error ("`%s' are not allowed in the socket name\n", PATHSEP_S);
exit (1);
}
if (strlen (*name) + 1 >= sizeof serv_addr->sun_path)
{
log_error ("name of socket too long\n");
exit (1);
}
}
static int
create_server_socket (struct sockaddr_un *serv_addr,
int standard_socket, const char *name)
{
socklen_t len;
int fd;
int rc;
#ifdef HAVE_W32_SYSTEM
fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
#else
fd = socket (AF_UNIX, SOCK_STREAM, 0);
#endif
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);
#ifdef HAVE_W32_SYSTEM
rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
if ((rc == -1) && standard_socket)
{
remove (name);
rc = bind (fd, (struct sockaddr*) serv_addr, len);
}
#else
rc = bind (fd, (struct sockaddr*) serv_addr, len);
if ((rc == -1) && standard_socket && (errno == EADDRINUSE))
{
remove (name);
rc = bind (fd, (struct sockaddr*) serv_addr, len);
}
#endif
if (rc == -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);
return fd;
}
int int
main (int argc, char **argv ) main (int argc, char **argv )
{ {
@ -865,8 +781,6 @@ main (int argc, char **argv )
int fd; int fd;
int fd_ssh; int fd_ssh;
pid_t pid; pid_t pid;
struct sockaddr_un serv_addr;
struct sockaddr_un serv_addr_ssh;
/* Remove the DISPLAY variable so that a pinentry does not /* Remove the DISPLAY variable so that a pinentry does not
default to a specific display. There is still a default default to a specific display. There is still a default
@ -877,27 +791,27 @@ main (int argc, char **argv )
unsetenv ("DISPLAY"); unsetenv ("DISPLAY");
#endif #endif
/* Create the socket name . */
create_socket_name (&socket_name, standard_socket, &serv_addr,
"S.gpg-agent", "/tmp/gpg-XXXXXX/S.gpg-agent");
if (opt.ssh_support)
create_socket_name (&socket_name_ssh, standard_socket, &serv_addr_ssh,
"S.gpg-agent.ssh", "/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
fd = create_server_socket (&serv_addr, /* Create the sockets. */
standard_socket, socket_name); socket_name = create_socket_name (standard_socket,
"S.gpg-agent",
"/tmp/gpg-XXXXXX/S.gpg-agent");
if (opt.ssh_support) if (opt.ssh_support)
fd_ssh = create_server_socket (&serv_addr_ssh, socket_name_ssh = create_socket_name (standard_socket,
standard_socket, socket_name_ssh); "S.gpg-agent.ssh",
"/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
fd = create_server_socket (standard_socket, socket_name);
if (opt.ssh_support)
fd_ssh = create_server_socket (standard_socket, socket_name_ssh);
else else
/* Make the compiler happy. */
fd_ssh = -1; fd_ssh = -1;
fflush (NULL); fflush (NULL);
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
pid = getpid (); pid = getpid ();
printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid); printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
#else /*!HAVE_W32_SYSTEM*/ #else /*!HAVE_W32_SYSTEM*/
pid = fork (); pid = fork ();
if (pid == (pid_t)-1) if (pid == (pid_t)-1)
@ -911,7 +825,7 @@ main (int argc, char **argv )
close (fd); close (fd);
/* create the info string: <name>:<pid>:<protocol_version> */ /* Create the info string: <name>:<pid>:<protocol_version> */
if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1", if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
socket_name, (ulong)pid ) < 0) socket_name, (ulong)pid ) < 0)
{ {
@ -937,13 +851,14 @@ main (int argc, char **argv )
} }
} }
*socket_name = 0; /* don't let cleanup() remove the socket - *socket_name = 0; /* Don't let cleanup() remove the socket -
the child should do this from now on */ the child should do this from now on */
if (opt.ssh_support) if (opt.ssh_support)
*socket_name_ssh = 0; *socket_name_ssh = 0;
if (argc) if (argc)
{ /* run the program given on the commandline */ { /* Run the program given on the commandline. */
if (putenv (infostr)) if (putenv (infostr))
{ {
log_error ("failed to set environment: %s\n", log_error ("failed to set environment: %s\n",
@ -972,7 +887,7 @@ main (int argc, char **argv )
} }
else else
{ {
/* print the environment string, so that the caller can use /* Print the environment string, so that the caller can use
shell's eval to set it */ shell's eval to set it */
if (csh_style) if (csh_style)
{ {
@ -995,6 +910,7 @@ main (int argc, char **argv )
printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid); printf ("%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
} }
} }
/* Note: teh standard free is here correct. */
free (infostr); free (infostr);
if (opt.ssh_support) if (opt.ssh_support)
{ {
@ -1003,8 +919,8 @@ main (int argc, char **argv )
} }
exit (0); exit (0);
} }
/*NEVER REACHED*/ /*NOTREACHED*/
} /* end parent */ } /* End parent */
/* /*
This is the child This is the child
@ -1181,6 +1097,125 @@ reread_configuration (void)
} }
/* Create a name for the socket. With USE_STANDARD_SOCKET given as
true ising STANDARD_NAME in the home directory or if given has
false from the mkdir type name TEMPLATE. In the latter case a
unique name in a unique new directory will be created. In both
cases check for valid characters as well as against a maximum
allowed length for a unix domain socket is done. The function
terminates the process in case of an error. Retunrs: Pointer to an
allcoated string with the absolute name of the socket used. */
static char *
create_socket_name (int use_standard_socket,
char *standard_name, char *template)
{
char *name, *p;
if (use_standard_socket)
name = make_filename (opt.homedir, standard_name, NULL);
else
{
name = xstrdup (template);
p = strrchr (name, '/');
if (!p)
BUG ();
*p = 0;
if (!mkdtemp (name))
{
log_error (_("can't create directory `%s': %s\n"),
name, strerror (errno));
agent_exit (2);
}
*p = '/';
}
if (strchr (name, PATHSEP_C))
{
log_error (("`%s' are not allowed in the socket name\n"), PATHSEP_S);
agent_exit (2);
}
if (strlen (name) + 1 >= DIMof (struct sockaddr_un, sun_path) )
{
log_error (_("name of socket too long\n"));
agent_exit (2);
}
return name;
}
/* Create a Unix domain socket with NAME. IS_STANDARD_NAME indicates
whether a non-random socket is used. Returns the filedescriptor or
terminates the process in case of an error. */
static int
create_server_socket (int is_standard_name, const char *name)
{
struct sockaddr_un *serv_addr;
socklen_t len;
int fd;
int rc;
#ifdef HAVE_W32_SYSTEM
fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
#else
fd = socket (AF_UNIX, SOCK_STREAM, 0);
#endif
if (fd == -1)
{
log_error (_("can't create socket: %s\n"), strerror (errno));
agent_exit (2);
}
memset (serv_addr, 0, sizeof *serv_addr);
serv_addr->sun_family = AF_UNIX;
assert (strlen (name) + 1 < sizeof (serv_addr->sun_path));
strcpy (serv_addr->sun_path, name);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen (serv_addr->sun_path) + 1);
#ifdef HAVE_W32_SYSTEM
rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
if (is_standard_name && rc == -1 )
{
remove (name);
rc = bind (fd, (struct sockaddr*) serv_addr, len);
}
#else
rc = bind (fd, (struct sockaddr*) serv_addr, len);
if (is_standard_name && rc == -1 && errno == EADDRINUSE)
{
remove (name);
rc = bind (fd, (struct sockaddr*) serv_addr, len);
}
#endif
if (rc == -1)
{
log_error (_("error binding socket to `%s': %s\n"),
serv_addr->sun_path, strerror (errno));
close (fd);
agent_exit (2);
}
if (listen (fd, 5 ) == -1)
{
log_error (_("listen() failed: %s\n"), strerror (errno));
close (fd);
agent_exit (2);
}
if (opt.verbose)
log_info (_("listening on socket `%s'\n"), serv_addr->sun_path);
return fd;
}
/* Check that the directory for storing the private keys exists and
create it if not. This function won't fail as it is only a
convenience function and not strictly necessary. */
static void static void
create_private_keys_directory (const char *home) create_private_keys_directory (const char *home)
{ {
@ -1248,11 +1283,11 @@ create_directories (void)
} }
} }
else else
log_error ("error stat-ing `%s': %s\n", home, strerror (errno)); log_error (_("stat() failed for `%s': %s\n"), home, strerror (errno));
} }
else if ( !S_ISDIR(statbuf.st_mode)) else if ( !S_ISDIR(statbuf.st_mode))
{ {
log_error ("can't use `%s' as home directory\n", home); log_error (_("can't use `%s' as home directory\n"), home);
} }
else /* exists and is a directory. */ else /* exists and is a directory. */
{ {
@ -1315,13 +1350,14 @@ handle_signal (int signo)
} }
/* This is the standard connection thread's main function. */
static void * static void *
start_connection_thread (void *arg) start_connection_thread (void *arg)
{ {
int fd = (int)arg; int fd = (int)arg;
if (opt.verbose) if (opt.verbose)
log_info ("handler for fd %d started\n", fd); log_info (_("handler for fd %d started\n"), fd);
/* FIXME: Move this housekeeping into a ticker function. Calling it /* FIXME: Move this housekeeping into a ticker function. Calling it
for each connection should work but won't work anymore if our for each connection should work but won't work anymore if our
@ -1330,31 +1366,33 @@ start_connection_thread (void *arg)
start_command_handler (-1, fd); start_command_handler (-1, fd);
if (opt.verbose) if (opt.verbose)
log_info ("handler for fd %d terminated\n", fd); log_info (_("handler for fd %d terminated\n"), fd);
return NULL; return NULL;
} }
/* This is the ssh connection thread's main function. */
static void * static void *
start_connection_thread_ssh (void *arg) start_connection_thread_ssh (void *arg)
{ {
int fd = (int)arg; int fd = (int)arg;
if (opt.verbose) if (opt.verbose)
log_info ("ssh handler for fd %d started\n", fd); 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 (); agent_trustlist_housekeeping ();
start_command_handler_ssh (fd); start_command_handler_ssh (fd);
if (opt.verbose) if (opt.verbose)
log_info ("ssh handler for fd %d terminated\n", fd); log_info (_("ssh handler for fd %d terminated\n"), fd);
return NULL; return NULL;
} }
/* Connection handler loop. Wait for coecntion requests and spawn a
thread after accepting a connection. */
static void static void
handle_connections (int listen_fd, int listen_fd_ssh) handle_connections (int listen_fd, int listen_fd_ssh)
{ {
@ -1363,7 +1401,7 @@ handle_connections (int listen_fd, int listen_fd_ssh)
sigset_t sigs; sigset_t sigs;
int signo; int signo;
struct sockaddr_un paddr; struct sockaddr_un paddr;
socklen_t plen = sizeof ( paddr ); socklen_t plen;
fd_set fdset, read_fdset; fd_set fdset, read_fdset;
int ret; int ret;
int fd; int fd;
@ -1406,74 +1444,62 @@ handle_connections (int listen_fd, int listen_fd_ssh)
continue; continue;
} }
/* POSIX says that fd_set should be implemented as a structure,
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset; read_fdset = fdset;
ret = pth_select (FD_SETSIZE, &read_fdset, NULL, NULL, NULL);
ret = pth_select_ev (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev);
if (ret == -1) if (ret == -1)
{ {
log_error ("pth_select failed: %s - waiting 1s\n", log_error (_("pth_select failed: %s - waiting 1s\n"),
strerror (errno)); strerror (errno));
pth_sleep (1); pth_sleep (1);
continue; continue;
} }
if (pth_event_occurred (ev))
{
handle_signal (signo);
}
if (FD_ISSET (listen_fd, &read_fdset)) if (FD_ISSET (listen_fd, &read_fdset))
{ {
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev); plen = sizeof paddr;
fd = pth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
if (fd == -1) if (fd == -1)
{ {
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */ log_error ("accept failed: %s\n", strerror (errno));
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)); else if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
pth_sleep(1);
continue;
}
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
{ {
log_error ("error spawning connection handler: %s\n", log_error ("error spawning connection handler: %s\n",
strerror (errno) ); strerror (errno) );
close (fd); close (fd);
} }
} fd = -1;
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)) if (listen_fd_ssh != -1 && FD_ISSET (listen_fd_ssh, &read_fdset))
{ {
log_error ("error spawning connection handler: %s\n", plen = sizeof paddr;
fd = pth_accept (listen_fd_ssh, (struct sockaddr *)&paddr, &plen);
if (fd == -1)
{
log_error ("accept failed for ssh: %s\n", strerror (errno));
}
else if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
{
log_error ("error spawning ssh connection handler: %s\n",
strerror (errno) ); strerror (errno) );
close (fd); close (fd);
} }
fd = -1;
} }
} }
pth_event_free (ev, PTH_FREE_ALL); pth_event_free (ev, PTH_FREE_ALL);
cleanup (); cleanup ();
log_info ("%s %s stopped\n", strusage(11), strusage(13)); log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
} }
#endif /*USE_GNU_PTH*/ #endif /*USE_GNU_PTH*/
@ -1527,6 +1553,7 @@ check_for_running_agent (int mode)
else /* MODE != 0 */ else /* MODE != 0 */
{ {
infostr = make_filename (opt.homedir, "S.gpg-agent", NULL); infostr = make_filename (opt.homedir, "S.gpg-agent", NULL);
pid = (pid_t)(-1);
} }

View File

@ -198,4 +198,5 @@ estream_t es_tmpfile (void);
void es_opaque_set (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque); void es_opaque_set (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque);
void *es_opaque_get (estream_t stream); void *es_opaque_get (estream_t stream);
#endif #endif /*ESTREAM_H*/