Page MenuHome GnuPG

No OneTemporary

diff --git a/g13/ChangeLog b/g13/ChangeLog
index 1430297b2..5d74c7098 100644
--- a/g13/ChangeLog
+++ b/g13/ChangeLog
@@ -1,11 +1,3 @@
-2009-10-16 Marcus Brinkmann <marcus@g10code.com>
- * AM_CFLAGS, g13_LDADD: Use libassuan instead of libassuan-pth.
- * g13.c: Invoke ASSUAN_SYSTEM_PTH_IMPL.
- (main): Call assuan_set_system_hooks.
-
-2009-10-16 Marcus Brinkmann <marcus@g10code.com>
-
- * Makefile.am (AM_CFLAGS): Add $(KSBA_CFLAGS).
- (g13_LDADD): Add $(KSBA_LIBS).
+ Under initial development - no need for a ChangeLog.
diff --git a/g13/Makefile.am b/g13/Makefile.am
index cf25f6945..84004cb34 100644
--- a/g13/Makefile.am
+++ b/g13/Makefile.am
@@ -1,47 +1,46 @@
# g13/Makefile.am
# 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/>.
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = g13
AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
-AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) \
- $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
+AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
g13_SOURCES = \
g13.c g13.h \
keyblob.h \
utils.c utils.h \
server.c server.h \
create.c create.h \
mount.c mount.h \
mountinfo.c mountinfo.h \
call-gpg.c call-gpg.h \
runner.c runner.h \
backend.c backend.h \
be-encfs.c be-encfs.h \
be-truecrypt.c be-truecrypt.h
g13_LDADD = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a \
- $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL)
diff --git a/g13/call-gpg.c b/g13/call-gpg.c
index dd519021e..6e5c55f40 100644
--- a/g13/call-gpg.c
+++ b/g13/call-gpg.c
@@ -1,596 +1,590 @@
/* call-gpg.c - Communication with the GPG
* 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 <errno.h>
#include <time.h>
#include <assert.h>
#include <pth.h>
#include "g13.h"
#include <assuan.h>
#include "i18n.h"
#include "call-gpg.h"
#include "utils.h"
#include "../common/exechelp.h"
/* Fire up a new GPG. Handle the server's initial greeting. Returns
0 on success and stores the assuan context at R_CTX. */
static gpg_error_t
start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
{
gpg_error_t err;
assuan_context_t ctx = NULL;
const char *pgmname;
const char *argv[7];
int no_close_list[5];
int i;
char line[ASSUAN_LINELENGTH];
(void)ctrl;
*r_ctx = NULL;
err = assuan_new (&ctx);
if (err)
{
log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
return err;
}
/* The first time we are used, intialize the gpg_program variable. */
if ( !opt.gpg_program || !*opt.gpg_program )
opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
if (opt.verbose)
log_info (_("no running gpg - starting `%s'\n"), opt.gpg_program);
/* Compute argv[0]. */
if ( !(pgmname = strrchr (opt.gpg_program, '/')))
pgmname = opt.gpg_program;
else
pgmname++;
if (fflush (NULL))
{
err = gpg_error_from_syserror ();
log_error ("error flushing pending output: %s\n", gpg_strerror (err));
return err;
}
i = 0;
argv[i++] = pgmname;
argv[i++] = "--server";
if ((opt.debug & 1024))
argv[i++] = "--debug=1024";
argv[i++] = "-z";
argv[i++] = "0";
argv[i++] = NULL;
i = 0;
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
if (input_fd != -1)
no_close_list[i++] = input_fd;
if (output_fd != -1)
no_close_list[i++] = output_fd;
no_close_list[i] = -1;
/* Connect to GPG and perform initial handshaking. */
err = assuan_pipe_connect (ctx, opt.gpg_program, argv, no_close_list);
-
- /* if (!err) */
- /* err = assuan_transact (ctx, "OPTION audit-events=1", */
- /* NULL, NULL, NULL, NULL, NULL, NULL); */
- /* audit_log_ok (ctrl->audit, AUDIT_GPG_READY, err); */
-
if (err)
{
assuan_release (ctx);
log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
return gpg_error (GPG_ERR_NO_ENGINE);
}
if (input_fd != -1)
{
snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
assuan_release (ctx);
log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
return err;
}
}
if (output_fd != -1)
{
snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
assuan_release (ctx);
log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
return err;
}
}
*r_ctx = ctx;
if (DBG_ASSUAN)
log_debug ("connection to GPG established\n");
return 0;
}
/* Release the assuan context created by start_gpg. */
static void
release_gpg (assuan_context_t ctx)
{
assuan_release (ctx);
}
/* The data passed to the writer_thread. */
struct writer_thread_parms
{
int fd;
const void *data;
size_t datalen;
gpg_error_t *err_addr;
};
/* The thread started by start_writer. */
static void *
writer_thread (void *arg)
{
struct writer_thread_parms *parm = arg;
const char *buffer = parm->data;
size_t length = parm->datalen;
while (length)
{
ssize_t nwritten;
nwritten = pth_write (parm->fd, buffer, length < 4096? length:4096);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
*parm->err_addr = gpg_error_from_syserror ();
break; /* Write error. */
}
length -= nwritten;
buffer += nwritten;
}
if (close (parm->fd))
log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
xfree (parm);
return NULL;
}
/* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD.
On success the thread receives the ownership over FD. The thread
ID is stored at R_TID. WRITER_ERR is the address of an gpg_error_t
variable to receive a possible write error after the thread has
finished. */
static gpg_error_t
start_writer (int fd, const void *data, size_t datalen,
pth_t *r_tid, gpg_error_t *err_addr)
{
gpg_error_t err;
struct writer_thread_parms *parm;
pth_attr_t tattr;
pth_t tid;
*r_tid = NULL;
*err_addr = 0;
parm = xtrymalloc (sizeof *parm);
if (!parm)
return gpg_error_from_syserror ();
parm->fd = fd;
parm->data = data;
parm->datalen = datalen;
parm->err_addr = err_addr;
tattr = pth_attr_new ();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "fd-writer");
tid = pth_spawn (tattr, writer_thread, parm);
if (!tid)
{
err = gpg_error_from_syserror ();
log_error ("error spawning writer thread: %s\n", gpg_strerror (err));
}
else
{
err = 0;
*r_tid = tid;
}
pth_attr_destroy (tattr);
return err;
}
/* The data passed to the reader_thread. */
struct reader_thread_parms
{
int fd;
membuf_t *mb;
gpg_error_t *err_addr;
};
/* The thread started by start_reader. */
static void *
reader_thread (void *arg)
{
struct reader_thread_parms *parm = arg;
char buffer[4096];
int nread;
while ( (nread = pth_read (parm->fd, buffer, sizeof buffer)) )
{
if (nread < 0)
{
if (errno == EINTR)
continue;
*parm->err_addr = gpg_error_from_syserror ();
break; /* Read error. */
}
put_membuf (parm->mb, buffer, nread);
}
if (close (parm->fd))
log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
xfree (parm);
return NULL;
}
/* Fire up a thread to receive data from the file descriptor FD. On
success the thread receives the ownership over FD. The thread ID
is stored at R_TID. After the thread has finished an error from
the thread will be stored at ERR_ADDR. */
static gpg_error_t
start_reader (int fd, membuf_t *mb, pth_t *r_tid, gpg_error_t *err_addr)
{
gpg_error_t err;
struct reader_thread_parms *parm;
pth_attr_t tattr;
pth_t tid;
*r_tid = NULL;
*err_addr = 0;
parm = xtrymalloc (sizeof *parm);
if (!parm)
return gpg_error_from_syserror ();
parm->fd = fd;
parm->mb = mb;
parm->err_addr = err_addr;
tattr = pth_attr_new ();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "fd-reader");
tid = pth_spawn (tattr, reader_thread, parm);
if (!tid)
{
err = gpg_error_from_syserror ();
log_error ("error spawning reader thread: %s\n", gpg_strerror (err));
}
else
{
err = 0;
*r_tid = tid;
}
pth_attr_destroy (tattr);
return err;
}
/* Call GPG to encrypt a block of data.
*/
gpg_error_t
gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
void **r_ciph, size_t *r_ciphlen)
{
gpg_error_t err;
assuan_context_t ctx;
int outbound_fds[2] = { -1, -1 };
int inbound_fds[2] = { -1, -1 };
pth_t writer_tid = NULL;
pth_t reader_tid = NULL;
gpg_error_t writer_err, reader_err;
membuf_t reader_mb;
*r_ciph = NULL;
*r_ciphlen = 0;
/* Init the memory buffer to receive the encrypted stuff. */
init_membuf (&reader_mb, 4096);
/* Create two pipes. */
err = gnupg_create_outbound_pipe (outbound_fds);
if (!err)
err = gnupg_create_inbound_pipe (inbound_fds);
if (err)
{
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
goto leave;
}
/* Start GPG and send the INPUT and OUTPUT commands. */
err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx);
if (err)
goto leave;
close (outbound_fds[0]); outbound_fds[0] = -1;
close (inbound_fds[1]); inbound_fds[1] = -1;
/* Start a writer thread to feed the INPUT command of the server. */
err = start_writer (outbound_fds[1], plain, plainlen,
&writer_tid, &writer_err);
if (err)
return err;
outbound_fds[1] = -1; /* The thread owns the FD now. */
/* Start a reader thread to eat from the OUTPUT command of the
server. */
err = start_reader (inbound_fds[0], &reader_mb,
&reader_tid, &reader_err);
if (err)
return err;
outbound_fds[0] = -1; /* The thread owns the FD now. */
/* Run the encryption. */
err = assuan_transact (ctx, "RECIPIENT alpha@example.net",
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("the engine's RECIPIENT command failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
goto leave;
}
err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("the engine's ENCRYPT command failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
goto leave;
}
/* Wait for reader and return the data. */
if (!pth_join (reader_tid, NULL))
{
err = gpg_error_from_syserror ();
log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
goto leave;
}
reader_tid = NULL;
if (reader_err)
{
err = reader_err;
log_error ("read error in reader thread: %s\n", gpg_strerror (err));
goto leave;
}
/* Wait for the writer to catch a writer error. */
if (!pth_join (writer_tid, NULL))
{
err = gpg_error_from_syserror ();
log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
goto leave;
}
writer_tid = NULL;
if (writer_err)
{
err = writer_err;
log_error ("write error in writer thread: %s\n", gpg_strerror (err));
goto leave;
}
/* Return the data. */
*r_ciph = get_membuf (&reader_mb, r_ciphlen);
if (!*r_ciph)
{
err = gpg_error_from_syserror ();
log_error ("error while storing the data in the reader thread: %s\n",
gpg_strerror (err));
goto leave;
}
leave:
if (reader_tid)
{
pth_cancel (reader_tid);
pth_join (reader_tid, NULL);
}
if (writer_tid)
{
pth_cancel (writer_tid);
pth_join (writer_tid, NULL);
}
if (outbound_fds[0] != -1)
close (outbound_fds[0]);
if (outbound_fds[1] != -1)
close (outbound_fds[1]);
if (inbound_fds[0] != -1)
close (inbound_fds[0]);
if (inbound_fds[1] != -1)
close (inbound_fds[1]);
release_gpg (ctx);
xfree (get_membuf (&reader_mb, NULL));
return err;
}
/* Call GPG to decrypt a block of data.
*/
gpg_error_t
gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
void **r_plain, size_t *r_plainlen)
{
gpg_error_t err;
assuan_context_t ctx;
int outbound_fds[2] = { -1, -1 };
int inbound_fds[2] = { -1, -1 };
pth_t writer_tid = NULL;
pth_t reader_tid = NULL;
gpg_error_t writer_err, reader_err;
membuf_t reader_mb;
*r_plain = NULL;
*r_plainlen = 0;
/* Init the memory buffer to receive the encrypted stuff. */
init_membuf_secure (&reader_mb, 1024);
/* Create two pipes. */
err = gnupg_create_outbound_pipe (outbound_fds);
if (!err)
err = gnupg_create_inbound_pipe (inbound_fds);
if (err)
{
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
goto leave;
}
/* Start GPG and send the INPUT and OUTPUT commands. */
err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx);
if (err)
goto leave;
close (outbound_fds[0]); outbound_fds[0] = -1;
close (inbound_fds[1]); inbound_fds[1] = -1;
/* Start a writer thread to feed the INPUT command of the server. */
err = start_writer (outbound_fds[1], ciph, ciphlen,
&writer_tid, &writer_err);
if (err)
return err;
outbound_fds[1] = -1; /* The thread owns the FD now. */
/* Start a reader thread to eat from the OUTPUT command of the
server. */
err = start_reader (inbound_fds[0], &reader_mb,
&reader_tid, &reader_err);
if (err)
return err;
outbound_fds[0] = -1; /* The thread owns the FD now. */
/* Run the decryption. */
err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("the engine's DECRYPT command failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
goto leave;
}
/* Wait for reader and return the data. */
if (!pth_join (reader_tid, NULL))
{
err = gpg_error_from_syserror ();
log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
goto leave;
}
reader_tid = NULL;
if (reader_err)
{
err = reader_err;
log_error ("read error in reader thread: %s\n", gpg_strerror (err));
goto leave;
}
/* Wait for the writer to catch a writer error. */
if (!pth_join (writer_tid, NULL))
{
err = gpg_error_from_syserror ();
log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
goto leave;
}
writer_tid = NULL;
if (writer_err)
{
err = writer_err;
log_error ("write error in writer thread: %s\n", gpg_strerror (err));
goto leave;
}
/* Return the data. */
*r_plain = get_membuf (&reader_mb, r_plainlen);
if (!*r_plain)
{
err = gpg_error_from_syserror ();
log_error ("error while storing the data in the reader thread: %s\n",
gpg_strerror (err));
goto leave;
}
leave:
if (reader_tid)
{
pth_cancel (reader_tid);
pth_join (reader_tid, NULL);
}
if (writer_tid)
{
pth_cancel (writer_tid);
pth_join (writer_tid, NULL);
}
if (outbound_fds[0] != -1)
close (outbound_fds[0]);
if (outbound_fds[1] != -1)
close (outbound_fds[1]);
if (inbound_fds[0] != -1)
close (inbound_fds[0]);
if (inbound_fds[1] != -1)
close (inbound_fds[1]);
release_gpg (ctx);
xfree (get_membuf (&reader_mb, NULL));
return err;
}
diff --git a/g13/g13.c b/g13/g13.c
index 0e479b016..5838b13fa 100644
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -1,977 +1,962 @@
/* g13.c - Disk Key management with GnuPG
* 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 <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <pth.h>
#include "g13.h"
#include <gcrypt.h>
#include <assuan.h>
#include "i18n.h"
#include "sysutils.h"
#include "gc-opt-flags.h"
#include "keyblob.h"
#include "server.h"
#include "runner.h"
#include "create.h"
#include "mount.h"
#include "mountinfo.h"
enum cmd_and_opt_values {
aNull = 0,
oQuiet = 'q',
oVerbose = 'v',
aGPGConfList = 500,
aGPGConfTest,
aCreate,
aMount,
aUmount,
aServer,
oOptions,
oDebug,
oDebugLevel,
oDebugAll,
oDebugNone,
oDebugWait,
oDebugAllowCoreDump,
oLogFile,
oNoLogFile,
oAuditLog,
oOutput,
oAgentProgram,
oGpgProgram,
oDisplay,
oTTYname,
oTTYtype,
oLCctype,
oLCmessages,
oXauthority,
oStatusFD,
oLoggerFD,
oNoVerbose,
oNoSecmemWarn,
oNoGreeting,
oNoTTY,
oNoOptions,
oHomedir,
oWithColons,
oDryRun,
oNoDetach,
oRecipient,
oNoRandomSeedFile,
oFakedSystemTime
};
static ARGPARSE_OPTS opts[] = {
ARGPARSE_group (300, N_("@Commands:\n ")),
ARGPARSE_c (aCreate, "create", N_("Create a new file system container")),
ARGPARSE_c (aMount, "mount", N_("Mount a file system container") ),
ARGPARSE_c (aUmount, "umount", N_("Unmount a file system container") ),
ARGPARSE_c (aServer, "server", N_("Run in server mode")),
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
ARGPARSE_group (301, N_("@\nOptions:\n ")),
ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
ARGPARSE_s_n (oNoTTY, "no-tty", N_("don't use the terminal at all")),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write log output to FILE")),
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
- ARGPARSE_s_s (oAuditLog, "audit-log",
- N_("|FILE|write an audit log to FILE")),
ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_p_u (oDebug, "debug", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level",
N_("|LEVEL|set the debugging level to LEVEL")),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_n (oDebugNone, "debug-none", "@"),
ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
ARGPARSE_s_i (oStatusFD, "status-fd",
N_("|FD|write status info to this FD")),
ARGPARSE_group (302, N_(
"@\n(See the man page for a complete listing of all commands and options)\n"
)),
ARGPARSE_group (303, N_("@\nExamples:\n\n"
" blurb\n"
" blurb\n")),
/* Hidden options. */
ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_n (oNoOptions, "no-options", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_s_s (oGpgProgram, "gpg-program", "@"),
ARGPARSE_s_s (oDisplay, "display", "@"),
ARGPARSE_s_s (oTTYname, "ttyname", "@"),
ARGPARSE_s_s (oTTYtype, "ttytype", "@"),
ARGPARSE_s_s (oLCctype, "lc-ctype", "@"),
ARGPARSE_s_s (oLCmessages, "lc-messages", "@"),
ARGPARSE_s_s (oXauthority, "xauthority", "@"),
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
ARGPARSE_s_n (oWithColons, "with-colons", "@"),
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
/* Command aliases. */
ARGPARSE_end ()
};
/* The timer tick interval used by the idle task. */
#define TIMERTICK_INTERVAL_SEC (1)
/* Global variable to keep an error count. */
int g13_errors_seen = 0;
/* It is possible that we are currently running under setuid permissions. */
static int maybe_setuid = 1;
/* Helper to implement --debug-level and --debug. */
static const char *debug_level;
static unsigned int debug_value;
/* Flag to indicate that a shutdown was requested. */
static int shutdown_pending;
/* The thread id of the idle task. */
static pth_t idle_task_tid;
static void set_cmd (enum cmd_and_opt_values *ret_cmd,
enum cmd_and_opt_values new_cmd );
static void emergency_cleanup (void);
static void start_idle_task (void);
static void join_idle_task (void);
/* Begin Pth wrapper functions. */
ASSUAN_SYSTEM_PTH_IMPL;
GCRY_THREAD_OPTION_PTH_IMPL;
static int fixed_gcry_pth_init (void)
{
return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
}
/* End Pth wrapper functions. */
static const char *
my_strusage( int level )
{
const char *p;
switch (level)
{
case 11: p = "g13 (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
break;
case 1:
case 40: p = _("Usage: g13 [options] [files] (-h for help)");
break;
case 41:
p = _("Syntax: g13 [options] [files]\n"
"Create, mount or unmount an encrypted file system container\n");
break;
case 31: p = "\nHome: "; break;
case 32: p = opt.homedir; break;
default: p = NULL; break;
}
return p;
}
static void
wrong_args (const char *text)
{
fputs (_("usage: g13 [options] "), stderr);
fputs (text, stderr);
putc ('\n', stderr);
g13_exit (2);
}
/* Setup the debugging. With a DEBUG_LEVEL of NULL only the active
debug flags are propagated to the subsystems. With DEBUG_LEVEL
set, a specific set of debug flags is set; and individual debugging
flags will be added on top. */
static void
set_debug (void)
{
if (!debug_level)
;
else if (!strcmp (debug_level, "none"))
opt.debug = 0;
else if (!strcmp (debug_level, "basic"))
opt.debug = DBG_ASSUAN_VALUE|DBG_MOUNT_VALUE;
else if (!strcmp (debug_level, "advanced"))
opt.debug = DBG_ASSUAN_VALUE|DBG_MOUNT_VALUE;
else if (!strcmp (debug_level, "expert"))
opt.debug = (DBG_ASSUAN_VALUE|DBG_MOUNT_VALUE|DBG_CRYPTO_VALUE);
else if (!strcmp (debug_level, "guru"))
opt.debug = ~0;
else
{
log_error (_("invalid debug-level `%s' given\n"), debug_level);
g13_exit(2);
}
opt.debug |= debug_value;
if (opt.debug && !opt.verbose)
opt.verbose = 1;
if (opt.debug)
opt.quiet = 0;
if (opt.debug & DBG_CRYPTO_VALUE )
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
}
static void
set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
{
enum cmd_and_opt_values cmd = *ret_cmd;
if (!cmd || cmd == new_cmd)
cmd = new_cmd;
else
{
log_error (_("conflicting commands\n"));
g13_exit (2);
}
*ret_cmd = cmd;
}
/* Helper to add recipients to a list. */
static int
add_encryption_key (ctrl_t ctrl, const char *name,
void /*FIXME*/ *keylist, int is_cms)
{
/* FIXME: Decide whether to add a CMS or OpenPGP key and then add
the key to a list. */
/* int rc = foo_add_to_certlist (ctrl, name, 0, recplist, is_encrypt_to); */
/* if (rc) */
/* { */
/* if (recp_required) */
/* { */
/* log_error ("can't encrypt to `%s': %s\n", name, gpg_strerror (rc)); */
/* gpgsm_status2 (ctrl, STATUS_INV_RECP, */
/* get_inv_recpsgnr_code (rc), name, NULL); */
/* } */
/* else */
/* log_info (_("NOTE: won't be able to encrypt to `%s': %s\n"), */
/* name, gpg_strerror (rc)); */
/* } */
return 0; /* Key is good. */
}
int
main ( int argc, char **argv)
{
ARGPARSE_ARGS pargs;
int orig_argc;
char **orig_argv;
gpg_error_t err;
const char *fname;
int may_coredump;
FILE *configfp = NULL;
char *configname = NULL;
unsigned configlineno;
int parse_debug = 0;
int no_more_options = 0;
int default_config =1;
char *logfile = NULL;
- char *auditlog = NULL;
int greeting = 0;
int nogreeting = 0;
int debug_wait = 0;
int use_random_seed = 1;
int nodetach = 0;
int nokeysetup = 0;
enum cmd_and_opt_values cmd = 0;
struct server_control_s ctrl;
- estream_t auditfp = NULL;
strlist_t recipients = NULL;
/*mtrace();*/
gnupg_reopen_std ("g13");
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
log_set_prefix ("g13", 1);
/* Make sure that our subsystems are ready. */
i18n_init ();
init_common_subsystems ();
/* Libgcrypt requires us to register the threading model first.
Note that this will also do the pth_init. */
gcry_threads_pth.init = fixed_gcry_pth_init;
err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
if (err)
{
log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
gpg_strerror (err));
}
/* Check that the Libgcrypt is suitable. */
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
/* Take extra care of the random pool. */
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
may_coredump = disable_core_dumps ();
gnupg_init_signals (0, emergency_cleanup);
create_dotlock (NULL); /* Register locking cleanup. */
opt.homedir = default_homedir ();
/* First check whether we have a config file on the commandline. */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1|(1<<6); /* Do not remove the args, ignore version. */
while (arg_parse( &pargs, opts))
{
if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
parse_debug++;
else if (pargs.r_opt == oOptions)
{ /* Yes, there is one, so we do not try the default one but
read the config file when it is encountered at the
commandline. */
default_config = 0;
}
else if (pargs.r_opt == oNoOptions)
default_config = 0; /* --no-options */
else if (pargs.r_opt == oHomedir)
opt.homedir = pargs.r.ret_str;
}
/* Initialize the secure memory. */
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
maybe_setuid = 0;
/*
Now we are now working under our real uid
*/
/* Setup malloc hooks. */
{
struct assuan_malloc_hooks malloc_hooks;
malloc_hooks.malloc = gcry_malloc;
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
}
/* Prepare libassuan. */
assuan_set_assuan_log_prefix (log_get_prefix (NULL));
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
/* Setup a default control structure for command line mode. */
memset (&ctrl, 0, sizeof ctrl);
g13_init_default_ctrl (&ctrl);
/* Set the default option file */
if (default_config )
configname = make_filename (opt.homedir, "g13.conf", NULL);
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags = 1; /* Do not remove the args. */
next_pass:
if (configname)
{
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if (parse_debug)
log_info (_("NOTE: no default option file `%s'\n"), configname);
}
else
{
log_error (_("option file `%s': %s\n"),
configname, strerror(errno));
g13_exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname)
log_info (_("reading options from `%s'\n"), configname);
default_config = 0;
}
while (!no_more_options
&& optfile_parse (configfp, configname, &configlineno, &pargs, opts))
{
switch (pargs.r_opt)
{
case aGPGConfList:
case aGPGConfTest:
set_cmd (&cmd, pargs.r_opt);
nogreeting = 1;
nokeysetup = 1;
break;
case aServer:
case aMount:
case aUmount:
nokeysetup = 1;
case aCreate:
set_cmd (&cmd, pargs.r_opt);
break;
case oOutput: opt.outfile = pargs.r.ret_str; break;
case oQuiet: opt.quiet = 1; break;
case oNoGreeting: nogreeting = 1; break;
case oNoTTY: break;
case oDryRun: opt.dry_run = 1; break;
case oVerbose:
opt.verbose++;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
break;
case oNoVerbose:
opt.verbose = 0;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
break;
case oLogFile: logfile = pargs.r.ret_str; break;
case oNoLogFile: logfile = NULL; break;
- case oAuditLog: auditlog = pargs.r.ret_str; break;
-
case oNoDetach: nodetach = 1; break;
case oDebug: debug_value |= pargs.r.ret_ulong; break;
case oDebugAll: debug_value = ~0; break;
case oDebugNone: debug_value = 0; break;
case oDebugLevel: debug_level = pargs.r.ret_str; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oDebugAllowCoreDump:
may_coredump = enable_core_dumps ();
break;
case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
case oNoOptions: break; /* no-options */
case oOptions:
/* Config files may not be nested (silently ignore them). */
if (!configfp)
{
xfree(configname);
configname = xstrdup (pargs.r.ret_str);
goto next_pass;
}
break;
case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
case oGpgProgram: opt.gpg_program = pargs.r.ret_str; break;
case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
case oXauthority: opt.xauthority = xstrdup (pargs.r.ret_str); break;
case oFakedSystemTime:
{
time_t faked_time = isotime2epoch (pargs.r.ret_str);
if (faked_time == (time_t)(-1))
faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
gnupg_set_time (faked_time, 0);
}
break;
case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;
case oNoRandomSeedFile: use_random_seed = 0; break;
case oRecipient: /* Store the encryption key. */
add_to_strlist (&recipients, pargs.r.ret_str);
break;
default:
pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
break;
}
}
if (configfp)
{
fclose (configfp);
configfp = NULL;
/* Keep a copy of the config filename. */
opt.config_filename = configname;
configname = NULL;
goto next_pass;
}
xfree (configname);
configname = NULL;
if (!opt.config_filename)
opt.config_filename = make_filename (opt.homedir, "g13.conf", NULL);
if (log_get_errorcount(0))
g13_exit(2);
/* Now that we have the options parsed we need to update the default
control structure. */
g13_init_default_ctrl (&ctrl);
if (nogreeting)
greeting = 0;
if (greeting)
{
fprintf (stderr, "%s %s; %s\n",
strusage(11), strusage(13), strusage(14) );
fprintf (stderr, "%s\n", strusage(15) );
}
if (may_coredump && !opt.quiet)
log_info (_("WARNING: program may create a core file!\n"));
if (logfile)
{
log_set_file (logfile);
log_set_prefix (NULL, 1|2|4);
}
if (gnupg_faked_time_p ())
{
gnupg_isotime_t tbuf;
log_info (_("WARNING: running with faked system time: "));
gnupg_get_isotime (tbuf);
dump_isotime (tbuf);
log_printf ("\n");
}
/* Print any pending secure memory warnings. */
gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
/* Setup the debug flags for all subsystems. */
set_debug ();
/* Install a regular exit handler to make real sure that the secure
memory gets wiped out. */
if (atexit (emergency_cleanup))
{
log_error ("atexit failed\n");
g13_exit (2);
}
/* Terminate if we found any error until now. */
if (log_get_errorcount(0))
g13_exit (2);
/* Set the standard GnuPG random seed file. */
if (use_random_seed)
{
char *p = make_filename (opt.homedir, "random_seed", NULL);
gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
xfree(p);
}
/* Store given filename into FNAME. */
fname = argc? *argv : NULL;
/* Parse all given encryption keys. This does a lookup of the keys
and stops if any of the given keys was not found. */
if (!nokeysetup)
{
strlist_t sl;
int failed = 0;
for (sl = recipients; sl; sl = sl->next)
if (add_encryption_key (&ctrl, sl->d, NULL /* FIXME*/, 0))
failed = 1;
if (failed)
g13_exit (1);
}
/* Dispatch command. */
switch (cmd)
{
case aGPGConfList:
{ /* List options and default values in the GPG Conf format. */
char *config_filename_esc = percent_escape (opt.config_filename, NULL);
printf ("gpgconf-g13.conf:%lu:\"%s\n",
GC_OPT_FLAG_DEFAULT, config_filename_esc);
xfree (config_filename_esc);
printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE);
printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
}
break;
case aGPGConfTest:
/* This is merely a dummy command to test whether the
configuration file is valid. */
break;
case aServer:
{
start_idle_task ();
err = g13_server (&ctrl);
if (err)
log_error ("server exited with error: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
else
shutdown_pending++;
}
break;
case aCreate: /* Create a new container. */
{
if (argc != 1)
wrong_args ("--create filename");
start_idle_task ();
err = g13_create_container (&ctrl, argv[0]);
if (err)
log_error ("error creating a new container: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
else
shutdown_pending++;
}
break;
case aMount: /* Mount a container. */
{
if (argc != 1 && argc != 2 )
wrong_args ("--mount filename [mountpoint]");
start_idle_task ();
err = g13_mount_container (&ctrl, argv[0], argc == 2?argv[1]:NULL);
if (err)
log_error ("error mounting container `%s': %s <%s>\n",
*argv, gpg_strerror (err), gpg_strsource (err));
}
break;
default:
log_error (_("invalid command (there is no implicit command)\n"));
break;
}
if (!err)
join_idle_task ();
- /* Print the audit result if needed. */
- if (auditlog && auditfp)
- {
- /* audit_print_result (ctrl.audit, auditfp, 0); */
- /* audit_release (ctrl.audit); */
- ctrl.audit = NULL;
- es_fclose (auditfp);
- }
-
/* Cleanup. */
g13_exit (0);
return 8; /*NOTREACHED*/
}
/* Note: This function is used by signal handlers!. */
static void
emergency_cleanup (void)
{
gcry_control (GCRYCTL_TERM_SECMEM );
}
void
g13_exit (int rc)
{
gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
if (opt.debug & DBG_MEMSTAT_VALUE)
{
gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
emergency_cleanup ();
rc = rc? rc : log_get_errorcount(0)? 2 : g13_errors_seen? 1 : 0;
exit (rc);
}
/* Store defaults into the per-connection CTRL object. */
void
g13_init_default_ctrl (struct server_control_s *ctrl)
{
ctrl->conttype = CONTTYPE_ENCFS;
}
/* This function is called for each signal we catch. It is run in the
main context or the one of a Pth thread and thus it is not
restricted in what it may do. */
static void
handle_signal (int signo)
{
switch (signo)
{
#ifndef HAVE_W32_SYSTEM
case SIGHUP:
log_info ("SIGHUP received - re-reading configuration\n");
/* Fixme: Not yet implemented. */
break;
case SIGUSR1:
log_info ("SIGUSR1 received - printing internal information:\n");
pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
mountinfo_dump_all ();
break;
case SIGUSR2:
log_info ("SIGUSR2 received - no action defined\n");
break;
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
else
log_info ("SIGTERM received - still %u runners active\n",
runner_get_threads ());
shutdown_pending++;
if (shutdown_pending > 2)
{
log_info ("shutdown forced\n");
log_info ("%s %s stopped\n", strusage(11), strusage(13) );
g13_exit (0);
}
break;
case SIGINT:
log_info ("SIGINT received - immediate shutdown\n");
log_info( "%s %s stopped\n", strusage(11), strusage(13));
g13_exit (0);
break;
#endif /*!HAVE_W32_SYSTEM*/
default:
log_info ("signal %d received - no action defined\n", signo);
}
}
/* This ticker function is called about every TIMERTICK_INTERVAL_SEC
seconds. */
static void
handle_tick (void)
{
/* log_debug ("TICK\n"); */
}
/* The idle task. We use a separate thread to do idle stuff and to
catch signals. */
static void *
idle_task (void *dummy_arg)
{
sigset_t sigs; /* The set of signals we want to catch. */
pth_event_t ev; /* The main event to catch signals. */
pth_event_t time_ev; /* The time event. */
int signo; /* The number of a raised signal is stored here. */
(void)dummy_arg;
/* Create the event to catch the signals. */
#ifndef HAVE_W32_SYSTEM
sigemptyset (&sigs );
sigaddset (&sigs, SIGHUP);
sigaddset (&sigs, SIGUSR1);
sigaddset (&sigs, SIGUSR2);
sigaddset (&sigs, SIGINT);
sigaddset (&sigs, SIGTERM);
pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
#else
sigs = 0;
#endif
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
/* The time event neds to computed n tghe fly. */
time_ev = NULL;
for (;;)
{
/* The shutdown flag allows us to terminate the idle task. */
if (shutdown_pending)
{
runner_cancel_all ();
if (!runner_get_threads ())
break; /* ready */
}
/* Create a timeout event if needed. To help with power saving
we syncronize the ticks to the next full second. */
if (!time_ev)
{
pth_time_t nexttick;
nexttick = pth_timeout (TIMERTICK_INTERVAL_SEC, 0);
if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */
{
nexttick.tv_sec++;
nexttick.tv_usec = 0;
}
time_ev = pth_event (PTH_EVENT_TIME, nexttick);
}
pth_event_concat (ev, time_ev, NULL);
pth_wait (ev);
pth_event_isolate (time_ev);
if (pth_event_occurred (ev))
{
handle_signal (signo);
}
if (time_ev && pth_event_occurred (time_ev))
{
pth_event_free (time_ev, PTH_FREE_ALL);
time_ev = NULL;
handle_tick ();
}
}
pth_event_free (ev, PTH_FREE_ALL);
if (time_ev)
pth_event_free (time_ev, PTH_FREE_ALL);
log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
return NULL;
}
/* Start the idle task. */
static void
start_idle_task (void)
{
pth_attr_t tattr;
pth_t tid;
tattr = pth_attr_new ();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "idle-task");
tid = pth_spawn (tattr, idle_task, NULL);
if (!tid)
{
log_fatal ("error starting idle task: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
return; /*NOTREACHED*/
}
idle_task_tid = tid;
pth_attr_destroy (tattr);
}
/* Wait for the idle task to finish. */
static void
join_idle_task (void)
{
if (idle_task_tid)
{
if (!pth_join (idle_task_tid, NULL))
log_error ("waiting for idle task thread failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
}
}
diff --git a/g13/g13.h b/g13/g13.h
index 0bfc42e9c..3c52b50f4 100644
--- a/g13/g13.h
+++ b/g13/g13.h
@@ -1,113 +1,111 @@
/* g13.h - Global definitions for G13.
* 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/>.
*/
#ifndef G13_H
#define G13_H
#ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined
#endif
#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_G13
#include <gpg-error.h>
#include "../common/util.h"
#include "../common/status.h"
#include "../common/estream.h"
-#include "../common/audit.h"
#include "../common/session-env.h"
/* A large struct named "opt" to keep global flags. */
struct
{
unsigned int debug; /* Debug flags (DBG_foo_VALUE). */
int verbose; /* Verbosity level. */
int quiet; /* Be as quiet as possible. */
int dry_run; /* Don't change any persistent data. */
const char *homedir; /* Configuration directory name. */
const char *config_filename; /* Name of the used config file. */
/* Filename of the AGENT program. */
const char *agent_program;
/* Filename of the GPG program. Unless set via an program option it
is initialzed at the first engine startup to the standard gpg
filename. */
const char *gpg_program;
/* Environment variables passed along to the engine. */
char *display;
char *ttyname;
char *ttytype;
char *lc_ctype;
char *lc_messages;
char *xauthority;
char *pinentry_user_data;
session_env_t session_env;
/* Name of the output file - FIXME: what is this? */
const char *outfile;
} opt;
/* Debug values and macros. */
#define DBG_MOUNT_VALUE 1 /* Debug mount or device stuff. */
#define DBG_CRYPTO_VALUE 4 /* Debug low level crypto. */
#define DBG_MEMORY_VALUE 32 /* Debug memory allocation stuff. */
#define DBG_MEMSTAT_VALUE 128 /* Show memory statistics. */
#define DBG_ASSUAN_VALUE 1024 /* Debug assuan communication. */
#define DBG_MOUNT (opt.debug & DBG_MOUNT_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
/* Forward declaration for an object defined in server.c. */
struct server_local_s;
/* Session control object. This object is passed down to most
functions. The default values for it are set by
g13_init_default_ctrl(). */
struct server_control_s
{
int no_server; /* We are not running under server control */
int status_fd; /* Only for non-server mode */
struct server_local_s *server_local;
- audit_ctx_t audit; /* NULL or a context for the audit subsystem. */
int agent_seen; /* Flag indicating that the gpg-agent has been
accessed. */
int with_colons; /* Use column delimited output format */
/* Type of the current container. See the CONTTYPE_ constants. */
int conttype;
};
/*-- g13.c --*/
void g13_exit (int rc);
void g13_init_default_ctrl (struct server_control_s *ctrl);
#endif /*G13_H*/
diff --git a/g13/server.c b/g13/server.c
index 900dbc909..585b9e7aa 100644
--- a/g13/server.c
+++ b/g13/server.c
@@ -1,744 +1,738 @@
/* 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"
#include "./server.h"
#include "./mount.h"
/* Local data for this server module. A pointer to this is stored in
the CTRL object of each connection. */
struct server_local_s
{
/* The Assuan contect we are working on. */
assuan_context_t assuan_ctx;
char *containername; /* Malloced active containername. */
};
/* Local prototypes. */
static int command_has_option (const char *cmd, const char *cmdopt);
/*
Helper functions.
*/
/* Set an error and a description. */
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
/* Skip over options. Blanks after the options are also removed. */
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. */
/* static int */
/* has_option (const char *line, const char *name) */
/* { */
/* const char *s; */
/* int n = strlen (name); */
/* s = strstr (line, name); */
/* if (s && s >= skip_options (line)) */
/* return 0; */
/* return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
/* } */
/* 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;
}
/* 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;
(void)ctrl;
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, "enable-audit-log"))
- {
- /* This is not yet used. */
- /* int i = *value? atoi (value) : 0; */
- /* ctrl->server_local->enable_audit_log = i; */
- }
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. */
static void
reset_notify (assuan_context_t ctx)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
xfree (ctrl->server_local->containername);
ctrl->server_local->containername = NULL;
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
}
/* OPEN [options] <filename>
Open the container FILENAME. FILENAME must be percent-plus
escaped. A quick check to see whether this is a suitable G13
container file is done. However no cryptographic check or any
other check is done. This command is used to define the target for
further commands. The filename is reset with the RESET command,
another OPEN or the CREATE command.
*/
static gpg_error_t
cmd_open (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
char *p, *pend;
size_t len;
/* In any case reset the active container. */
xfree (ctrl->server_local->containername);
ctrl->server_local->containername = NULL;
/* 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;
}
/* 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 ();
leave:
return leave_cmd (ctx, err);
}
/* MOUNT [options] [<mountpoint>]
Mount the currently open file onto MOUNTPOINT. If MOUNTPOINT is
not given the system picks an unused mountpoint. MOUNTPOINT must
be percent-plus escaped to allow for arbitrary names.
*/
static gpg_error_t
cmd_mount (assuan_context_t ctx, char *line)
{
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;
}
if (!ctrl->server_local->containername)
{
err = gpg_error (GPG_ERR_MISSING_ACTION);
goto leave;
}
/* Perform the mount. */
err = g13_mount_container (ctrl, ctrl->server_local->containername,
*line? line : NULL);
leave:
return leave_cmd (ctx, err);
}
/* UMOUNT [options] [<mountpoint>]
Unmount the currently open file or the one opened at MOUNTPOINT.
MOUNTPOINT must be percent-plus escaped.
*/
static gpg_error_t
cmd_umount (assuan_context_t ctx, char *line)
{
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;
}
/* Perform the unmount. */
err = g13_umount_container (ctrl, ctrl->server_local->containername,
*line? line : NULL);
leave:
return leave_cmd (ctx, err);
}
/* RECIPIENT <userID>
FIXME - description.
All RECIPIENT commands are cumulative until a RESET or an
successful CREATE command.
*/
static gpg_error_t
cmd_recipient (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
(void)ctrl;
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
/* err = gpgsm_add_to_certlist (ctrl, line, 0, */
/* &ctrl->server_local->recplist, 0); */
/* if (err) */
/* { */
/* gpgsm_status2 (ctrl, STATUS_INV_RECP, */
/* get_inv_recpsgnr_code (rc), line, NULL); */
/* } */
return leave_cmd (ctx, err);
}
/* SIGNER <userID>
FIXME - description.
*/
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;
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return leave_cmd (ctx, err);
}
/* CREATE [options] filename
Create a new container. On success the OPEN command is done
implictly for the new container.
*/
static gpg_error_t
cmd_create (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
(void)ctrl;
/* First we close the active container. */
xfree (ctrl->server_local->containername);
ctrl->server_local->containername = NULL;
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return leave_cmd (ctx, err);
}
/* GETINFO <what>
Multipurpose function to return a variety of information.
Supported values for WHAT are:
version - Return the version of the program.
pid - Return the process id of the server.
cmd_has_option CMD OPT
- Returns OK if the command CMD implements the option OPT.
*/
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;
return 0;
}
/* Tell the Assuan library about our commands. */
static int
register_commands (assuan_context_t ctx)
{
static struct {
const char *name;
gpg_error_t (*handler)(assuan_context_t, char *line);
} table[] = {
{ "OPEN", cmd_open },
{ "MOUNT", cmd_mount },
{ "UMOUNT", cmd_umount },
{ "RECIPIENT", cmd_recipient },
{ "SIGNER", cmd_signer },
{ "CREATE", cmd_create },
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ "GETINFO", cmd_getinfo },
{ NULL }
};
gpg_error_t err;
int i;
for (i=0; table[i].name; i++)
{
err = assuan_register_command (ctx, table[i].name, table[i].handler);
if (err)
return err;
}
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;
int filedes[2];
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. */
filedes[0] = 0;
filedes[1] = 1;
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;
if (DBG_ASSUAN)
assuan_set_log_stream (ctx, log_get_stream ());
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));
leave:
if (ctrl->server_local)
{
xfree (ctrl->server_local);
ctrl->server_local = NULL;
}
assuan_release (ctx);
return err;
}
/* gpg_error_t */
/* gpgsm_status2 (ctrl_t ctrl, int no, ...) */
/* { */
/* gpg_error_t err = 0; */
/* va_list arg_ptr; */
/* const char *text; */
/* va_start (arg_ptr, no); */
/* 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"); */
/* if (!statusfp) */
/* { */
/* log_fatal ("can't open fd %d for status output: %s\n", */
/* ctrl->status_fd, strerror(errno)); */
/* } */
/* } */
/* fputs ("[GNUPG:] ", statusfp); */
/* fputs (get_status_string (no), statusfp); */
/* 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; */
/* 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); */
/* } */
/* va_end (arg_ptr); */
/* return err; */
/* } */
/* gpg_error_t */
/* gpgsm_status (ctrl_t ctrl, int no, const char *text) */
/* { */
/* return gpgsm_status2 (ctrl, no, text, NULL); */
/* } */
/* gpg_error_t */
/* gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text, */
/* gpg_err_code_t ec) */
/* { */
/* char buf[30]; */
/* sprintf (buf, "%u", (unsigned int)ec); */
/* if (text) */
/* return gpgsm_status2 (ctrl, no, text, buf, NULL); */
/* else */
/* return gpgsm_status2 (ctrl, no, buf, NULL); */
/* } */
/* 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);
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 31, 8:00 AM (8 h, 33 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
6c/9d/7bc0f06a0b0f3e757207afa30ea1

Event Timeline