mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
* no-pth.c, Makefile.am: Removed.
* call-scd.c: Seirialized all scdaeom access when using Pth. * cache.c: Made the cache Pth-thread-safe. (agent_unlock_cache_entry): New. * findkey.c (unprotect): Unlock the returned cache value. * command.c (cmd_get_passphrase): Ditto. * gpg-agent.c (main): Register pth_read/write with Assuan.
This commit is contained in:
parent
72f48d9e8a
commit
b209c17be9
@ -1,3 +1,25 @@
|
||||
2002-05-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-scd.c: Seirialized all scdaeom access when using Pth.
|
||||
|
||||
* cache.c: Made the cache Pth-thread-safe.
|
||||
(agent_unlock_cache_entry): New.
|
||||
* findkey.c (unprotect): Unlock the returned cache value.
|
||||
* command.c (cmd_get_passphrase): Ditto.
|
||||
|
||||
* gpg-agent.c (main): Register pth_read/write with Assuan.
|
||||
|
||||
2002-05-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* query.c: Serialized all pinentry access when using Pth.
|
||||
|
||||
* gpg-agent.c (handle_signal,start_connection_thread)
|
||||
(handle_connections): New
|
||||
(main): Use the new Pth stuff to allow concurrent connections.
|
||||
* command.c (start_command_handler): Add new arg FD so that the
|
||||
fucntion can also be used for an already connected socket.
|
||||
* Makefile.am: Link with Pth.
|
||||
|
||||
2002-05-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* cache.c (housekeeping, agent_put_cache): Use our time() wrapper.
|
||||
|
@ -21,7 +21,7 @@
|
||||
bin_PROGRAMS = gpg-agent
|
||||
noinst_PROGRAMS = protect-tool
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS)
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) $(PTH_CFLAGS)
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
gpg_agent_SOURCES = \
|
||||
@ -43,7 +43,7 @@ gpg_agent_SOURCES = \
|
||||
|
||||
|
||||
gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
|
||||
../common/libcommon.a $(LIBGCRYPT_LIBS)
|
||||
../common/libcommon.a $(LIBGCRYPT_LIBS) $(PTH_LIBS)
|
||||
|
||||
protect_tool_SOURCES = \
|
||||
protect-tool.c \
|
||||
|
@ -104,7 +104,7 @@ void agent_exit (int rc); /* also implemented in other tools */
|
||||
const char *trans (const char *text);
|
||||
|
||||
/*-- command.c --*/
|
||||
void start_command_handler (int);
|
||||
void start_command_handler (int, int);
|
||||
|
||||
/*-- findkey.c --*/
|
||||
int agent_write_private_key (const unsigned char *grip,
|
||||
@ -124,8 +124,8 @@ int agent_get_confirmation (const char *desc, const char *ok,
|
||||
|
||||
/*-- cache.c --*/
|
||||
int agent_put_cache (const char *key, const char *data, int ttl);
|
||||
const char *agent_get_cache (const char *key);
|
||||
|
||||
const char *agent_get_cache (const char *key, void **cache_id);
|
||||
void agent_unlock_cache_entry (void **cache_id);
|
||||
|
||||
|
||||
/*-- pksign.c --*/
|
||||
|
@ -40,6 +40,7 @@ struct cache_item_s {
|
||||
time_t created;
|
||||
time_t accessed;
|
||||
int ttl; /* max. lifetime given in seonds */
|
||||
int lockcount;
|
||||
struct secret_data_s *pw;
|
||||
char key[1];
|
||||
};
|
||||
@ -87,7 +88,7 @@ housekeeping (void)
|
||||
/* first expire the actual data */
|
||||
for (r=thecache; r; r = r->next)
|
||||
{
|
||||
if (r->pw && r->accessed + r->ttl < current)
|
||||
if (!r->lockcount && r->pw && r->accessed + r->ttl < current)
|
||||
{
|
||||
if (DBG_CACHE)
|
||||
log_debug (" expired `%s' (%ds after last access)\n",
|
||||
@ -99,10 +100,10 @@ housekeeping (void)
|
||||
}
|
||||
|
||||
/* second, make sure that we also remove them based on the created stamp so
|
||||
that the used has to enter it from time to time. We do this every hour */
|
||||
that the user has to enter it from time to time. We do this every hour */
|
||||
for (r=thecache; r; r = r->next)
|
||||
{
|
||||
if (r->pw && r->created + 60*60 < current)
|
||||
if (!r->lockcount && r->pw && r->created + 60*60 < current)
|
||||
{
|
||||
if (DBG_CACHE)
|
||||
log_debug (" expired `%s' (1h after creation)\n", r->key);
|
||||
@ -117,6 +118,17 @@ housekeeping (void)
|
||||
for (rprev=NULL, r=thecache; r; )
|
||||
{
|
||||
if (!r->pw && r->accessed + 60*30 < current)
|
||||
{
|
||||
if (r->lockcount)
|
||||
{
|
||||
log_error ("can't remove unused cache entry `%s' due to"
|
||||
" lockcount=%d\n",
|
||||
r->key, r->lockcount);
|
||||
r->accessed += 60*10; /* next error message in 10 minutes */
|
||||
rprev = r;
|
||||
r = r->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
ITEM r2 = r->next;
|
||||
if (DBG_CACHE)
|
||||
@ -128,6 +140,7 @@ housekeeping (void)
|
||||
rprev->next = r2;
|
||||
r = r2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rprev = r;
|
||||
@ -158,7 +171,7 @@ agent_put_cache (const char *key, const char *data, int ttl)
|
||||
|
||||
for (r=thecache; r; r = r->next)
|
||||
{
|
||||
if ( !strcmp (r->key, key))
|
||||
if (!r->lockcount && !strcmp (r->key, key))
|
||||
break;
|
||||
}
|
||||
if (r)
|
||||
@ -206,34 +219,67 @@ agent_put_cache (const char *key, const char *data, int ttl)
|
||||
|
||||
/* Try to find an item in the cache */
|
||||
const char *
|
||||
agent_get_cache (const char *key)
|
||||
agent_get_cache (const char *key, void **cache_id)
|
||||
{
|
||||
ITEM r;
|
||||
int count = 0;
|
||||
|
||||
if (DBG_CACHE)
|
||||
log_debug ("agent_get_cache `%s'...\n", key);
|
||||
housekeeping ();
|
||||
|
||||
/* FIXME: Returning pointers is not thread safe - add a reference
|
||||
counter */
|
||||
for (r=thecache; r; r = r->next, count++)
|
||||
/* first try to find one with no locks - this is an updated cache
|
||||
entry: We might have entries with a lockcount and without a
|
||||
lockcount. */
|
||||
for (r=thecache; r; r = r->next)
|
||||
{
|
||||
if (r->pw && !strcmp (r->key, key))
|
||||
if (!r->lockcount && r->pw && !strcmp (r->key, key))
|
||||
{
|
||||
/* put_cache does only put strings into the cache, so we
|
||||
don't need the lengths */
|
||||
r->accessed = gnupg_get_time ();
|
||||
if (DBG_CACHE)
|
||||
log_debug ("... hit\n");
|
||||
r->lockcount++;
|
||||
*cache_id = r;
|
||||
return r->pw->data;
|
||||
}
|
||||
}
|
||||
/* again, but this time get even one with a lockcount set */
|
||||
for (r=thecache; r; r = r->next)
|
||||
{
|
||||
if (r->pw && !strcmp (r->key, key))
|
||||
{
|
||||
r->accessed = gnupg_get_time ();
|
||||
if (DBG_CACHE)
|
||||
log_debug ("... hit (locked)\n");
|
||||
r->lockcount++;
|
||||
*cache_id = r;
|
||||
return r->pw->data;
|
||||
}
|
||||
}
|
||||
if (DBG_CACHE)
|
||||
log_debug ("... miss\n");
|
||||
|
||||
*cache_id = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
agent_unlock_cache_entry (void **cache_id)
|
||||
{
|
||||
ITEM r;
|
||||
|
||||
for (r=thecache; r; r = r->next)
|
||||
{
|
||||
if (r == *cache_id)
|
||||
{
|
||||
if (!r->lockcount)
|
||||
log_error ("trying to unlock non-locked cache entry `%s'\n",
|
||||
r->key);
|
||||
else
|
||||
r->lockcount--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,12 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* Fixme: For now we have serialized all access to the scdaemon which
|
||||
make sense becuase the scdaemon can't handle concurrent connections
|
||||
right now. We should however keep a list of connections and lock
|
||||
just that connection - it migth make sense to implemtn parts of
|
||||
this in Assuan.*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@ -27,6 +33,9 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef USE_GNU_PTH
|
||||
# include <pth.h>
|
||||
#endif
|
||||
|
||||
#include "agent.h"
|
||||
#include "../assuan/assuan.h"
|
||||
@ -38,6 +47,9 @@
|
||||
#endif
|
||||
|
||||
static ASSUAN_CONTEXT scd_ctx = NULL;
|
||||
#ifdef USE_GNU_PTH
|
||||
static pth_mutex_t scd_lock = PTH_MUTEX_INIT;
|
||||
#endif
|
||||
|
||||
/* callback parameter for learn card */
|
||||
struct learn_parm_s {
|
||||
@ -60,7 +72,7 @@ struct membuf {
|
||||
|
||||
|
||||
|
||||
/* A simple implemnation of a dynamic buffer. Use init_membuf() to
|
||||
/* A simple implementation of a dynamic buffer. Use init_membuf() to
|
||||
create a buffer, put_membuf to append bytes and get_membuf to
|
||||
release and return the buffer. Allocation errors are detected but
|
||||
only returned at the final get_membuf(), this helps not to clutter
|
||||
@ -122,6 +134,20 @@ get_membuf (struct membuf *mb, size_t *len)
|
||||
|
||||
|
||||
|
||||
static int
|
||||
unlock_scd (int rc)
|
||||
{
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_release (&scd_lock))
|
||||
{
|
||||
log_error ("failed to release the SCD lock\n");
|
||||
if (!rc)
|
||||
rc = GNUPG_Internal_Error;
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Fork off the SCdaemon if this has not already been done */
|
||||
static int
|
||||
start_scd (void)
|
||||
@ -131,6 +157,14 @@ start_scd (void)
|
||||
ASSUAN_CONTEXT ctx;
|
||||
const char *argv[3];
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_acquire (&scd_lock, 0, NULL))
|
||||
{
|
||||
log_error ("failed to acquire the SCD lock\n");
|
||||
return GNUPG_Internal_Error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (scd_ctx)
|
||||
return 0; /* No need to serialize things because the agent is
|
||||
expected to tun as a single-thread (or may be in
|
||||
@ -142,7 +176,7 @@ start_scd (void)
|
||||
if (fflush (NULL))
|
||||
{
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return seterr (Write_Error);
|
||||
return unlock_scd (seterr (Write_Error));
|
||||
}
|
||||
|
||||
/* FIXME: change the default location of the program */
|
||||
@ -163,7 +197,7 @@ start_scd (void)
|
||||
{
|
||||
log_error ("can't connect to the SCdaemon: %s\n",
|
||||
assuan_strerror (rc));
|
||||
return seterr (No_Scdaemon);
|
||||
return unlock_scd (seterr (No_Scdaemon));
|
||||
}
|
||||
scd_ctx = ctx;
|
||||
|
||||
@ -218,9 +252,9 @@ agent_card_learn (void (*kpinfo_cb)(void*, const char *), void *kpinfo_cb_arg)
|
||||
NULL, NULL, NULL, NULL,
|
||||
learn_status_cb, &parm);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
|
||||
return 0;
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
|
||||
@ -274,7 +308,7 @@ agent_card_serialno (char **r_serialno)
|
||||
this is really SCdaemon's duty */
|
||||
rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
|
||||
rc = assuan_transact (scd_ctx, "SERIALNO",
|
||||
NULL, NULL, NULL, NULL,
|
||||
@ -282,10 +316,10 @@ agent_card_serialno (char **r_serialno)
|
||||
if (rc)
|
||||
{
|
||||
xfree (serialno);
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
}
|
||||
*r_serialno = serialno;
|
||||
return 0;
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
|
||||
@ -354,7 +388,7 @@ agent_card_pksign (const char *keyid,
|
||||
return rc;
|
||||
|
||||
if (indatalen*2 + 50 > DIM(line))
|
||||
return seterr (General_Error);
|
||||
return unlock_scd (seterr (General_Error));
|
||||
|
||||
sprintf (line, "SETDATA ");
|
||||
p = line + strlen (line);
|
||||
@ -362,7 +396,7 @@ agent_card_pksign (const char *keyid,
|
||||
sprintf (p, "%02X", indata[i]);
|
||||
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
|
||||
init_membuf (&data, 1024);
|
||||
inqparm.ctx = scd_ctx;
|
||||
@ -377,7 +411,7 @@ agent_card_pksign (const char *keyid,
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
}
|
||||
sigbuf = get_membuf (&data, &sigbuflen);
|
||||
|
||||
@ -388,7 +422,7 @@ agent_card_pksign (const char *keyid,
|
||||
if (!*r_buf)
|
||||
{
|
||||
xfree (*r_buf);
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_scd (GNUPG_Out_Of_Core);
|
||||
}
|
||||
p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" );
|
||||
sprintf (p, "%u:", (unsigned int)sigbuflen);
|
||||
@ -399,7 +433,7 @@ agent_card_pksign (const char *keyid,
|
||||
xfree (sigbuf);
|
||||
|
||||
assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
|
||||
return 0;
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
/* Decipher INDATA using the current card. Note that the returned value is */
|
||||
@ -423,7 +457,7 @@ agent_card_pkdecrypt (const char *keyid,
|
||||
|
||||
/* FIXME: use secure memory where appropriate */
|
||||
if (indatalen*2 + 50 > DIM(line))
|
||||
return seterr (General_Error);
|
||||
return unlock_scd (seterr (General_Error));
|
||||
|
||||
sprintf (line, "SETDATA ");
|
||||
p = line + strlen (line);
|
||||
@ -431,7 +465,7 @@ agent_card_pkdecrypt (const char *keyid,
|
||||
sprintf (p, "%02X", indata[i]);
|
||||
rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
|
||||
init_membuf (&data, 1024);
|
||||
inqparm.ctx = scd_ctx;
|
||||
@ -446,13 +480,13 @@ agent_card_pkdecrypt (const char *keyid,
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
}
|
||||
*r_buf = get_membuf (&data, r_buflen);
|
||||
if (!*r_buf)
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_scd (GNUPG_Out_Of_Core);
|
||||
|
||||
return 0;
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
|
||||
@ -481,13 +515,13 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
}
|
||||
*r_buf = get_membuf (&data, r_buflen);
|
||||
if (!*r_buf)
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_scd (GNUPG_Out_Of_Core);
|
||||
|
||||
return 0;
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
|
||||
@ -517,19 +551,19 @@ agent_card_readkey (const char *id, unsigned char **r_buf)
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
return unlock_scd (map_assuan_err (rc));
|
||||
}
|
||||
*r_buf = get_membuf (&data, &buflen);
|
||||
if (!*r_buf)
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_scd (GNUPG_Out_Of_Core);
|
||||
|
||||
if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
|
||||
{
|
||||
xfree (*r_buf); *r_buf = NULL;
|
||||
return GNUPG_Invalid_Value;
|
||||
return unlock_scd (GNUPG_Invalid_Value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -370,6 +370,7 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
|
||||
char *response;
|
||||
char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
|
||||
char *p;
|
||||
void *cache_marker;
|
||||
|
||||
/* parse the stuff */
|
||||
for (p=line; *p == ' '; p++)
|
||||
@ -417,17 +418,18 @@ cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
|
||||
desc = NULL;
|
||||
|
||||
/* Note: we store the hexified versions in the cache. */
|
||||
pw = cacheid ? agent_get_cache (cacheid) : NULL;
|
||||
pw = cacheid ? agent_get_cache (cacheid, &cache_marker) : NULL;
|
||||
if (pw)
|
||||
{
|
||||
assuan_begin_confidential (ctx);
|
||||
rc = assuan_set_okay_line (ctx, pw);
|
||||
agent_unlock_cache_entry (&cache_marker);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note, that we only need to repalce the + characters and
|
||||
should leave the other escaping in place becuase the escaped
|
||||
sting is send verbatim to the pinentry which does the
|
||||
/* Note, that we only need to replace the + characters and
|
||||
should leave the other escaping in place because the escaped
|
||||
string is send verbatim to the pinentry which does the
|
||||
unescaping (but not the + replacing) */
|
||||
if (errtext)
|
||||
plus_to_blank (errtext);
|
||||
@ -593,10 +595,10 @@ register_commands (ASSUAN_CONTEXT ctx)
|
||||
}
|
||||
|
||||
|
||||
/* Startup the server. If LISTEN_FD is given as -1, this is a simple
|
||||
/* Startup the server. If LISTEN_FD and FD is given as -1, this is a simple
|
||||
piper server, otherwise it is a regular server */
|
||||
void
|
||||
start_command_handler (int listen_fd)
|
||||
start_command_handler (int listen_fd, int fd)
|
||||
{
|
||||
int rc;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
@ -604,8 +606,7 @@ start_command_handler (int listen_fd)
|
||||
|
||||
memset (&ctrl, 0, sizeof ctrl);
|
||||
|
||||
|
||||
if (listen_fd == -1)
|
||||
if (listen_fd == -1 && fd == -1)
|
||||
{
|
||||
int filedes[2];
|
||||
|
||||
@ -613,10 +614,14 @@ start_command_handler (int listen_fd)
|
||||
filedes[1] = 1;
|
||||
rc = assuan_init_pipe_server (&ctx, filedes);
|
||||
}
|
||||
else
|
||||
else if (listen_fd != -1)
|
||||
{
|
||||
rc = assuan_init_socket_server (&ctx, listen_fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = assuan_init_connected_socket_server (&ctx, fd);
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to initialize the server: %s\n",
|
||||
@ -664,5 +669,3 @@ start_command_handler (int listen_fd)
|
||||
assuan_deinit_server (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -106,10 +106,12 @@ unprotect (unsigned char **keybuf, const unsigned char *grip)
|
||||
/* first try to get it from the cache - if there is none or we can't
|
||||
unprotect it, we fall back to ask the user */
|
||||
{
|
||||
const char *pw = agent_get_cache (hexgrip);
|
||||
void *cache_marker;
|
||||
const char *pw = agent_get_cache (hexgrip, &cache_marker);
|
||||
if (pw)
|
||||
{
|
||||
rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
|
||||
agent_unlock_cache_entry (&cache_marker);
|
||||
if (!rc)
|
||||
{
|
||||
xfree (*keybuf);
|
||||
|
@ -33,6 +33,9 @@
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef USE_GNU_PTH
|
||||
# include <pth.h>
|
||||
#endif
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
@ -113,7 +116,13 @@ static ARGPARSE_OPTS opts[] = {
|
||||
};
|
||||
|
||||
|
||||
#ifndef USE_GNU_PTH
|
||||
static volatile int caught_fatal_sig = 0;
|
||||
#endif /*!USE_GNU_PTH*/
|
||||
|
||||
/* flag to indicate that a shutdown was requested */
|
||||
static int shutdown_pending;
|
||||
|
||||
|
||||
/* It is possible that we are currently running under setuid permissions */
|
||||
static int maybe_setuid = 1;
|
||||
@ -122,6 +131,11 @@ static int maybe_setuid = 1;
|
||||
static char socket_name[128];
|
||||
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
static void handle_connections (int listen_fd);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static const char *
|
||||
my_strusage (int level)
|
||||
@ -205,6 +219,7 @@ cleanup (void)
|
||||
}
|
||||
|
||||
|
||||
#ifndef USE_GNU_PTH
|
||||
static RETSIGTYPE
|
||||
cleanup_sh (int sig)
|
||||
{
|
||||
@ -226,6 +241,7 @@ cleanup_sh (int sig)
|
||||
#endif
|
||||
raise( sig );
|
||||
}
|
||||
#endif /*!USE_GNU_PTH*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv )
|
||||
@ -265,6 +281,9 @@ main (int argc, char **argv )
|
||||
}
|
||||
|
||||
assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
|
||||
#ifdef USE_GNU_PTH
|
||||
assuan_set_io_func (pth_read, pth_write);
|
||||
#endif
|
||||
gcry_set_log_handler (my_gcry_logger, NULL);
|
||||
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
|
||||
@ -447,7 +466,7 @@ main (int argc, char **argv )
|
||||
|
||||
if (pipe_server)
|
||||
{ /* this is the simple pipe based server */
|
||||
start_command_handler (-1);
|
||||
start_command_handler (-1, -1);
|
||||
}
|
||||
else
|
||||
{ /* regular server mode */
|
||||
@ -574,6 +593,7 @@ main (int argc, char **argv )
|
||||
/*NEVER REACHED*/
|
||||
} /* end parent */
|
||||
|
||||
|
||||
/* this is the child */
|
||||
|
||||
/* detach from tty and put process into a new session */
|
||||
@ -592,6 +612,22 @@ main (int argc, char **argv )
|
||||
}
|
||||
}
|
||||
|
||||
if (chdir("/"))
|
||||
{
|
||||
log_error ("chdir to / failed: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_init ())
|
||||
{
|
||||
log_error ("failed to initialize the Pth library\n");
|
||||
exit (1);
|
||||
}
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
handle_connections (fd);
|
||||
#else /*!USE_GNU_PTH*/
|
||||
/* setup signals */
|
||||
{
|
||||
struct sigaction oact, nact;
|
||||
@ -610,15 +646,8 @@ main (int argc, char **argv )
|
||||
sigaction (SIGPIPE, &nact, NULL);
|
||||
sigaction (SIGINT, &nact, NULL);
|
||||
}
|
||||
|
||||
if (chdir("/"))
|
||||
{
|
||||
log_error ("chdir to / failed: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
start_command_handler (fd);
|
||||
|
||||
start_command_handler (fd, -1);
|
||||
#endif /*!USE_GNU_PTH*/
|
||||
close (fd);
|
||||
}
|
||||
|
||||
@ -628,10 +657,7 @@ main (int argc, char **argv )
|
||||
void
|
||||
agent_exit (int rc)
|
||||
{
|
||||
#if 0
|
||||
#warning no update_random_seed_file
|
||||
update_random_seed_file();
|
||||
#endif
|
||||
/*FIXME: update_random_seed_file();*/
|
||||
#if 0
|
||||
/* at this time a bit annoying */
|
||||
if (opt.debug & DBG_MEMSTAT_VALUE)
|
||||
@ -647,3 +673,144 @@ agent_exit (int rc)
|
||||
exit (rc);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
reread_configuration (void)
|
||||
{
|
||||
/* FIXME: Move parts of the option parsing to here. */
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
static void
|
||||
handle_signal (int signo)
|
||||
{
|
||||
switch (signo)
|
||||
{
|
||||
case SIGHUP:
|
||||
log_info ("SIGHUP received - re-reading configuration\n");
|
||||
reread_configuration ();
|
||||
break;
|
||||
|
||||
case SIGUSR1:
|
||||
if (opt.verbose < 5)
|
||||
opt.verbose++;
|
||||
log_info ("SIGUSR1 received - verbosity set to %d\n", opt.verbose);
|
||||
break;
|
||||
|
||||
case SIGUSR2:
|
||||
if (opt.verbose)
|
||||
opt.verbose--;
|
||||
log_info ("SIGUSR2 received - verbosity set to %d\n", opt.verbose );
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
if (!shutdown_pending)
|
||||
log_info ("SIGTERM received - shutting down ...\n");
|
||||
else
|
||||
log_info ("SIGTERM received - still %ld running threads\n",
|
||||
pth_ctrl( PTH_CTRL_GETTHREADS ));
|
||||
shutdown_pending++;
|
||||
if (shutdown_pending > 2)
|
||||
{
|
||||
log_info ("shutdown forced\n");
|
||||
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
|
||||
cleanup ();
|
||||
agent_exit (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGINT:
|
||||
log_info ("SIGINT received - immediate shutdown\n");
|
||||
log_info( "%s %s stopped\n", strusage(11), strusage(13));
|
||||
cleanup ();
|
||||
agent_exit (0);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_info ("signal %d received - no action defined\n", signo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
start_connection_thread (void *arg)
|
||||
{
|
||||
int fd = (int)arg;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("handler for fd %d started\n", fd);
|
||||
start_command_handler (-1, fd);
|
||||
if (opt.verbose)
|
||||
log_info ("handler for fd %d terminated\n", fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handle_connections (int listen_fd)
|
||||
{
|
||||
pth_attr_t tattr;
|
||||
pth_event_t ev;
|
||||
sigset_t sigs;
|
||||
int signo;
|
||||
struct sockaddr_un paddr;
|
||||
socklen_t plen = sizeof( paddr );
|
||||
int fd;
|
||||
|
||||
tattr = pth_attr_new();
|
||||
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
|
||||
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
|
||||
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
|
||||
|
||||
sigemptyset (&sigs );
|
||||
sigaddset (&sigs, SIGHUP);
|
||||
sigaddset (&sigs, SIGUSR1);
|
||||
sigaddset (&sigs, SIGUSR2);
|
||||
sigaddset (&sigs, SIGINT);
|
||||
sigaddset (&sigs, SIGTERM);
|
||||
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (shutdown_pending)
|
||||
{
|
||||
if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
|
||||
break; /* ready */
|
||||
|
||||
/* Do not accept anymore connections and wait for existing
|
||||
connections to terminate */
|
||||
signo = 0;
|
||||
pth_wait (ev);
|
||||
if (pth_event_occurred (ev) && signo)
|
||||
handle_signal (signo);
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
|
||||
if (fd == -1)
|
||||
{
|
||||
if (pth_event_occurred (ev))
|
||||
{
|
||||
handle_signal (signo);
|
||||
continue;
|
||||
}
|
||||
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
|
||||
pth_sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
|
||||
{
|
||||
log_error ("error spawning connection handler: %s\n",
|
||||
strerror (errno) );
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
|
||||
pth_event_free (ev, PTH_FREE_ALL);
|
||||
cleanup ();
|
||||
log_info ("%s %s stopped\n", strusage(11), strusage(13));
|
||||
}
|
||||
#endif /*USE_GNU_PTH*/
|
||||
|
@ -27,6 +27,9 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef USE_GNU_PTH
|
||||
# include <pth.h>
|
||||
#endif
|
||||
|
||||
#include "agent.h"
|
||||
#include "../assuan/assuan.h"
|
||||
@ -38,6 +41,9 @@
|
||||
#endif
|
||||
|
||||
static ASSUAN_CONTEXT entry_ctx = NULL;
|
||||
#ifdef USE_GNU_PTH
|
||||
static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
|
||||
#endif
|
||||
|
||||
/* data to be passed to our callbacks */
|
||||
struct entry_parm_s {
|
||||
@ -49,7 +55,24 @@ struct entry_parm_s {
|
||||
|
||||
|
||||
|
||||
/* Fork off the pin entry if this has not already been done */
|
||||
static int
|
||||
unlock_pinentry (int rc)
|
||||
{
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_release (&entry_lock))
|
||||
{
|
||||
log_error ("failed to release the entry lock\n");
|
||||
if (!rc)
|
||||
rc = GNUPG_Internal_Error;
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Fork off the pin entry if this has not already been done. Note,
|
||||
that this function must always be used to aquire the lock for the
|
||||
pinentry - we will serialize _all_ pinentry calls.
|
||||
*/
|
||||
static int
|
||||
start_pinentry (void)
|
||||
{
|
||||
@ -58,10 +81,16 @@ start_pinentry (void)
|
||||
ASSUAN_CONTEXT ctx;
|
||||
const char *argv[5];
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_acquire (&entry_lock, 0, NULL))
|
||||
{
|
||||
log_error ("failed to acquire the entry lock\n");
|
||||
return GNUPG_Internal_Error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (entry_ctx)
|
||||
return 0; /* No need to serialize things becuase the agent is
|
||||
expected to tun as a single-thread (or may be in
|
||||
future using libpth) */
|
||||
return 0;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("no running PIN Entry - starting it\n");
|
||||
@ -69,7 +98,7 @@ start_pinentry (void)
|
||||
if (fflush (NULL))
|
||||
{
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return seterr (Write_Error);
|
||||
return unlock_pinentry (seterr (Write_Error));
|
||||
}
|
||||
|
||||
/* FIXME: change the default location of the program */
|
||||
@ -80,6 +109,7 @@ start_pinentry (void)
|
||||
else
|
||||
pgmname++;
|
||||
|
||||
/* FIXME: We must do this thread specific */
|
||||
argv[0] = pgmname;
|
||||
if (opt.display)
|
||||
{
|
||||
@ -96,7 +126,7 @@ start_pinentry (void)
|
||||
{
|
||||
log_error ("can't connect to the PIN entry module: %s\n",
|
||||
assuan_strerror (rc));
|
||||
return seterr (No_PIN_Entry);
|
||||
return unlock_pinentry (seterr (No_PIN_Entry));
|
||||
}
|
||||
entry_ctx = ctx;
|
||||
|
||||
@ -107,47 +137,47 @@ start_pinentry (void)
|
||||
opt.no_grab? "OPTION no-grab":"OPTION grab",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
if (opt.ttyname)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 )
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_pinentry (GNUPG_Out_Of_Core);
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (opt.ttytype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 )
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_pinentry (GNUPG_Out_Of_Core);
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (opt.lc_ctype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 )
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_pinentry (GNUPG_Out_Of_Core);
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (opt.lc_messages)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 )
|
||||
return GNUPG_Out_Of_Core;
|
||||
return unlock_pinentry (GNUPG_Out_Of_Core);
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -213,14 +243,14 @@ agent_askpin (const char *desc_text, const char *start_err_text,
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
rc = assuan_transact (entry_ctx,
|
||||
pininfo->min_digits? "SETPROMPT PIN:"
|
||||
: "SETPROMPT Passphrase:",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
|
||||
{
|
||||
@ -242,7 +272,7 @@ agent_askpin (const char *desc_text, const char *start_err_text,
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
errtext = NULL;
|
||||
}
|
||||
|
||||
@ -251,9 +281,9 @@ agent_askpin (const char *desc_text, const char *start_err_text,
|
||||
errtext = pininfo->min_digits? trans ("PIN too long")
|
||||
: trans ("Passphrase too long");
|
||||
else if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
if (!errtext && !pininfo->min_digits)
|
||||
return 0; /* okay, got a passphrase */
|
||||
return unlock_pinentry (0); /* okay, got a passphrase */
|
||||
if (!errtext && !all_digitsp (pininfo->pin))
|
||||
errtext = trans ("Invalid characters in PIN");
|
||||
if (!errtext && pininfo->max_digits
|
||||
@ -264,10 +294,11 @@ agent_askpin (const char *desc_text, const char *start_err_text,
|
||||
errtext = trans ("PIN too short");
|
||||
|
||||
if (!errtext)
|
||||
return 0; /* okay, got a PIN */
|
||||
return unlock_pinentry (0); /* okay, got a PIN */
|
||||
}
|
||||
|
||||
return pininfo->min_digits? GNUPG_Bad_PIN : GNUPG_Bad_Passphrase;
|
||||
return unlock_pinentry (pininfo->min_digits? GNUPG_Bad_PIN
|
||||
: GNUPG_Bad_Passphrase);
|
||||
}
|
||||
|
||||
|
||||
@ -301,13 +332,13 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
if (errtext)
|
||||
{
|
||||
@ -315,28 +346,28 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = ASSUAN_LINELENGTH/2 - 5;
|
||||
parm.buffer = gcry_malloc_secure (parm.size+10);
|
||||
if (!parm.buffer)
|
||||
return seterr (Out_Of_Core);
|
||||
return unlock_pinentry (seterr (Out_Of_Core));
|
||||
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
xfree (parm.buffer);
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
|
||||
if (!hexstring)
|
||||
{
|
||||
xfree (parm.buffer);
|
||||
return seterr (Out_Of_Core);
|
||||
return unlock_pinentry (seterr (Out_Of_Core));
|
||||
}
|
||||
|
||||
for (i=0, p=parm.buffer; *p; p++, i += 2)
|
||||
@ -344,7 +375,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
|
||||
|
||||
xfree (parm.buffer);
|
||||
*retpass = hexstring;
|
||||
return 0;
|
||||
return unlock_pinentry (0);
|
||||
}
|
||||
|
||||
|
||||
@ -370,7 +401,7 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
if (ok)
|
||||
{
|
||||
@ -378,7 +409,7 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (cancel)
|
||||
{
|
||||
@ -386,11 +417,11 @@ agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return map_assuan_err (rc);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2002-05-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* no-pth.c, Makefile.am: Removed.
|
||||
|
||||
2002-05-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* mkdtemp.c: Replaced byte by unsigned char because it is no longer
|
||||
|
@ -32,7 +32,6 @@ libcommon_a_SOURCES = \
|
||||
errors.c errors.h \
|
||||
maperror.c \
|
||||
sysutils.c sysutils.h \
|
||||
no-pth.c \
|
||||
cryptmiss.c \
|
||||
gettime.c
|
||||
|
||||
|
@ -1,54 +0,0 @@
|
||||
/* no-pth.c - stubs to avoid linking against PTH
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#ifdef USE_GNU_PTH /*we need the stubs only in this case */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pth.h>
|
||||
|
||||
#if PTH_SYSCALL_SOFT
|
||||
# error this file cannot be used with PTH syscall divertion
|
||||
#endif
|
||||
|
||||
|
||||
ssize_t
|
||||
pth_read (int a, void *b , size_t c)
|
||||
{
|
||||
return read (a, b, c);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
pth_write (int a, const void *b, size_t c)
|
||||
{
|
||||
return write (a, b, c);
|
||||
}
|
||||
|
||||
int
|
||||
pth_accept (int a, struct sockaddr *b, socklen_t *c)
|
||||
{
|
||||
return accept (a, b, c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /*USE_GNU_PTH*/
|
Loading…
x
Reference in New Issue
Block a user