diff --git a/kbx/backend-kbx.c b/kbx/backend-kbx.c
index 7f9ef358b..b8d39c2ed 100644
--- a/kbx/backend-kbx.c
+++ b/kbx/backend-kbx.c
@@ -1,292 +1,292 @@
/* backend-kbx.c - Keybox format backend for keyboxd
* Copyright (C) 2019 g10 Code GmbH
*
* 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 .
- * SPDX-License-Identifier: GPL-3.0+
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
#include
#include
#include
#include
#include
#include "keyboxd.h"
#include "../common/i18n.h"
#include "backend.h"
#include "keybox.h"
/* Our definition of the backend handle. */
struct backend_handle_s
{
enum database_types db_type; /* Always DB_TYPE_KBX. */
unsigned int backend_id; /* Id of this backend. */
void *token; /* Used to create a new KEYBOX_HANDLE. */
char filename[1];
};
/* Check that the file FILENAME is a valid keybox file which can be
* used here. Common return codes:
*
* 0 := Valid keybox file
* GPG_ERR_ENOENT := No such file
* GPG_ERR_NO_OBJ := File exists with size zero.
* GPG_ERR_INV_OBJ:= File exists but is not a keybox file.
*/
static gpg_error_t
check_kbx_file_magic (const char *filename)
{
gpg_error_t err;
u32 magic;
unsigned char verbuf[4];
estream_t fp;
fp = es_fopen (filename, "rb");
if (!fp)
return gpg_error_from_syserror ();
err = gpg_error (GPG_ERR_INV_OBJ);
if (es_fread (&magic, 4, 1, fp) == 1 )
{
if (es_fread (&verbuf, 4, 1, fp) == 1
&& verbuf[0] == 1
&& es_fread (&magic, 4, 1, fp) == 1
&& !memcmp (&magic, "KBXf", 4))
{
err = 0;
}
}
else /* Maybe empty: Let's create it. */
err = gpg_error (GPG_ERR_NO_OBJ);
es_fclose (fp);
return err;
}
/* Create new keybox file. This can also be used if the keybox
* already exists but has a length of zero. Do not use it in any
* other cases. */
static gpg_error_t
create_keybox (const char *filename)
{
gpg_error_t err;
dotlock_t lockhd = NULL;
estream_t fp;
/* To avoid races with other temporary instances of keyboxd trying
* to create or update the keybox, we do the next stuff in a locked
* state. */
lockhd = dotlock_create (filename, 0);
if (!lockhd)
{
err = gpg_error_from_syserror ();
/* A reason for this to fail is that the directory is not
* writable. However, this whole locking stuff does not make
* sense if this is the case. An empty non-writable directory
* with no keybox is not really useful at all. */
if (opt.verbose)
log_info ("can't allocate lock for '%s': %s\n",
filename, gpg_strerror (err));
return err;
}
if ( dotlock_take (lockhd, -1) )
{
err = gpg_error_from_syserror ();
/* This is something bad. Probably a stale lockfile. */
log_info ("can't lock '%s': %s\n", filename, gpg_strerror (err));
goto leave;
}
/* Make sure that at least one record is in a new keybox file, so
* that the detection magic will work the next time it is used.
* We always set the OpenPGP blobs maybe availabale flag. */
fp = es_fopen (filename, "w+b,mode=-rw-------");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error (_("error creating keybox '%s': %s\n"),
filename, gpg_strerror (err));
goto leave;
}
err = _keybox_write_header_blob (NULL, fp, 1);
es_fclose (fp);
if (err)
{
log_error (_("error creating keybox '%s': %s\n"),
filename, gpg_strerror (err));
goto leave;
}
if (!opt.quiet)
log_info (_("keybox '%s' created\n"), filename);
err = 0;
leave:
if (lockhd)
{
dotlock_release (lockhd);
dotlock_destroy (lockhd);
}
return err;
}
/* Install a new resource and return a handle for that backend. */
gpg_error_t
be_kbx_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
const char *filename, int readonly)
{
gpg_error_t err;
backend_handle_t hd;
void *token;
(void)ctrl;
*r_hd = NULL;
hd = xtrycalloc (1, sizeof *hd + strlen (filename));
if (!hd)
return gpg_error_from_syserror ();
hd->db_type = DB_TYPE_KBX;
strcpy (hd->filename, filename);
err = check_kbx_file_magic (filename);
switch (gpg_err_code (err))
{
case 0:
break;
case GPG_ERR_ENOENT:
case GPG_ERR_NO_OBJ:
if (readonly)
{
err = gpg_error (GPG_ERR_ENOENT);
goto leave;
}
err = create_keybox (filename);
if (err)
goto leave;
break;
default:
goto leave;
}
err = keybox_register_file (filename, 0, &token);
if (err)
goto leave;
hd->backend_id = be_new_backend_id ();
hd->token = token;
*r_hd = hd;
hd = NULL;
leave:
xfree (hd);
return 0;
}
/* Release the backend handle HD and all its resources. HD is not
* valid after a call to this function. */
void
be_kbx_release_resource (ctrl_t ctrl, backend_handle_t hd)
{
(void)ctrl;
if (!hd)
return;
hd->db_type = DB_TYPE_NONE;
xfree (hd);
}
void
be_kbx_release_kbx_hd (KEYBOX_HANDLE kbx_hd)
{
keybox_release (kbx_hd);
}
/* Search for the keys described by (DESC,NDESC) and return them to
* the caller. BACKEND_HD is the handle for this backend and REQUEST
* is the current database request object. */
gpg_error_t
be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc)
{
gpg_error_t err;
db_request_part_t part;
size_t descindex;
unsigned long skipped_long_blobs;
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
log_assert (request);
/* Find the specific request part or allocate it. */
for (part = request->part; part; part = part->next)
if (part->backend_id == backend_hd->backend_id)
break;
if (!part)
{
part = xtrycalloc (1, sizeof *part);
if (!part)
{
err = gpg_error_from_syserror ();
goto leave;
}
part->backend_id = backend_hd->backend_id;
part->kbx_hd = keybox_new_openpgp (backend_hd->token, 0);
if (!part->kbx_hd)
{
err = gpg_error_from_syserror ();
xfree (part);
goto leave;
}
part->next = request->part;
request->part = part;
}
if (!desc)
err = keybox_search_reset (part->kbx_hd);
else
err = keybox_search (part->kbx_hd, desc, ndesc, KEYBOX_BLOBTYPE_PGP,
&descindex, &skipped_long_blobs);
if (err == -1)
err = gpg_error (GPG_ERR_EOF);
if (desc && !err)
{
/* Successful search operation. */
void *buffer;
size_t buflen;
enum pubkey_types pubkey_type;
err = keybox_get_data (part->kbx_hd, &buffer, &buflen, &pubkey_type);
if (err)
goto leave;
/* Note: be_return_pubkey always takes ownership of BUFFER. */
err = be_return_pubkey (ctrl, buffer, buflen, pubkey_type);
}
leave:
return err;
}
diff --git a/kbx/kbxserver.c b/kbx/kbxserver.c
index 1f70ef779..a54444178 100644
--- a/kbx/kbxserver.c
+++ b/kbx/kbxserver.c
@@ -1,652 +1,664 @@
/* kbxserver.c - Handle Assuan commands send to the keyboxd
* Copyright (C) 2019 g10 Code GmbH
*
* 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 .
* SPDX-License-Identifier: GPL-3.0+
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "keyboxd.h"
#include
#include "../common/i18n.h"
#include "../common/server-help.h"
#include "../common/userids.h"
#include "../common/asshelp.h"
#include "frontend.h"
#define PARM_ERROR(t) assuan_set_error (ctx, \
gpg_error (GPG_ERR_ASS_PARAMETER), (t))
#define set_error(e,t) (ctx ? assuan_set_error (ctx, gpg_error (e), (t)) \
/**/: gpg_error (e))
/* Control structure per connection. */
struct server_local_s
{
/* Data used to associate an Assuan context with local server data */
assuan_context_t assuan_ctx;
/* The session id (a counter). */
unsigned int session_id;
/* If this flag is set to true this process will be terminated after
* the end of this session. */
int stopme;
/* If the first both flags are set the assuan logging of data lines
* is suppressed. The count variable is used to show the number of
* non-logged bytes. */
size_t inhibit_data_logging_count;
unsigned int inhibit_data_logging : 1;
unsigned int inhibit_data_logging_now : 1;
/* This flag is set if the last search command was called with --more. */
unsigned int search_expecting_more : 1;
/* This flag is set if the last search command was successful. */
unsigned int search_any_found : 1;
/* The first is the current search description as parsed by the
* cmd_search. If more than one pattern is required, cmd_search
* also allocates and sets multi_search_desc and
* multi_search_desc_len. If a search description has ever been
* allocated the allocated size is stored at
* multi_search_desc_size. */
KEYBOX_SEARCH_DESC search_desc;
KEYBOX_SEARCH_DESC *multi_search_desc;
unsigned int multi_search_desc_size;
unsigned int multi_search_desc_len;
};
/* Return the assuan contxt from the local server info in CTRL. */
static assuan_context_t
get_assuan_ctx_from_ctrl (ctrl_t ctrl)
{
if (!ctrl || !ctrl->server_local)
return NULL;
return ctrl->server_local->assuan_ctx;
}
/* A wrapper around assuan_send_data which makes debugging the output
* in verbose mode easier. It also takes CTRL as argument. */
gpg_error_t
kbxd_write_data_line (ctrl_t ctrl, const void *buffer_arg, size_t size)
{
const char *buffer = buffer_arg;
assuan_context_t ctx = get_assuan_ctx_from_ctrl (ctrl);
gpg_error_t err;
if (!ctx) /* Oops - no assuan context. */
return gpg_error (GPG_ERR_NOT_PROCESSED);
/* If we do not want logging, enable it here. */
if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
ctrl->server_local->inhibit_data_logging_now = 1;
if (opt.verbose && buffer && size)
{
/* Ease reading of output by limiting the line length. */
size_t n, nbytes;
nbytes = size;
do
{
n = nbytes > 64? 64 : nbytes;
err = assuan_send_data (ctx, buffer, n);
if (err)
{
gpg_err_set_errno (EIO);
goto leave;
}
buffer += n;
nbytes -= n;
if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
{
gpg_err_set_errno (EIO);
goto leave;
}
}
while (nbytes);
}
else
{
err = assuan_send_data (ctx, buffer, size);
if (err)
{
gpg_err_set_errno (EIO); /* For use by data_line_cookie_write. */
goto leave;
}
}
leave:
if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
{
ctrl->server_local->inhibit_data_logging_now = 0;
ctrl->server_local->inhibit_data_logging_count += size;
}
return err;
}
/* Helper to print a message while leaving a command. */
static gpg_error_t
leave_cmd (assuan_context_t ctx, gpg_error_t err)
{
if (err)
{
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));
}
return err;
}
/* Handle 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;
if (!strcmp (key, "lc-messages"))
{
if (ctrl->lc_messages)
xfree (ctrl->lc_messages);
ctrl->lc_messages = xtrystrdup (value);
if (!ctrl->lc_messages)
return out_of_core ();
}
else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
return err;
}
static const char hlp_search[] =
"SEARCH [--no-data] [[--more] PATTERN]\n"
"\n"
"Search for the keys identified by PATTERN. With --more more\n"
"patterns to be used for the search are expected with the next\n"
"command. With --no-data only the search status is returned but\n"
"not the actual data. See also \"NEXT\".";
static gpg_error_t
cmd_search (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int opt_more, opt_no_data;
gpg_error_t err;
unsigned int n, k;
opt_no_data = has_option (line, "--no-data");
opt_more = has_option (line, "--more");
line = skip_options (line);
ctrl->server_local->search_any_found = 0;
- if (!*line && opt_more)
+ if (!*line)
{
- err = set_error (GPG_ERR_INV_ARG, "--more but no pattern");
- goto leave;
+ if (opt_more)
+ {
+ err = set_error (GPG_ERR_INV_ARG, "--more but no pattern");
+ goto leave;
+ }
+ else if (!*line && ctrl->server_local->search_expecting_more)
+ {
+ /* It would be too surprising to first set a pattern but
+ * finally add no pattern to search the entire DB. */
+ err = set_error (GPG_ERR_INV_ARG, "--more pending but no pattern");
+ goto leave;
+ }
+ else /* No pattern - return the first item. */
+ {
+ memset (&ctrl->server_local->search_desc, 0,
+ sizeof ctrl->server_local->search_desc);
+ ctrl->server_local->search_desc.mode = KEYDB_SEARCH_MODE_FIRST;
+ }
}
- else if (!*line && ctrl->server_local->search_expecting_more)
+ else
{
- /* It would be too surprising to first set a pattern but finally
- * add no pattern to search the entire DB. */
- err = set_error (GPG_ERR_INV_ARG, "--more pending but no pattern");
- goto leave;
+ err = classify_user_id (line, &ctrl->server_local->search_desc, 0);
+ if (err)
+ goto leave;
}
- err = classify_user_id (line, &ctrl->server_local->search_desc, 0);
- if (err)
- goto leave;
if (opt_more || ctrl->server_local->search_expecting_more)
{
/* More pattern are expected - store the current one and return
* success. */
if (!ctrl->server_local->multi_search_desc_size)
{
n = 10;
ctrl->server_local->multi_search_desc
= xtrycalloc (n, sizeof *ctrl->server_local->multi_search_desc);
if (!ctrl->server_local->multi_search_desc)
{
err = gpg_error_from_syserror ();
goto leave;
}
ctrl->server_local->multi_search_desc_size = n;
}
if (ctrl->server_local->multi_search_desc_len
== ctrl->server_local->multi_search_desc_size)
{
KEYBOX_SEARCH_DESC *desc;
n = ctrl->server_local->multi_search_desc_size + 10;
desc = xtrycalloc (n, sizeof *desc);
if (!desc)
{
err = gpg_error_from_syserror ();
goto leave;
}
for (k=0; k < ctrl->server_local->multi_search_desc_size; k++)
desc[k] = ctrl->server_local->multi_search_desc[k];
xfree (ctrl->server_local->multi_search_desc);
ctrl->server_local->multi_search_desc = desc;
ctrl->server_local->multi_search_desc_size = n;
}
/* Actually store. */
ctrl->server_local->multi_search_desc
[ctrl->server_local->multi_search_desc_len++]
= ctrl->server_local->search_desc;
if (opt_more)
{
/* We need to be called aagain with more pattern. */
ctrl->server_local->search_expecting_more = 1;
goto leave;
}
ctrl->server_local->search_expecting_more = 0;
/* Continue with the actual search. */
}
else
ctrl->server_local->multi_search_desc_len = 0;
ctrl->no_data_return = opt_no_data;
if (ctrl->server_local->multi_search_desc_len)
err = kbxd_search (ctrl, ctrl->server_local->multi_search_desc,
ctrl->server_local->multi_search_desc_len, 1);
else
err = kbxd_search (ctrl, &ctrl->server_local->search_desc, 1, 1);
if (err)
goto leave;
/* Set a flag for use by NEXT. */
ctrl->server_local->search_any_found = 1;
leave:
if (err)
ctrl->server_local->multi_search_desc_len = 0;
ctrl->no_data_return = 0;
return leave_cmd (ctx, err);
}
static const char hlp_next[] =
"NEXT [--no-data]\n"
"\n"
"Get the next search result from a previus search.";
static gpg_error_t
cmd_next (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int opt_no_data;
gpg_error_t err;
opt_no_data = has_option (line, "--no-data");
line = skip_options (line);
if (*line)
{
err = set_error (GPG_ERR_INV_ARG, "no args expected");
goto leave;
}
if (!ctrl->server_local->search_any_found)
{
err = set_error (GPG_ERR_NOTHING_FOUND, "no previous SEARCH");
goto leave;
}
ctrl->no_data_return = opt_no_data;
if (ctrl->server_local->multi_search_desc_len)
err = kbxd_search (ctrl, ctrl->server_local->multi_search_desc,
ctrl->server_local->multi_search_desc_len, 0);
else
err = kbxd_search (ctrl, &ctrl->server_local->search_desc, 1, 0);
if (err)
goto leave;
leave:
ctrl->no_data_return = 0;
return leave_cmd (ctx, err);
}
static const char hlp_getinfo[] =
"GETINFO \n"
"\n"
"Multi purpose command to return certain information. \n"
"Supported values of WHAT are:\n"
"\n"
"version - Return the version of the program.\n"
"pid - Return the process id of the server.\n"
"socket_name - Return the name of the socket.\n"
"session_id - Return the current session_id.\n"
"getenv NAME - Return value of envvar NAME\n";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
char numbuf[50];
if (!strcmp (line, "version"))
{
const char *s = VERSION;
err = assuan_send_data (ctx, s, strlen (s));
}
else if (!strcmp (line, "pid"))
{
snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
err = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strcmp (line, "socket_name"))
{
const char *s = get_kbxd_socket_name ();
if (!s)
s = "[none]";
err = assuan_send_data (ctx, s, strlen (s));
}
else if (!strcmp (line, "session_id"))
{
snprintf (numbuf, sizeof numbuf, "%u", ctrl->server_local->session_id);
err = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strncmp (line, "getenv", 6)
&& (line[6] == ' ' || line[6] == '\t' || !line[6]))
{
line += 6;
while (*line == ' ' || *line == '\t')
line++;
if (!*line)
err = gpg_error (GPG_ERR_MISSING_VALUE);
else
{
const char *s = getenv (line);
if (!s)
err = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
else
err = assuan_send_data (ctx, s, strlen (s));
}
}
else
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
return leave_cmd (ctx, err);
}
static const char hlp_killkeyboxd[] =
"KILLKEYBOXD\n"
"\n"
"This command allows a user - given sufficient permissions -\n"
"to kill this keyboxd process.\n";
static gpg_error_t
cmd_killkeyboxd (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)line;
ctrl->server_local->stopme = 1;
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return gpg_error (GPG_ERR_EOF);
}
static const char hlp_reloadkeyboxd[] =
"RELOADKEYBOXD\n"
"\n"
"This command is an alternative to SIGHUP\n"
"to reload the configuration.";
static gpg_error_t
cmd_reloadkeyboxd (assuan_context_t ctx, char *line)
{
(void)ctx;
(void)line;
kbxd_sighup_action ();
return 0;
}
/* Tell the assuan library about our commands. */
static int
register_commands (assuan_context_t ctx)
{
static struct {
const char *name;
assuan_handler_t handler;
const char * const help;
} table[] = {
{ "SEARCH", cmd_search, hlp_search },
{ "NEXT", cmd_next, hlp_next },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
{ "RELOADKEYBOXD",cmd_reloadkeyboxd,hlp_reloadkeyboxd },
{ NULL, NULL }
};
int i, j, rc;
for (i=j=0; table[i].name; i++)
{
rc = assuan_register_command (ctx, table[i].name, table[i].handler,
table[i].help);
if (rc)
return rc;
}
return 0;
}
/* Note that we do not reset the list of configured keyservers. */
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)line;
(void)ctrl;
return 0;
}
/* This function is called by our assuan log handler to test whether a
* log message shall really be printed. The function must return
* false to inhibit the logging of MSG. CAT gives the requested log
* category. MSG might be NULL. */
int
kbxd_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
const char *msg)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)cat;
(void)msg;
if (!ctrl || !ctrl->server_local)
return 1; /* Can't decide - allow logging. */
if (!ctrl->server_local->inhibit_data_logging)
return 1; /* Not requested - allow logging. */
/* Disallow logging if *_now is true. */
return !ctrl->server_local->inhibit_data_logging_now;
}
/* Startup the server and run the main command loop. With FD = -1,
* use stdin/stdout. SESSION_ID is either 0 or a unique number
* identifying a session. */
void
kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
{
static const char hello[] = "Keyboxd " VERSION " at your service";
static char *hello_line;
int rc;
assuan_context_t ctx;
ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
if (!ctrl->server_local)
{
log_error (_("can't allocate control structure: %s\n"),
gpg_strerror (gpg_error_from_syserror ()));
xfree (ctrl);
return;
}
rc = assuan_new (&ctx);
if (rc)
{
log_error (_("failed to allocate assuan context: %s\n"),
gpg_strerror (rc));
kbxd_exit (2);
}
if (fd == GNUPG_INVALID_FD)
{
assuan_fd_t filedes[2];
filedes[0] = assuan_fdopen (0);
filedes[1] = assuan_fdopen (1);
rc = assuan_init_pipe_server (ctx, filedes);
}
else
{
rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
}
if (rc)
{
assuan_release (ctx);
log_error (_("failed to initialize the server: %s\n"),
gpg_strerror (rc));
kbxd_exit (2);
}
rc = register_commands (ctx);
if (rc)
{
log_error (_("failed to the register commands with Assuan: %s\n"),
gpg_strerror(rc));
kbxd_exit (2);
}
if (!hello_line)
{
hello_line = xtryasprintf
("Home: %s\n"
"Config: %s\n"
"%s",
gnupg_homedir (),
/*opt.config_filename? opt.config_filename :*/ "[none]",
hello);
}
ctrl->server_local->assuan_ctx = ctx;
assuan_set_pointer (ctx, ctrl);
assuan_set_hello_line (ctx, hello_line);
assuan_register_option_handler (ctx, option_handler);
assuan_register_reset_notify (ctx, reset_notify);
ctrl->server_local->session_id = session_id;
/* The next call enable the use of status_printf. */
set_assuan_context_func (get_assuan_ctx_from_ctrl);
for (;;)
{
rc = assuan_accept (ctx);
if (rc == -1)
break;
if (rc)
{
log_info (_("Assuan accept problem: %s\n"), gpg_strerror (rc));
break;
}
#ifndef HAVE_W32_SYSTEM
if (opt.verbose)
{
assuan_peercred_t peercred;
if (!assuan_get_peercred (ctx, &peercred))
log_info ("connection from process %ld (%ld:%ld)\n",
(long)peercred->pid, (long)peercred->uid,
(long)peercred->gid);
}
#endif
rc = assuan_process (ctx);
if (rc)
{
log_info (_("Assuan processing failed: %s\n"), gpg_strerror (rc));
continue;
}
}
set_assuan_context_func (NULL);
ctrl->server_local->assuan_ctx = NULL;
assuan_release (ctx);
if (ctrl->server_local->stopme)
kbxd_exit (0);
if (ctrl->refcount)
log_error ("oops: connection control structure still referenced (%d)\n",
ctrl->refcount);
else
{
xfree (ctrl->server_local->multi_search_desc);
xfree (ctrl->server_local);
ctrl->server_local = NULL;
}
}