#endif
#include <npth.h>
-#define JNLIB_NEED_LOG_LOGV
-#define JNLIB_NEED_AFLOCAL
+#define GNUPG_COMMON_NEED_AFLOCAL
#include "agent.h"
#include <assuan.h> /* Malloc hooks and socket wrappers. */
oDebugLevel,
oDebugWait,
oDebugQuickRandom,
+ oDebugPinentry,
oNoGreeting,
oNoOptions,
oHomedir,
oPinentryProgram,
oPinentryTouchFile,
+ oPinentryInvisibleChar,
oDisplay,
oTTYname,
oTTYtype,
oUseStandardSocket,
oNoUseStandardSocket,
oExtraSocket,
+ oBrowserSocket,
oFakedSystemTime,
oIgnoreCacheForSigning,
oNoAllowMarkTrusted,
oAllowPresetPassphrase,
oAllowLoopbackPinentry,
+ oNoAllowExternalCache,
+ oAllowEmacsPinentry,
oKeepTTY,
oKeepDISPLAY,
oSSHSupport,
ARGPARSE_s_n (oCsh, "csh", N_("csh-style command output")),
ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
- ARGPARSE_s_u (oDebug, "debug", "@"),
+ ARGPARSE_s_s (oDebug, "debug", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
ARGPARSE_s_i (oDebugWait," debug-wait", "@"),
ARGPARSE_s_n (oDebugQuickRandom, "debug-quick-random", "@"),
+ ARGPARSE_s_n (oDebugPinentry, "debug-pinentry", "@"),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_n (oNoGrab, "no-grab", N_("do not grab keyboard and mouse")),
ARGPARSE_s_s (oPinentryProgram, "pinentry-program",
/* */ N_("|PGM|use PGM as the PIN-Entry program")),
ARGPARSE_s_s (oPinentryTouchFile, "pinentry-touch-file", "@"),
+ ARGPARSE_s_s (oPinentryInvisibleChar, "pinentry-invisible-char", "@"),
ARGPARSE_s_s (oScdaemonProgram, "scdaemon-program",
/* */ N_("|PGM|use PGM as the SCdaemon program") ),
ARGPARSE_s_n (oDisableScdaemon, "disable-scdaemon",
/* */ N_("do not use the SCdaemon") ),
ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"),
+
+ ARGPARSE_s_s (oExtraSocket, "extra-socket",
+ /* */ N_("|NAME|accept some commands via NAME")),
+
+ ARGPARSE_s_s (oBrowserSocket, "browser-socket", "@"),
+
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
ARGPARSE_s_n (oBatch, "batch", "@"),
ARGPARSE_s_n (oIgnoreCacheForSigning, "ignore-cache-for-signing",
/* */ N_("do not use the PIN cache when signing")),
+ ARGPARSE_s_n (oNoAllowExternalCache, "no-allow-external-cache",
+ /* */ N_("disallow the use of an external password cache")),
ARGPARSE_s_n (oNoAllowMarkTrusted, "no-allow-mark-trusted",
/* */ N_("disallow clients to mark keys as \"trusted\"")),
ARGPARSE_s_n (oAllowMarkTrusted, "allow-mark-trusted", "@"),
/* */ N_("allow presetting passphrase")),
ARGPARSE_s_n (oAllowLoopbackPinentry, "allow-loopback-pinentry",
N_("allow caller to override the pinentry")),
+ ARGPARSE_s_n (oAllowEmacsPinentry, "allow-emacs-pinentry",
+ /* */ N_("allow passphrase to be prompted through Emacs")),
+
ARGPARSE_s_n (oSSHSupport, "enable-ssh-support", N_("enable ssh support")),
ARGPARSE_s_n (oPuttySupport, "enable-putty-support",
#ifdef HAVE_W32_SYSTEM
/* */ "@"
#endif
),
- ARGPARSE_s_s (oExtraSocket, "extra-socket", "@"),
/* Dummy options for backward compatibility. */
ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"),
};
+/* The list of supported debug flags. */
+static struct debug_flags_s debug_flags [] =
+ {
+ { DBG_COMMAND_VALUE, "command" },
+ { DBG_MPI_VALUE , "mpi" },
+ { DBG_CRYPTO_VALUE , "crypto" },
+ { DBG_MEMORY_VALUE , "memory" },
+ { DBG_CACHE_VALUE , "cache" },
+ { DBG_MEMSTAT_VALUE, "memstat" },
+ { DBG_HASHING_VALUE, "hashing" },
+ { DBG_IPC_VALUE , "ipc" },
+ { 77, NULL } /* 77 := Do not exit on "help" or "?". */
+ };
+
+
+
#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */
#define DEFAULT_CACHE_TTL_SSH (30*60) /* 30 minutes */
#define MAX_CACHE_TTL (120*60) /* 2 hours */
#endif
+/* Flag indicating that the ssh-agent subsystem has been enabled. */
+static int ssh_support;
+
#ifdef HAVE_W32_SYSTEM
/* Flag indicating that support for Putty has been enabled. */
static int putty_support;
static char *socket_name_extra;
static char *redir_socket_name_extra;
+/* Name of the optional browser socket used for native gpg-agent requests. */
+static char *socket_name_browser;
+static char *redir_socket_name_browser;
+
/* Name of the communication socket used for ssh-agent-emulation. */
static char *socket_name_ssh;
static char *redir_socket_name_ssh;
POSIX systems). */
static assuan_sock_nonce_t socket_nonce;
static assuan_sock_nonce_t socket_nonce_extra;
+static assuan_sock_nonce_t socket_nonce_browser;
static assuan_sock_nonce_t socket_nonce_ssh;
*/
static char *create_socket_name (char *standard_name, int with_homedir);
-static gnupg_fd_t create_server_socket (char *name, int primary,
+static gnupg_fd_t create_server_socket (char *name, int primary, int cygwin,
char **r_redir_name,
assuan_sock_nonce_t *nonce);
static void create_directories (void);
static void handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_extra,
+ gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh);
static void check_own_socket (void);
static int check_for_running_agent (int silent);
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
if (opt.debug)
- log_info ("enabled debug flags:%s%s%s%s%s%s%s%s\n",
- (opt.debug & DBG_COMMAND_VALUE)? " command":"",
- (opt.debug & DBG_MPI_VALUE )? " mpi":"",
- (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
- (opt.debug & DBG_MEMORY_VALUE )? " memory":"",
- (opt.debug & DBG_CACHE_VALUE )? " cache":"",
- (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
- (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
- (opt.debug & DBG_IPC_VALUE )? " ipc":"");
+ parse_debug_flag (NULL, &opt.debug, debug_flags);
}
remove_socket (socket_name, redir_socket_name);
if (opt.extra_socket > 1)
remove_socket (socket_name_extra, redir_socket_name_extra);
+ if (opt.browser_socket > 1)
+ remove_socket (socket_name_browser, redir_socket_name_browser);
remove_socket (socket_name_ssh, redir_socket_name_ssh);
}
opt.verbose = 0;
opt.debug = 0;
opt.no_grab = 0;
+ opt.debug_pinentry = 0;
opt.pinentry_program = NULL;
opt.pinentry_touch_file = NULL;
+ xfree (opt.pinentry_invisible_char);
+ opt.pinentry_invisible_char = NULL;
opt.scdaemon_program = NULL;
opt.def_cache_ttl = DEFAULT_CACHE_TTL;
opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
opt.enable_passhrase_history = 0;
opt.ignore_cache_for_signing = 0;
opt.allow_mark_trusted = 1;
+ opt.allow_external_cache = 1;
+ opt.allow_emacs_pinentry = 0;
opt.disable_scdaemon = 0;
disable_check_own_socket = 0;
return 1;
case oQuiet: opt.quiet = 1; break;
case oVerbose: opt.verbose++; break;
- case oDebug: opt.debug |= pargs->r.ret_ulong; break;
+ case oDebug:
+ parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags);
+ break;
case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs->r.ret_str; break;
+ case oDebugPinentry: opt.debug_pinentry = 1; break;
case oLogFile:
if (!reread)
case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
+ case oPinentryInvisibleChar:
+ xfree (opt.pinentry_invisible_char);
+ opt.pinentry_invisible_char = xtrystrdup (pargs->r.ret_str); break;
+ break;
case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
case oDisableScdaemon: opt.disable_scdaemon = 1; break;
case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
case oAllowLoopbackPinentry: opt.allow_loopback_pinentry = 1; break;
+ case oNoAllowExternalCache: opt.allow_external_cache = 0;
+ break;
+
+ case oAllowEmacsPinentry: opt.allow_emacs_pinentry = 1;
+ break;
+
default:
return 0; /* not handled */
}
static void
finalize_rereadable_options (void)
{
- /* It would be too surprising if the max-cache-ttl is lower than the
- default-cache-ttl - thus we silently correct that. */
- if (opt.def_cache_ttl > opt.max_cache_ttl)
- opt.max_cache_ttl = opt.def_cache_ttl;
- if (opt.def_cache_ttl_ssh > opt.max_cache_ttl_ssh)
- opt.max_cache_ttl_ssh = opt.def_cache_ttl_ssh;
}
/* Please note that we may running SUID(ROOT), so be very CAREFUL
when adding any stuff between here and the call to INIT_SECMEM()
somewhere after the option parsing */
- log_set_prefix (GPG_AGENT_NAME, JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID);
+ log_set_prefix (GPG_AGENT_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_WITH_PID);
/* Make sure that our subsystems are ready. */
i18n_init ();
case oXauthority: default_xauthority = xstrdup (pargs.r.ret_str);
break;
- case oUseStandardSocket: /* dummy */ break;
- case oNoUseStandardSocket: /* dummy */ break;
+ case oUseStandardSocket:
+ case oNoUseStandardSocket:
+ obsolete_option (configname, configlineno, "use-standard-socket");
+ break;
case oFakedSystemTime:
{
case oKeepTTY: opt.keep_tty = 1; break;
case oKeepDISPLAY: opt.keep_display = 1; break;
- case oSSHSupport: opt.ssh_support = 1; break;
+ case oSSHSupport:
+ ssh_support = 1;
+ break;
case oPuttySupport:
# ifdef HAVE_W32_SYSTEM
putty_support = 1;
- opt.ssh_support = 1;
# endif
break;
socket_name_extra = pargs.r.ret_str;
break;
+ case oBrowserSocket:
+ opt.browser_socket = 1; /* (1 = points into argv) */
+ socket_name_browser = pargs.r.ret_str;
+ break;
+
case oDebugQuickRandom:
/* Only used by the first stage command line parser. */
break;
- case oWriteEnvFile: /* dummy */ break;
+ case oWriteEnvFile:
+ obsolete_option (configname, configlineno, "write-env-file");
+ break;
default : pargs.err = configfp? 1:2; break;
}
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("ignore-cache-for-signing:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+ es_printf ("no-allow-external-cache:%lu:\n",
+ GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("no-allow-mark-trusted:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
es_printf ("disable-scdaemon:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+ es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
#ifdef HAVE_W32_SYSTEM
es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
-#else
- es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
#endif
es_printf ("allow-loopback-pinentry:%lu:\n",
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+ es_printf ("allow-emacs-pinentry:%lu:\n",
+ GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
agent_exit (0);
}
if (logfile)
{
log_set_file (logfile);
- log_set_prefix (NULL, (JNLIB_LOG_WITH_PREFIX
- |JNLIB_LOG_WITH_TIME
- |JNLIB_LOG_WITH_PID));
+ log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
+ | GPGRT_LOG_WITH_TIME
+ | GPGRT_LOG_WITH_PID));
current_logfile = xstrdup (logfile);
}
{ /* Regular server mode */
gnupg_fd_t fd;
gnupg_fd_t fd_extra = GNUPG_INVALID_FD;
+ gnupg_fd_t fd_browser = GNUPG_INVALID_FD;
gnupg_fd_t fd_ssh = GNUPG_INVALID_FD;
pid_t pid;
gnupg_unsetenv ("DISPLAY");
#endif
+ /* Remove the INSIDE_EMACS variable so that a pinentry does not
+ always try to interact with Emacs. The variable is set when
+ a client requested this using an OPTION command. */
+ gnupg_unsetenv ("INSIDE_EMACS");
+
/* Create the sockets. */
socket_name = create_socket_name (GPG_AGENT_SOCK_NAME, 1);
- fd = create_server_socket (socket_name, 1,
+ fd = create_server_socket (socket_name, 1, 0,
&redir_socket_name, &socket_nonce);
if (opt.extra_socket)
{
socket_name_extra = create_socket_name (socket_name_extra, 0);
opt.extra_socket = 2; /* Indicate that it has been malloced. */
- fd_extra = create_server_socket (socket_name_extra, 0,
+ fd_extra = create_server_socket (socket_name_extra, 0, 0,
&redir_socket_name_extra,
&socket_nonce_extra);
}
- if (opt.ssh_support)
+ if (opt.browser_socket)
+ {
+ socket_name_browser = create_socket_name (socket_name_browser, 0);
+ opt.browser_socket = 2; /* Indicate that it has been malloced. */
+ fd_browser = create_server_socket (socket_name_browser, 0, 0,
+ &redir_socket_name_browser,
+ &socket_nonce_browser);
+ }
+
+ if (ssh_support)
{
socket_name_ssh = create_socket_name (GPG_AGENT_SSH_SOCK_NAME, 1);
- fd_ssh = create_server_socket (socket_name_ssh, 0,
+ fd_ssh = create_server_socket (socket_name_ssh, 0, 1,
&redir_socket_name_ssh,
&socket_nonce_ssh);
}
#endif /*HAVE_SIGPROCMASK*/
/* Create the SSH info string if enabled. */
- if (opt.ssh_support)
+ if (ssh_support)
{
if (asprintf (&infostr_ssh_sock, "SSH_AUTH_SOCK=%s",
socket_name_ssh) < 0)
the child should do this from now on */
if (opt.extra_socket)
*socket_name_extra = 0;
- if (opt.ssh_support)
+ if (opt.browser_socket)
+ *socket_name_browser = 0;
+ if (ssh_support)
*socket_name_ssh = 0;
if (argc)
{ /* Run the program given on the commandline. */
- if (opt.ssh_support && (putenv (infostr_ssh_sock)
- || putenv (infostr_ssh_valid)))
+ if (ssh_support && (putenv (infostr_ssh_sock)
+ || putenv (infostr_ssh_valid)))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
shell's eval to set it */
if (csh_style)
{
- if (opt.ssh_support)
+ if (ssh_support)
{
*strchr (infostr_ssh_sock, '=') = ' ';
es_printf ("setenv %s;\n", infostr_ssh_sock);
}
else
{
- if (opt.ssh_support)
+ if (ssh_support)
{
es_printf ("%s; export SSH_AUTH_SOCK;\n",
infostr_ssh_sock);
}
}
- if (opt.ssh_support)
+ if (ssh_support)
{
xfree (infostr_ssh_sock);
xfree (infostr_ssh_valid);
}
log_get_prefix (&oldflags);
- log_set_prefix (NULL, oldflags | JNLIB_LOG_RUN_DETACHED);
+ log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
opt.running_detached = 1;
}
#endif /*!HAVE_W32_SYSTEM*/
log_info ("%s %s started\n", strusage(11), strusage(13) );
- handle_connections (fd, fd_extra, fd_ssh);
+ handle_connections (fd, fd_extra, fd_browser, fd_ssh);
assuan_sock_close (fd);
}
function needs to be used for the regular socket first (indicated
by PRIMARY) and only then for the extra and the ssh sockets. If
the socket has been redirected the name of the real socket is
- stored as a malloced string at R_REDIR_NAME. */
+ stored as a malloced string at R_REDIR_NAME. If CYGWIN is set a
+ Cygwin compatible socket is created (Windows only). */
static gnupg_fd_t
-create_server_socket (char *name, int primary,
+create_server_socket (char *name, int primary, int cygwin,
char **r_redir_name, assuan_sock_nonce_t *nonce)
{
struct sockaddr *addr;
agent_exit (2);
}
+#if ASSUAN_VERSION_NUMBER >= 0x020300 /* >= 2.3.0 */
+ if (cygwin)
+ assuan_sock_set_flag (fd, "cygwin", 1);
+#else
+ (void)cygwin;
+#endif
+
unaddr = xmalloc (sizeof *unaddr);
addr = (struct sockaddr*)unaddr;
server is not yet operational; this would lead to a hang. */
if (primary && !check_for_running_agent (1))
{
- log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX);
+ log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX);
log_set_file (NULL);
log_error (_("a gpg-agent is already running - "
"not starting a new one\n"));
static void *
-start_connection_thread (ctrl_t ctrl)
+do_start_connection_thread (ctrl_t ctrl)
{
- if (check_nonce (ctrl, &socket_nonce))
- {
- log_error ("handler 0x%lx nonce check FAILED\n",
- (unsigned long) npth_self());
- return NULL;
- }
-
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("handler 0x%lx for fd %d started\n"),
{
ctrl_t ctrl = arg;
- return start_connection_thread (ctrl);
+ if (check_nonce (ctrl, &socket_nonce))
+ {
+ log_error ("handler 0x%lx nonce check FAILED\n",
+ (unsigned long) npth_self());
+ return NULL;
+ }
+
+ return do_start_connection_thread (ctrl);
}
{
ctrl_t ctrl = arg;
+ if (check_nonce (ctrl, &socket_nonce_extra))
+ {
+ log_error ("handler 0x%lx nonce check FAILED\n",
+ (unsigned long) npth_self());
+ return NULL;
+ }
+
ctrl->restricted = 1;
- return start_connection_thread (ctrl);
+ return do_start_connection_thread (ctrl);
+}
+
+
+/* This is the browser socket connection thread's main function. */
+static void *
+start_connection_thread_browser (void *arg)
+{
+ ctrl_t ctrl = arg;
+
+ if (check_nonce (ctrl, &socket_nonce_browser))
+ {
+ log_error ("handler 0x%lx nonce check FAILED\n",
+ (unsigned long) npth_self());
+ return NULL;
+ }
+
+ ctrl->restricted = 2;
+ return do_start_connection_thread (ctrl);
}
static void
handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_extra,
+ gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh)
{
npth_attr_t tattr;
void *(*func) (void *arg);
gnupg_fd_t l_fd;
} listentbl[] = {
- { "std", start_connection_thread_std },
- { "extra",start_connection_thread_extra },
- { "ssh", start_connection_thread_ssh }
+ { "std", start_connection_thread_std },
+ { "extra", start_connection_thread_extra },
+ { "browser", start_connection_thread_browser },
+ { "ssh", start_connection_thread_ssh }
};
if (FD2INT (listen_fd_extra) > nfd)
nfd = FD2INT (listen_fd_extra);
}
+ if (listen_fd_browser != GNUPG_INVALID_FD)
+ {
+ FD_SET ( FD2INT(listen_fd_browser), &fdset);
+ if (FD2INT (listen_fd_browser) > nfd)
+ nfd = FD2INT (listen_fd_browser);
+ }
if (listen_fd_ssh != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_ssh), &fdset);
listentbl[0].l_fd = listen_fd;
listentbl[1].l_fd = listen_fd_extra;
- listentbl[2].l_fd = listen_fd_ssh;
+ listentbl[2].l_fd = listen_fd_browser;
+ listentbl[3].l_fd = listen_fd_ssh;
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;