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:
parent
625bafa4da
commit
b326996b78
140
AUTHORS
140
AUTHORS
@ -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.
|
||||||
|
|
@ -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.
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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 --*/
|
||||||
|
@ -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;
|
||||||
|
162
agent/findkey.c
162
agent/findkey.c
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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*/
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user