2009-10-14 19:06:10 +02:00
|
|
|
|
/* server.c - The G13 Assuan server
|
|
|
|
|
* Copyright (C) 2009 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#include "g13.h"
|
|
|
|
|
#include <assuan.h>
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
#include "keyblob.h"
|
2009-10-19 11:18:46 +02:00
|
|
|
|
#include "server.h"
|
|
|
|
|
#include "mount.h"
|
|
|
|
|
#include "create.h"
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
|
|
|
|
|
/* The filepointer for status message used in non-server mode */
|
|
|
|
|
static FILE *statusfp;
|
|
|
|
|
|
2009-10-14 19:06:10 +02:00
|
|
|
|
/* Local data for this server module. A pointer to this is stored in
|
|
|
|
|
the CTRL object of each connection. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
struct server_local_s
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
/* The Assuan contect we are working on. */
|
|
|
|
|
assuan_context_t assuan_ctx;
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
char *containername; /* Malloced active containername. */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
strlist_t recipients; /* List of recipients. */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Local prototypes. */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
static int command_has_option (const char *cmd, const char *cmdopt);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/*
|
2011-02-04 12:57:53 +01:00
|
|
|
|
Helper functions.
|
2009-10-15 19:20:41 +02:00
|
|
|
|
*/
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Set an error and a description. */
|
|
|
|
|
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Skip over options. Blanks after the options are also removed. */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
static char *
|
|
|
|
|
skip_options (const char *line)
|
|
|
|
|
{
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
while ( *line == '-' && line[1] == '-' )
|
|
|
|
|
{
|
|
|
|
|
while (*line && !spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
while (spacep (line))
|
|
|
|
|
line++;
|
|
|
|
|
}
|
|
|
|
|
return (char*)line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check whether the option NAME appears in LINE. */
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* static int */
|
|
|
|
|
/* has_option (const char *line, const char *name) */
|
|
|
|
|
/* { */
|
|
|
|
|
/* const char *s; */
|
|
|
|
|
/* int n = strlen (name); */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* s = strstr (line, name); */
|
|
|
|
|
/* if (s && s >= skip_options (line)) */
|
|
|
|
|
/* return 0; */
|
|
|
|
|
/* return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
|
|
|
|
|
/* } */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Helper to print a message while leaving a command. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
leave_cmd (assuan_context_t ctx, gpg_error_t err)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
2009-10-15 19:20:41 +02:00
|
|
|
|
if (err)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
2009-10-15 19:20:41 +02:00
|
|
|
|
const char *name = assuan_get_command_name (ctx);
|
|
|
|
|
if (!name)
|
|
|
|
|
name = "?";
|
|
|
|
|
if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
|
|
|
|
|
log_error ("command '%s' failed: %s\n", name,
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
else
|
|
|
|
|
log_error ("command '%s' failed: %s <%s>\n", name,
|
|
|
|
|
gpg_strerror (err), gpg_strsource (err));
|
2009-10-14 19:06:10 +02:00
|
|
|
|
}
|
2009-10-15 19:20:41 +02:00
|
|
|
|
return err;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
2009-10-14 19:06:10 +02:00
|
|
|
|
/* The handler for Assuan OPTION commands. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
option_handler (assuan_context_t ctx, const char *key, const char *value)
|
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
(void)ctrl;
|
|
|
|
|
|
2009-10-14 19:06:10 +02:00
|
|
|
|
if (!strcmp (key, "putenv"))
|
|
|
|
|
{
|
|
|
|
|
/* Change the session's environment to be used for the
|
|
|
|
|
Pinentry. Valid values are:
|
|
|
|
|
<NAME> Delete envvar NAME
|
|
|
|
|
<KEY>= Set envvar NAME to the empty string
|
|
|
|
|
<KEY>=<VALUE> Set envvar NAME to VALUE
|
|
|
|
|
*/
|
|
|
|
|
err = session_env_putenv (opt.session_env, value);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "display"))
|
|
|
|
|
{
|
|
|
|
|
err = session_env_setenv (opt.session_env, "DISPLAY", value);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "ttyname"))
|
|
|
|
|
{
|
|
|
|
|
err = session_env_setenv (opt.session_env, "GPG_TTY", value);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "ttytype"))
|
|
|
|
|
{
|
|
|
|
|
err = session_env_setenv (opt.session_env, "TERM", value);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "lc-ctype"))
|
|
|
|
|
{
|
|
|
|
|
xfree (opt.lc_ctype);
|
|
|
|
|
opt.lc_ctype = xtrystrdup (value);
|
|
|
|
|
if (!opt.lc_ctype)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "lc-messages"))
|
|
|
|
|
{
|
|
|
|
|
xfree (opt.lc_messages);
|
|
|
|
|
opt.lc_messages = xtrystrdup (value);
|
|
|
|
|
if (!opt.lc_messages)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "xauthority"))
|
|
|
|
|
{
|
|
|
|
|
err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "pinentry-user-data"))
|
|
|
|
|
{
|
|
|
|
|
err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "allow-pinentry-notify"))
|
|
|
|
|
{
|
|
|
|
|
; /* We always allow it. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The handler for an Assuan RESET command. */
|
agent/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
common/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* get-passphrase.c (default_inq_cb, membuf_data_cb): Change return
type to gpg_error_t.
g10/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
scd/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
sm/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
* call-agent.c (membuf_data_cb, default_inq_cb)
(inq_ciphertext_cb, scd_serialno_status_cb)
(scd_keypairinfo_status_cb, istrusted_status_cb)
(learn_status_cb, learn_cb, keyinfo_status_cb): Return gpg_error_t.
2009-11-02 18:47:11 +01:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
reset_notify (assuan_context_t ctx, char *line)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
|
agent/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
common/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* get-passphrase.c (default_inq_cb, membuf_data_cb): Change return
type to gpg_error_t.
g10/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
scd/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
sm/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
* call-agent.c (membuf_data_cb, default_inq_cb)
(inq_ciphertext_cb, scd_serialno_status_cb)
(scd_keypairinfo_status_cb, istrusted_status_cb)
(learn_status_cb, learn_cb, keyinfo_status_cb): Return gpg_error_t.
2009-11-02 18:47:11 +01:00
|
|
|
|
(void)line;
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
xfree (ctrl->server_local->containername);
|
|
|
|
|
ctrl->server_local->containername = NULL;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
FREE_STRLIST (ctrl->server_local->recipients);
|
|
|
|
|
|
2009-10-14 19:06:10 +02:00
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
agent/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
common/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* get-passphrase.c (default_inq_cb, membuf_data_cb): Change return
type to gpg_error_t.
g10/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
scd/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
sm/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
* call-agent.c (membuf_data_cb, default_inq_cb)
(inq_ciphertext_cb, scd_serialno_status_cb)
(scd_keypairinfo_status_cb, istrusted_status_cb)
(learn_status_cb, learn_cb, keyinfo_status_cb): Return gpg_error_t.
2009-11-02 18:47:11 +01:00
|
|
|
|
return 0;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static const char hlp_open[] =
|
2009-11-04 11:06:38 +01:00
|
|
|
|
"OPEN [<options>] <filename>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Open the container FILENAME. FILENAME must be percent-plus\n"
|
|
|
|
|
"escaped. A quick check to see whether this is a suitable G13\n"
|
|
|
|
|
"container file is done. However no cryptographic check or any\n"
|
|
|
|
|
"other check is done. This command is used to define the target for\n"
|
|
|
|
|
"further commands. The filename is reset with the RESET command,\n"
|
|
|
|
|
"another OPEN or the CREATE command.";
|
2009-10-14 19:06:10 +02:00
|
|
|
|
static gpg_error_t
|
2009-10-15 19:20:41 +02:00
|
|
|
|
cmd_open (assuan_context_t ctx, char *line)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
2009-10-15 19:20:41 +02:00
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
char *p, *pend;
|
|
|
|
|
size_t len;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* In any case reset the active container. */
|
|
|
|
|
xfree (ctrl->server_local->containername);
|
|
|
|
|
ctrl->server_local->containername = NULL;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Parse the line. */
|
|
|
|
|
line = skip_options (line);
|
|
|
|
|
for (p=line; *p && !spacep (p); p++)
|
|
|
|
|
;
|
|
|
|
|
pend = p;
|
|
|
|
|
while (spacep(p))
|
|
|
|
|
p++;
|
|
|
|
|
if (*p || pend == line)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_ASS_SYNTAX);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
*pend = 0;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Unescape the line and check for embedded Nul bytes. */
|
|
|
|
|
len = percent_plus_unescape_inplace (line, 0);
|
|
|
|
|
line[len] = 0;
|
|
|
|
|
if (!len || memchr (line, 0, len))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Do a basic check. */
|
|
|
|
|
err = g13_is_container (ctrl, line);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
/* Store the filename. */
|
|
|
|
|
ctrl->server_local->containername = xtrystrdup (line);
|
|
|
|
|
if (!ctrl->server_local->containername)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
leave:
|
2009-10-14 19:06:10 +02:00
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static const char hlp_mount[] =
|
2009-11-04 12:57:26 +01:00
|
|
|
|
"MOUNT [options] [<mountpoint>]\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Mount the currently open file onto MOUNTPOINT. If MOUNTPOINT is not\n"
|
|
|
|
|
"given the system picks an unused mountpoint. MOUNTPOINT must\n"
|
|
|
|
|
"be percent-plus escaped to allow for arbitrary names.";
|
2009-10-14 19:06:10 +02:00
|
|
|
|
static gpg_error_t
|
2009-10-15 19:20:41 +02:00
|
|
|
|
cmd_mount (assuan_context_t ctx, char *line)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
char *p, *pend;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
line = skip_options (line);
|
|
|
|
|
for (p=line; *p && !spacep (p); p++)
|
|
|
|
|
;
|
|
|
|
|
pend = p;
|
|
|
|
|
while (spacep(p))
|
|
|
|
|
p++;
|
|
|
|
|
if (*p)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_ASS_SYNTAX);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
*pend = 0;
|
|
|
|
|
|
|
|
|
|
/* Unescape the line and check for embedded Nul bytes. */
|
|
|
|
|
len = percent_plus_unescape_inplace (line, 0);
|
|
|
|
|
line[len] = 0;
|
|
|
|
|
if (memchr (line, 0, len))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
if (!ctrl->server_local->containername)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
2009-10-15 19:20:41 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_MISSING_ACTION);
|
|
|
|
|
goto leave;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-10-15 19:20:41 +02:00
|
|
|
|
/* Perform the mount. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
err = g13_mount_container (ctrl, ctrl->server_local->containername,
|
2009-10-15 19:20:41 +02:00
|
|
|
|
*line? line : NULL);
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static const char hlp_umount[] =
|
2009-11-04 12:57:26 +01:00
|
|
|
|
"UMOUNT [options] [<mountpoint>]\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Unmount the currently open file or the one opened at MOUNTPOINT.\n"
|
|
|
|
|
"MOUNTPOINT must be percent-plus escaped. On success the mountpoint\n"
|
|
|
|
|
"is returned via a \"MOUNTPOINT\" status line.";
|
2009-10-14 19:06:10 +02:00
|
|
|
|
static gpg_error_t
|
2009-10-15 19:20:41 +02:00
|
|
|
|
cmd_umount (assuan_context_t ctx, char *line)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
char *p, *pend;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
line = skip_options (line);
|
|
|
|
|
for (p=line; *p && !spacep (p); p++)
|
|
|
|
|
;
|
|
|
|
|
pend = p;
|
|
|
|
|
while (spacep(p))
|
|
|
|
|
p++;
|
2009-10-15 19:20:41 +02:00
|
|
|
|
if (*p)
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_ASS_SYNTAX);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
*pend = 0;
|
|
|
|
|
|
|
|
|
|
/* Unescape the line and check for embedded Nul bytes. */
|
|
|
|
|
len = percent_plus_unescape_inplace (line, 0);
|
|
|
|
|
line[len] = 0;
|
2009-10-15 19:20:41 +02:00
|
|
|
|
if (memchr (line, 0, len))
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
|
|
|
|
/* Perform the unmount. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
err = g13_umount_container (ctrl, ctrl->server_local->containername,
|
2009-10-15 19:20:41 +02:00
|
|
|
|
*line? line : NULL);
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static const char hlp_recipient[] =
|
2009-11-04 12:57:26 +01:00
|
|
|
|
"RECIPIENT <userID>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Add USERID to the list of recipients to be used for the next CREATE\n"
|
|
|
|
|
"command. All recipient commands are cumulative until a RESET or an\n"
|
|
|
|
|
"successful create command.";
|
2009-10-15 19:20:41 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
cmd_recipient (assuan_context_t ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
2009-10-19 11:18:46 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
line = skip_options (line);
|
|
|
|
|
|
|
|
|
|
if (!add_to_strlist_try (&ctrl->server_local->recipients, line))
|
|
|
|
|
err = gpg_error_from_syserror ();
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-11-04 12:57:26 +01:00
|
|
|
|
static const char hlp_signer[] =
|
|
|
|
|
"SIGNER <userID>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Not yet implemented.";
|
2009-10-15 19:20:41 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
cmd_signer (assuan_context_t ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
|
|
|
|
(void)ctrl;
|
2009-10-19 11:18:46 +02:00
|
|
|
|
(void)line;
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-11-04 12:57:26 +01:00
|
|
|
|
static const char hlp_create[] =
|
|
|
|
|
"CREATE [options] <filename>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Create a new container. On success the OPEN command is \n"
|
|
|
|
|
"implictly done for the new container.";
|
2009-10-15 19:20:41 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
cmd_create (assuan_context_t ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
gpg_error_t err;
|
2009-10-19 11:18:46 +02:00
|
|
|
|
char *p, *pend;
|
|
|
|
|
size_t len;
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
|
|
|
|
/* First we close the active container. */
|
|
|
|
|
xfree (ctrl->server_local->containername);
|
|
|
|
|
ctrl->server_local->containername = NULL;
|
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
/* Parse the line. */
|
|
|
|
|
line = skip_options (line);
|
|
|
|
|
for (p=line; *p && !spacep (p); p++)
|
|
|
|
|
;
|
|
|
|
|
pend = p;
|
|
|
|
|
while (spacep(p))
|
|
|
|
|
p++;
|
|
|
|
|
if (*p || pend == line)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_ASS_SYNTAX);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
*pend = 0;
|
|
|
|
|
|
|
|
|
|
/* Unescape the line and check for embedded Nul bytes. */
|
|
|
|
|
len = percent_plus_unescape_inplace (line, 0);
|
|
|
|
|
line[len] = 0;
|
|
|
|
|
if (!len || memchr (line, 0, len))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
/* Create container. */
|
|
|
|
|
err = g13_create_container (ctrl, line, ctrl->server_local->recipients);
|
2009-10-15 19:20:41 +02:00
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
FREE_STRLIST (ctrl->server_local->recipients);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-10-19 11:18:46 +02:00
|
|
|
|
/* Store the filename. */
|
|
|
|
|
ctrl->server_local->containername = xtrystrdup (line);
|
|
|
|
|
if (!ctrl->server_local->containername)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
leave:
|
2009-10-15 19:20:41 +02:00
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static const char hlp_getinfo[] =
|
2009-11-04 12:57:26 +01:00
|
|
|
|
"GETINFO <what>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Multipurpose function to return a variety of information.\n"
|
|
|
|
|
"Supported values for WHAT are:\n"
|
|
|
|
|
"\n"
|
|
|
|
|
" version - Return the version of the program.\n"
|
|
|
|
|
" pid - Return the process id of the server.\n"
|
|
|
|
|
" cmd_has_option CMD OPT\n"
|
|
|
|
|
" - Return OK if the command CMD implements the option OPT.";
|
2009-10-14 19:06:10 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
cmd_getinfo (assuan_context_t ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
|
|
|
|
|
if (!strcmp (line, "version"))
|
|
|
|
|
{
|
|
|
|
|
const char *s = PACKAGE_VERSION;
|
|
|
|
|
err = assuan_send_data (ctx, s, strlen (s));
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (line, "pid"))
|
|
|
|
|
{
|
|
|
|
|
char numbuf[50];
|
|
|
|
|
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
|
|
|
|
|
err = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
|
|
|
|
}
|
|
|
|
|
else if (!strncmp (line, "cmd_has_option", 14)
|
|
|
|
|
&& (line[14] == ' ' || line[14] == '\t' || !line[14]))
|
|
|
|
|
{
|
|
|
|
|
char *cmd, *cmdopt;
|
|
|
|
|
line += 14;
|
|
|
|
|
while (*line == ' ' || *line == '\t')
|
|
|
|
|
line++;
|
|
|
|
|
if (!*line)
|
|
|
|
|
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cmd = line;
|
|
|
|
|
while (*line && (*line != ' ' && *line != '\t'))
|
|
|
|
|
line++;
|
|
|
|
|
if (!*line)
|
|
|
|
|
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*line++ = 0;
|
|
|
|
|
while (*line == ' ' || *line == '\t')
|
|
|
|
|
line++;
|
|
|
|
|
if (!*line)
|
|
|
|
|
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cmdopt = line;
|
|
|
|
|
if (!command_has_option (cmd, cmdopt))
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
|
|
|
|
|
|
|
|
|
return leave_cmd (ctx, err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return true if the command CMD implements the option CMDOPT. */
|
|
|
|
|
static int
|
|
|
|
|
command_has_option (const char *cmd, const char *cmdopt)
|
|
|
|
|
{
|
|
|
|
|
(void)cmd;
|
|
|
|
|
(void)cmdopt;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-10-14 19:06:10 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Tell the Assuan library about our commands. */
|
|
|
|
|
static int
|
|
|
|
|
register_commands (assuan_context_t ctx)
|
|
|
|
|
{
|
|
|
|
|
static struct {
|
|
|
|
|
const char *name;
|
agent/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
common/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* get-passphrase.c (default_inq_cb, membuf_data_cb): Change return
type to gpg_error_t.
g10/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
scd/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
sm/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
* call-agent.c (membuf_data_cb, default_inq_cb)
(inq_ciphertext_cb, scd_serialno_status_cb)
(scd_keypairinfo_status_cb, istrusted_status_cb)
(learn_status_cb, learn_cb, keyinfo_status_cb): Return gpg_error_t.
2009-11-02 18:47:11 +01:00
|
|
|
|
assuan_handler_t handler;
|
2009-11-04 11:06:38 +01:00
|
|
|
|
const char * const help;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
} table[] = {
|
2009-11-04 12:57:26 +01:00
|
|
|
|
{ "OPEN", cmd_open, hlp_open },
|
|
|
|
|
{ "MOUNT", cmd_mount, hlp_mount},
|
|
|
|
|
{ "UMOUNT", cmd_umount, hlp_umount },
|
|
|
|
|
{ "RECIPIENT", cmd_recipient, hlp_recipient },
|
|
|
|
|
{ "SIGNER", cmd_signer, hlp_signer },
|
|
|
|
|
{ "CREATE", cmd_create, hlp_create },
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{ "INPUT", NULL },
|
|
|
|
|
{ "OUTPUT", NULL },
|
2009-11-04 12:57:26 +01:00
|
|
|
|
{ "GETINFO", cmd_getinfo,hlp_getinfo },
|
2009-10-14 19:06:10 +02:00
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; table[i].name; i++)
|
|
|
|
|
{
|
2009-11-04 11:06:38 +01:00
|
|
|
|
err = assuan_register_command (ctx, table[i].name, table[i].handler,
|
|
|
|
|
table[i].help);
|
2009-10-14 19:06:10 +02:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
}
|
2009-10-14 19:06:10 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Startup the server. DEFAULT_RECPLIST is the list of recipients as
|
|
|
|
|
set from the command line or config file. We only require those
|
|
|
|
|
marked as encrypt-to. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
g13_server (ctrl_t ctrl)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
2009-11-25 18:58:26 +01:00
|
|
|
|
assuan_fd_t filedes[2];
|
2009-10-14 19:06:10 +02:00
|
|
|
|
assuan_context_t ctx = NULL;
|
|
|
|
|
static const char hello[] = ("GNU Privacy Guard's G13 server "
|
|
|
|
|
PACKAGE_VERSION " ready");
|
|
|
|
|
|
|
|
|
|
/* We use a pipe based server so that we can work from scripts.
|
|
|
|
|
assuan_init_pipe_server will automagically detect when we are
|
|
|
|
|
called with a socketpair and ignore FIELDES in this case. */
|
2009-11-25 18:58:26 +01:00
|
|
|
|
filedes[0] = assuan_fdopen (0);
|
|
|
|
|
filedes[1] = assuan_fdopen (1);
|
2009-10-14 19:06:10 +02:00
|
|
|
|
err = assuan_new (&ctx);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to allocate an Assuan context: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = assuan_init_pipe_server (ctx, filedes);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to initialize the server: %s\n", gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = register_commands (ctx);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to the register commands with Assuan: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assuan_set_pointer (ctx, ctrl);
|
|
|
|
|
|
|
|
|
|
if (opt.verbose || opt.debug)
|
|
|
|
|
{
|
|
|
|
|
char *tmp = NULL;
|
|
|
|
|
const char *s1 = getenv ("GPG_AGENT_INFO");
|
|
|
|
|
|
|
|
|
|
tmp = xtryasprintf ("Home: %s\n"
|
|
|
|
|
"Config: %s\n"
|
|
|
|
|
"AgentInfo: %s\n"
|
|
|
|
|
"%s",
|
|
|
|
|
opt.homedir,
|
|
|
|
|
opt.config_filename,
|
|
|
|
|
s1?s1:"[not set]",
|
|
|
|
|
hello);
|
|
|
|
|
if (tmp)
|
|
|
|
|
{
|
|
|
|
|
assuan_set_hello_line (ctx, tmp);
|
|
|
|
|
xfree (tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
assuan_set_hello_line (ctx, hello);
|
|
|
|
|
|
|
|
|
|
assuan_register_reset_notify (ctx, reset_notify);
|
|
|
|
|
assuan_register_option_handler (ctx, option_handler);
|
|
|
|
|
|
|
|
|
|
ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
|
|
|
|
|
if (!ctrl->server_local)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
ctrl->server_local->assuan_ctx = ctx;
|
|
|
|
|
|
|
|
|
|
while ( !(err = assuan_accept (ctx)) )
|
|
|
|
|
{
|
|
|
|
|
err = assuan_process (ctx);
|
|
|
|
|
if (err)
|
|
|
|
|
log_info ("Assuan processing failed: %s\n", gpg_strerror (err));
|
|
|
|
|
}
|
|
|
|
|
if (err == -1)
|
|
|
|
|
err = 0;
|
|
|
|
|
else
|
|
|
|
|
log_info ("Assuan accept problem: %s\n", gpg_strerror (err));
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-10-14 19:06:10 +02:00
|
|
|
|
leave:
|
agent/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
common/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* get-passphrase.c (default_inq_cb, membuf_data_cb): Change return
type to gpg_error_t.
g10/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
scd/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* command.c (reset_notify): Take LINE arg and return error.
(register_commands): Use assuan_handler_t type.
sm/
2009-11-02 Marcus Brinkmann <marcus@g10code.de>
* server.c (reset_notify, input_notify, output_notify): Update to
new assuan interface.
(register_commands): Use assuan_handler_t.
* call-agent.c (membuf_data_cb, default_inq_cb)
(inq_ciphertext_cb, scd_serialno_status_cb)
(scd_keypairinfo_status_cb, istrusted_status_cb)
(learn_status_cb, learn_cb, keyinfo_status_cb): Return gpg_error_t.
2009-11-02 18:47:11 +01:00
|
|
|
|
reset_notify (ctx, NULL); /* Release all items hold by SERVER_LOCAL. */
|
2009-10-14 19:06:10 +02:00
|
|
|
|
if (ctrl->server_local)
|
|
|
|
|
{
|
|
|
|
|
xfree (ctrl->server_local);
|
|
|
|
|
ctrl->server_local = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assuan_release (ctx);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
/* Send a status line with status ID NO. The arguments are a list of
|
|
|
|
|
strings terminated by a NULL argument. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
g13_status (ctrl_t ctrl, int no, ...)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
va_list arg_ptr;
|
|
|
|
|
const char *text;
|
|
|
|
|
|
|
|
|
|
va_start (arg_ptr, no);
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
if (ctrl->no_server && ctrl->status_fd == -1)
|
|
|
|
|
; /* No status wanted. */
|
|
|
|
|
else if (ctrl->no_server)
|
|
|
|
|
{
|
|
|
|
|
if (!statusfp)
|
|
|
|
|
{
|
|
|
|
|
if (ctrl->status_fd == 1)
|
|
|
|
|
statusfp = stdout;
|
|
|
|
|
else if (ctrl->status_fd == 2)
|
|
|
|
|
statusfp = stderr;
|
|
|
|
|
else
|
|
|
|
|
statusfp = fdopen (ctrl->status_fd, "w");
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
if (!statusfp)
|
|
|
|
|
{
|
|
|
|
|
log_fatal ("can't open fd %d for status output: %s\n",
|
|
|
|
|
ctrl->status_fd, strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
fputs ("[GNUPG:] ", statusfp);
|
|
|
|
|
fputs (get_status_string (no), statusfp);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
while ( (text = va_arg (arg_ptr, const char*) ))
|
|
|
|
|
{
|
|
|
|
|
putc ( ' ', statusfp );
|
|
|
|
|
for (; *text; text++)
|
|
|
|
|
{
|
|
|
|
|
if (*text == '\n')
|
|
|
|
|
fputs ( "\\n", statusfp );
|
|
|
|
|
else if (*text == '\r')
|
|
|
|
|
fputs ( "\\r", statusfp );
|
|
|
|
|
else
|
|
|
|
|
putc ( *(const byte *)text, statusfp );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
putc ('\n', statusfp);
|
|
|
|
|
fflush (statusfp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
assuan_context_t ctx = ctrl->server_local->assuan_ctx;
|
|
|
|
|
char buf[950], *p;
|
|
|
|
|
size_t n;
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
p = buf;
|
|
|
|
|
n = 0;
|
|
|
|
|
while ( (text = va_arg (arg_ptr, const char *)) )
|
|
|
|
|
{
|
|
|
|
|
if (n)
|
|
|
|
|
{
|
|
|
|
|
*p++ = ' ';
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
for ( ; *text && n < DIM (buf)-2; n++)
|
|
|
|
|
*p++ = *text++;
|
|
|
|
|
}
|
|
|
|
|
*p = 0;
|
|
|
|
|
err = assuan_write_status (ctx, get_status_string (no), buf);
|
|
|
|
|
}
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
2009-10-28 13:02:15 +01:00
|
|
|
|
va_end (arg_ptr);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2009-10-14 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper to notify the client about Pinentry events. Returns an gpg
|
|
|
|
|
error code. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
g13_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
|
|
|
|
|
{
|
|
|
|
|
if (!ctrl || !ctrl->server_local)
|
|
|
|
|
return 0;
|
|
|
|
|
return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
|
|
|
|
|
}
|