Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F40810700
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
84 KB
Subscribers
None
View Options
diff --git a/configure.ac b/configure.ac
index 2ab95dc..f6cd09f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,502 +1,502 @@
# configure.ac - for libassuan
# Copyright (C) 2001, 2002, 2003, 2006, 2007, 2009,
# 2011, 2012, 2013 Free Software Foundation, Inc.
# Copyright (C) 2013, 2014, 2015 g10 Code GmbH
#
# This file is part of Assuan.
#
# Assuan is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of
# the License, or (at your option) any later version.
#
# Assuan 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, see <http://www.gnu.org/licenses/>.
# SPDX-License-Identifier: LGPL-2.1+
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
min_automake_version="1.14"
# To build a release you need to create a tag with the version number
# (git tag -s libassuan-n.m.k) and run "./autogen.sh --force". Please
# bump the version number immediately after the release and do another
# commit and push so that the git magic is able to work. See below
# for the LT versions.
m4_define([mym4_package],[libassuan])
m4_define([mym4_major], [3])
m4_define([mym4_minor], [0])
m4_define([mym4_micro], [0])
# To start a new development series, i.e a new major or minor number
# you need to mark an arbitrary commit before the first beta release
# with an annotated tag. For example a 2.1 branch starts off with
# the tag "foo-2.1-base". This is used as the base for counting
# beta numbers before the first release of a series.
# Below is m4 magic to extract and compute the git revision number,
# the decimalized short revision number, a beta version string and a
# flag indicating a development version (mym4_isbeta). Note that the
# m4 processing is done by autoconf and not during the configure run.
m4_define([mym4_verslist], m4_split(m4_esyscmd([./autogen.sh --find-version] \
mym4_package mym4_major mym4_minor mym4_micro),[:]))
m4_define([mym4_isbeta], m4_argn(2, mym4_verslist))
m4_define([mym4_version], m4_argn(4, mym4_verslist))
m4_define([mym4_revision], m4_argn(7, mym4_verslist))
m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist))
m4_esyscmd([echo ]mym4_version[>VERSION])
AC_INIT([mym4_package],[mym4_version],[https://bugs.gnupg.org])
# LT Version numbers, remember to change them just *before* a release.
# (Code changed: REVISION++)
# (Interfaces added/removed/changed: CURRENT++, REVISION=0)
# (Interfaces added: AGE++)
# (Interfaces removed/changed: AGE=0)
#
LIBASSUAN_LT_CURRENT=9
LIBASSUAN_LT_AGE=9
LIBASSUAN_LT_REVISION=0
# If the API is changed in an incompatible way: increment the next counter.
LIBASSUAN_CONFIG_API_VERSION=3
##############################################
AC_SUBST(LIBASSUAN_LT_CURRENT)
AC_SUBST(LIBASSUAN_LT_AGE)
AC_SUBST(LIBASSUAN_LT_REVISION)
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([serial-tests dist-bzip2 no-dist-gzip])
AM_MAINTAINER_MODE
AC_CONFIG_SRCDIR(src/assuan.h.in)
AC_CONFIG_MACRO_DIR(m4)
AC_CONFIG_HEADERS([config.h])
AC_CANONICAL_HOST
AM_SILENT_RULES
AB_INIT
AC_USE_SYSTEM_EXTENSIONS
# Taken from mpfr-4.0.1, then modified for LDADD_FOR_TESTS_KLUDGE
dnl Under Linux, make sure that the old dtags are used if LD_LIBRARY_PATH
dnl is defined. The issue is that with the new dtags, LD_LIBRARY_PATH has
dnl the precedence over the run path, so that if a compatible MPFR library
dnl is installed in some directory from $LD_LIBRARY_PATH, then the tested
dnl MPFR library will be this library instead of the MPFR library from the
dnl build tree. Other OS with the same issue might be added later.
dnl
dnl References:
dnl https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732
dnl http://lists.gnu.org/archive/html/libtool/2017-05/msg00000.html
dnl
dnl We need to check whether --disable-new-dtags is supported as alternate
dnl linkers may be used (e.g., with tcc: CC=tcc LD=tcc).
dnl
case $host in
*-*-linux*)
if test -n "$LD_LIBRARY_PATH"; then
saved_LDFLAGS="$LDFLAGS"
LDADD_FOR_TESTS_KLUDGE="-Wl,--disable-new-dtags"
LDFLAGS="$LDFLAGS $LDADD_FOR_TESTS_KLUDGE"
AC_MSG_CHECKING(whether --disable-new-dtags is supported by the linker)
AC_LINK_IFELSE([AC_LANG_SOURCE([[
int main (void) { return 0; }
]])],
[AC_MSG_RESULT(yes (use it since LD_LIBRARY_PATH is set))],
[AC_MSG_RESULT(no)
LDADD_FOR_TESTS_KLUDGE=""
])
LDFLAGS="$saved_LDFLAGS"
fi
;;
esac
AC_SUBST([LDADD_FOR_TESTS_KLUDGE])
VERSION_NUMBER=m4_esyscmd(printf "0x%02x%02x%02x" mym4_major \
mym4_minor mym4_micro)
AC_SUBST(VERSION_NUMBER)
# Don't default to build static libs.
LT_PREREQ([2.2.6])
LT_INIT([win32-dll disable-static])
LT_LANG([Windows Resource])
# For now we hardcode the use of version scripts. It would be better
# to write a test for this or even implement this within libtool.
have_ld_version_script=no
case "${host}" in
*-*-linux*)
have_ld_version_script=yes
;;
*-*-gnu*)
have_ld_version_script=yes
;;
*-apple-darwin*)
AC_DEFINE(_XOPEN_SOURCE, 500, Activate POSIX interface on MacOS X)
AC_DEFINE(_DARWIN_C_SOURCE, 1,
Expose all libc features (__DARWIN_C_FULL))
;;
esac
AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
#
# Specify how we support our local modification of libtool for Windows
# 64-bit. Options are:
#
# (1) apply: when appying patch fails, it results failure of entire build
# (2) never: never apply the patch (no try)
# (3) try: use patched if it goes well, use original if fails
#
AC_ARG_WITH([libtool-modification],
AS_HELP_STRING([--with-libtool-modification=apply|never|try],
[how to handle libtool modification (default=never)]),
build_libtool_modification=$withval,
build_libtool_modification=never)
#
# Apply a patch (locally maintained one of ours) to libtool
#
case $host in
x86_64-*mingw32*)
AC_CONFIG_COMMANDS([libtool-patch],[[
if test "$build_selection" = never; then
echo "patch not applied"
elif (mv -f libtool libtool.orig; \
sed -f $srcdir/build-aux/libtool-patch.sed libtool.orig >libtool); then
echo "applied successfully"
elif test "$build_selection" = try; then
mv -f libtool.orig libtool
echo "patch failed, thus, using original"
else
echo "patch failed"
as_fn_exit 1
fi
]],[build_selection=$build_libtool_modification])
;;
*)
;;
esac
AH_TOP([
#ifndef _ASSUAN_CONFIG_H_INCLUDED
#define _ASSUAN_CONFIG_H_INCLUDED
/* Provide the es_ macro for estream. */
#define GPGRT_ENABLE_ES_MACROS 1
])
AH_BOTTOM([
#endif /*_ASSUAN_CONFIG_H_INCLUDED*/
])
# Checks for programs.
missing_dir=`cd $ac_aux_dir && pwd`
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
AC_PROG_AWK
AC_PROG_CC
AC_PROG_CPP
AM_PROG_CC_C_O
if test "x$ac_cv_prog_cc_c89" = "xno" ; then
AC_MSG_ERROR([[No C-89 compiler found]])
fi
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
#AC_ARG_PROGRAM
# We need to compile and run a program on the build machine.
AX_CC_FOR_BUILD
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
AC_MSG_CHECKING([if gcc supports -Wpointer-arith])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wpointer-arith"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],_gcc_wopt=yes,_gcc_wopt=no)
AC_MSG_RESULT($_gcc_wopt)
CFLAGS=$_gcc_cflags_save;
if test x"$_gcc_wopt" = xyes ; then
CFLAGS="$CFLAGS -Wpointer-arith"
fi
fi
#
# Options depending on the host OS.
#
have_dosish_system=no
have_w32_system=no
have_w64_system=no
case "${host}" in
*-linux*)
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -fPIC -DPIC"
fi
;;
x86_64-*mingw32*)
have_dosish_system=yes
have_w32_system=yes
have_w64_system=yes
;;
*-mingw32*)
have_dosish_system=yes
have_w32_system=yes
;;
*-solaris*)
AC_DEFINE(_XOPEN_SOURCE, 500, Activate extensions on Solaris)
AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, Activate extensions on Solaris)
AC_DEFINE(__EXTENSIONS__, 1, Activate extensions on Solaris)
;;
esac
if test "$have_dosish_system" = yes; then
AC_DEFINE(HAVE_DOSISH_SYSTEM,1,
[Defined if we run on some of the PCDOS like systems
(DOS, Windoze. OS/2) with special properties like
no file modes])
fi
if test "$have_w32_system" = yes; then
AC_DEFINE(HAVE_W32_SYSTEM,1,[Defined if we run on a W32 API based system])
if test "$have_w64_system" = yes; then
AC_DEFINE(HAVE_W64_SYSTEM,1,
[Defined if we run on a 64 bit W32 API based system])
fi
AC_CHECK_HEADERS([winsock2.h])
fi
AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
AM_CONDITIONAL(HAVE_W64_SYSTEM, test "$have_w64_system" = yes)
#
# Provide information about the build.
#
BUILD_REVISION="mym4_revision"
AC_SUBST(BUILD_REVISION)
AC_DEFINE_UNQUOTED(BUILD_REVISION, "$BUILD_REVISION",
[GIT commit id revision used to build this package])
changequote(,)dnl
BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1./;s/\./,/g'`
changequote([,])dnl
BUILD_FILEVERSION="${BUILD_FILEVERSION}mym4_revision_dec"
AC_SUBST(BUILD_FILEVERSION)
AC_ARG_ENABLE([build-timestamp],
AS_HELP_STRING([--enable-build-timestamp],
[set an explicit build timestamp for reproducibility.
(default is the current time in ISO-8601 format)]),
[if test "$enableval" = "yes"; then
BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date`
else
BUILD_TIMESTAMP="$enableval"
fi],
[BUILD_TIMESTAMP="<none>"])
AC_SUBST(BUILD_TIMESTAMP)
AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP",
[The time this package was configured for a build])
#
# Check for network libraries. They are needed for tests.
#
AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt,
[NETLIBS="-lsocket $NETLIBS"]))
AC_SUBST(NETLIBS)
if test "$have_w32_system" = yes; then
# FIXME: Check why we need to use ws2_32 and document that.
NETLIBS="-lws2_32 $NETLIBS"
fi
#
# Provide info for src/libassuan-config.in
#
LIBASSUAN_CONFIG_LIBS="-lassuan"
LIBASSUAN_CONFIG_CFLAGS=""
LIBASSUAN_CONFIG_HOST="$host"
AC_SUBST(LIBASSUAN_CONFIG_LIBS)
AC_SUBST(LIBASSUAN_CONFIG_CFLAGS)
AC_SUBST(LIBASSUAN_CONFIG_HOST)
AC_SUBST(LIBASSUAN_CONFIG_API_VERSION)
#
# Checks for header files.
#
AC_CHECK_HEADERS([locale.h sys/uio.h stdint.h inttypes.h \
sys/types.h sys/stat.h unistd.h sys/time.h fcntl.h \
sys/select.h ucred.h sys/ucred.h])
AC_TYPE_UINTPTR_T
AC_TYPE_UINT16_T
#
# Checks for typedefs, structures, and compiler characteristics.
#
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
gl_TYPE_SOCKLEN_T
# Windows has different method for "descriptor passing" (actually,
# it's file handle passing), so, don't check the feature.
check_descriptor_passing=yes
case "${host}" in
*-*-cygwin*)
check_descriptor_passing=no
;;
*-mingw32*)
check_descriptor_passing=no
;;
esac
if test $check_descriptor_passing != yes; then
use_descriptor_passing=no
else
AC_CHECK_MEMBER(struct cmsghdr.cmsg_len,
[use_descriptor_passing=yes],
[use_descriptor_passing=no
AC_MSG_WARN([
***
*** Data structure for sending ancillary data missing.
*** Descriptor passing won't work.
***])],[
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#if HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#include <unistd.h>
])
fi
if test "$use_descriptor_passing" = "yes"; then
AC_DEFINE(USE_DESCRIPTOR_PASSING, 1,
[Defined if descriptor passing is supported])
fi
AM_CONDITIONAL(USE_DESCRIPTOR_PASSING, test "$use_descriptor_passing" = "yes")
# Checking for libgpg-error.
-AM_PATH_GPG_ERROR(1.17,, AC_MSG_ERROR([libgpg-error was not found]))
+AM_PATH_GPG_ERROR(1.50,, AC_MSG_ERROR([libgpg-error was not found]))
AM_CONDITIONAL(USE_GPGRT_CONFIG, [test -n "$GPGRT_CONFIG" \
-a "$ac_cv_path_GPG_ERROR_CONFIG" = no])
#
# Checks for library functions.
#
AC_CHECK_FUNCS([flockfile funlockfile inet_pton stat getaddrinfo \
getrlimit ])
# If we didn't find inet_pton, it might be in -lsocket (which might
# require -lnsl)
if test X"$ac_cv_func_inet_pton" != X"yes" ; then
AC_SEARCH_LIBS([inet_pton],[socket],[],[],[-lnsl])
if test X"$ac_cv_search_inet_pton" != X"no" ; then
AC_DEFINE([HAVE_INET_PTON],1,[Define to 1 if you have `inet_pton'.])
fi
fi
# On some systems (e.g. Solaris) nanosleep requires linking to librl.
# Given that we use nanosleep only as an optimization over a select
# based wait function we want it only if it is available in libc.
_save_libs="$LIBS"
AC_SEARCH_LIBS([nanosleep], [],
[AC_DEFINE(HAVE_NANOSLEEP,1,
[Define to 1 if you have the `nanosleep' function in libc.])])
LIBS="$_save_libs"
# Check for funopen
AC_CHECK_FUNCS(funopen)
if test $ac_cv_func_funopen != yes; then
# No funopen but we can implement that in terms of fopencookie.
AC_CHECK_FUNCS(fopencookie)
if test $ac_cv_func_fopencookie = yes; then
AC_LIBOBJ([funopen])
else
AC_MSG_WARN([
***
*** No implementation of fopencookie or funopen available.
*** The assuan_get_data_fp function won't work; see the
*** manual for details. GnuPG does not require this feature.
***])
fi
fi
AC_REPLACE_FUNCS(isascii)
AC_REPLACE_FUNCS(memrchr)
AC_REPLACE_FUNCS(stpcpy)
AC_CHECK_HEADERS(unistd.h)
AC_REPLACE_FUNCS(setenv)
#
# Check for the getsockopt SO_PEERCRED, etc.
#
AC_CHECK_MEMBER(struct sockpeercred.pid,
[AC_DEFINE(HAVE_STRUCT_SOCKPEERCRED_PID, 1,
Define if struct sockpeercred contains the pid member.)],
[], [#include <sys/types.h>
#include <sys/socket.h> ])
# (Open)Solaris
AC_CHECK_FUNCS([getpeerucred])
# FreeBSD
AC_CHECK_FUNCS([getpeereid])
#
# Extra features
#
build_doc=yes
AC_ARG_ENABLE([doc], AS_HELP_STRING([--disable-doc],
[do not build the documentation]),
build_doc=$enableval, build_doc=yes)
AM_CONDITIONAL([BUILD_DOC], [test "x$build_doc" != xno])
#
# Create the config files.
#
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([m4/Makefile])
AC_CONFIG_FILES([src/Makefile])
AC_CONFIG_FILES([doc/Makefile])
AC_CONFIG_FILES([tests/Makefile])
AC_CONFIG_FILES([src/libassuan-config], [chmod +x src/libassuan-config])
AC_CONFIG_FILES([src/versioninfo.rc])
AC_CONFIG_FILES([src/libassuan.pc])
AC_OUTPUT
echo "
Libassuan v${VERSION} has been configured as follows:
Revision: mym4_revision (mym4_revision_dec)
Platform: $host
"
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index 3f64f7f..f0740c6 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -1,488 +1,495 @@
/* assuan-defs.h - Internal definitions to Assuan
* Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008,
* 2009, 2010 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef ASSUAN_DEFS_H
#define ASSUAN_DEFS_H
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifndef HAVE_W32_SYSTEM
# include <sys/socket.h>
# include <sys/un.h>
#else
# ifdef HAVE_WINSOCK2_H
# /* Avoid inclusion of winsock.h via windows.h. */
# include <winsock2.h>
# endif
# include <windows.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "assuan.h"
#if __GNUC__ > 2
# define ASSUAN_GCC_A_PURE __attribute__ ((__pure__))
#else
# define ASSUAN_GCC_A_PURE
#endif
#ifndef HAVE_W32_SYSTEM
#define DIRSEP_C '/'
#else
#define DIRSEP_C '\\'
#endif
#define LINELENGTH ASSUAN_LINELENGTH
struct cmdtbl_s
{
const char *name;
assuan_handler_t handler;
const char *helpstr;
};
/* The context we use with most functions. */
struct assuan_context_s
{
/* Members managed by the generic routines in assuan.c. */
/* The error source for errors generated from this context. */
gpg_err_source_t err_source;
#ifdef HAVE_W32_SYSTEM
/* The per-context w32 error string. */
char w32_strerror[256];
#endif
/* The allocation hooks. */
struct assuan_malloc_hooks malloc_hooks;
/* Logging callback handler. */
assuan_log_cb_t log_cb;
void *log_cb_data;
void *user_pointer;
/* Context specific flags (cf. assuan_flag_t). */
struct
{
unsigned int no_waitpid : 1;
unsigned int confidential : 1;
unsigned int no_fixsignals : 1;
unsigned int convey_comments : 1;
unsigned int no_logging : 1;
unsigned int force_close : 1;
/* From here, we have internal flags, not defined by assuan_flag_t. */
unsigned int is_socket : 1;
unsigned int is_server : 1; /* Set if this is context belongs to a server */
unsigned int in_inquire : 1; /* Server: inside assuan_inquire */
unsigned int in_process_next : 1;
unsigned int process_complete : 1;
unsigned int in_command : 1;
unsigned int in_inq_cb : 1; /* Client: inquire callback is active */
unsigned int confidential_inquiry : 1; /* Client: inquiry is confidential */
} flags;
/* If set, this is called right before logging an I/O line. */
assuan_io_monitor_t io_monitor;
void *io_monitor_data;
int peercred_valid; /* Whether this structure has valid information. */
struct _assuan_peercred peercred;
/* Now come the members specific to subsystems or engines. FIXME:
This is not developed yet. See below for the legacy members. */
struct
{
void (*release) (assuan_context_t ctx);
/* Routine to read from input_fd. Sets errno on failure. */
ssize_t (*readfnc) (assuan_context_t, void *, size_t);
/* Routine to write to output_fd. Sets errno on failure. */
ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
/* Send a file descriptor. */
gpg_error_t (*sendfd) (assuan_context_t, assuan_fd_t);
/* Receive a file descriptor. */
gpg_error_t (*receivefd) (assuan_context_t, assuan_fd_t *);
} engine;
/* Engine specific or other subsystem members. */
/* assuan-logging.c. Does not require deallocation from us. */
FILE *log_fp;
/* assuan-util.c */
gpg_error_t err_no;
const char *err_str;
/* The following members are used by assuan_inquire_ext. */
gpg_error_t (*inquire_cb) (void *cb_data, gpg_error_t rc,
unsigned char *buf, size_t len);
void *inquire_cb_data;
void *inquire_membuf;
char *hello_line;
char *okay_line; /* See assuan_set_okay_line() */
struct {
assuan_fd_t fd;
int eof;
char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul
is always written at this pos. */
struct {
char line[LINELENGTH];
int linelen ;
int pending; /* i.e. at least one line is available in the attic */
} attic;
} inbound;
struct {
assuan_fd_t fd;
struct {
FILE *fp;
char line[LINELENGTH];
int linelen;
int error;
} data;
} outbound;
int max_accepts; /* If we can not handle more than one connection,
set this to 1, otherwise to -1. */
- /*
+#if GPG_ERROR_VERSION_NUMBER < 0x013200 /* 1.50 */
* Process reference (PID on POSIX, Process Handle on Windows).
+ * Process reference.
* Internal use, only valid for client with pipe.
*/
assuan_pid_t server_proc;
+#else
+ /*
+ * Process reference.
+ * Internal use, only valid for client with pipe.
+ */
+ gpgrt_process_t server_proc;
+#endif
/*
* NOTE: There are two different references for the process:
*
* (1) Process ID which is valid on a system.
* (2) Process handle which is private to the process that get it.
*
* POSIX system only has (1).
* Windows system has both of (1) and (2).
*/
#if defined(HAVE_W32_SYSTEM)
/*
* The process ID of the peer.
*
* client with pipe: Used internally for FD passing.
* client with socket: Used internally for FD passing.
*
* server with pipe: Not valid.
* server with socket: Valid for Cygwin Unix domain socket emulation.
*
*/
int process_id;
#else
/*
* The pid of the peer.
*
* client with pipe: Not valid.
* client with socket: Not valid.
*
* server with pipe: Valid (by env _assuan_pipe_connect_pid).
* server with socket: Valid on a system with SO_PEERCRED/etc.
*
*/
pid_t pid;
#endif
assuan_fd_t listen_fd; /* The fd we are listening on (used by
socket servers) */
assuan_sock_nonce_t listen_nonce; /* Used with LISTEN_FD. */
assuan_fd_t connected_fd; /* helper */
/* Used for Unix domain sockets. */
struct sockaddr_un myaddr;
struct sockaddr_un serveraddr;
/* Structure used for unix domain sockets. */
struct {
assuan_fd_t pendingfds[5]; /* Array to save received descriptors. */
int pendingfdscount; /* Number of received descriptors. */
} uds;
gpg_error_t (*accept_handler)(assuan_context_t);
void (*finish_handler)(assuan_context_t);
struct cmdtbl_s *cmdtbl;
size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */
/* The name of the command currently processed by a command handler.
This is a pointer into CMDTBL. NULL if not in a command
handler. */
const char *current_cmd_name;
assuan_handler_t bye_notify_fnc;
assuan_handler_t reset_notify_fnc;
assuan_handler_t cancel_notify_fnc;
gpg_error_t (*option_handler_fnc)(assuan_context_t,const char*, const char*);
assuan_handler_t input_notify_fnc;
assuan_handler_t output_notify_fnc;
/* This function is called right before a command handler is called. */
gpg_error_t (*pre_cmd_notify_fnc)(assuan_context_t, const char *cmd);
/* This function is called right after a command has been processed.
It may be used to command related cleanup. */
void (*post_cmd_notify_fnc)(assuan_context_t, gpg_error_t);
assuan_fd_t input_fd; /* Set by the INPUT command. */
assuan_fd_t output_fd; /* Set by the OUTPUT command. */
};
/* Generate an error code specific to a context. */
static GPG_ERR_INLINE gpg_error_t
_assuan_error (assuan_context_t ctx, gpg_err_code_t errcode)
{
return gpg_err_make (ctx?ctx->err_source: GPG_ERR_SOURCE_ASSUAN, errcode);
}
/* Release all resources associated with an engine operation. */
void _assuan_reset (assuan_context_t ctx);
/* Default log handler. */
int _assuan_log_handler (assuan_context_t ctx, void *hook,
unsigned int cat, const char *msg);
/* Manage memory specific to a context. */
void *_assuan_malloc (assuan_context_t ctx, size_t cnt);
void *_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt);
void *_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize);
void _assuan_free (assuan_context_t ctx, void *ptr);
/* System hooks. */
void _assuan_usleep (assuan_context_t ctx, unsigned int usec);
int _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
int _assuan_close (assuan_context_t ctx, assuan_fd_t fd);
int _assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd);
ssize_t _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer,
size_t size);
ssize_t _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size);
int _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd,
assuan_msghdr_t msg, int flags);
int _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd,
assuan_msghdr_t msg, int flags);
-int _assuan_spawn (assuan_context_t ctx, assuan_pid_t *r_pid, const char *name,
- const char *argv[],
+int _assuan_spawn (assuan_context_t ctx, const char *name, const char *argv[],
assuan_fd_t fd_in, assuan_fd_t fd_out,
assuan_fd_t *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
+ void (*atfork) (void *opaque),
void *atforkvalue, unsigned int flags);
assuan_pid_t _assuan_waitpid (assuan_context_t ctx, assuan_pid_t pid,
int nowait, int *status, int options);
int _assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2]);
assuan_fd_t _assuan_socket (assuan_context_t ctx, int namespace,
int style, int protocol);
int _assuan_connect (assuan_context_t ctx, assuan_fd_t sock,
struct sockaddr *addr, socklen_t length);
void __assuan_usleep (assuan_context_t ctx, unsigned int usec);
int __assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
int __assuan_close (assuan_context_t ctx, assuan_fd_t fd);
int __assuan_spawn (assuan_context_t ctx, assuan_pid_t *r_pid, const char *name,
const char **argv, assuan_fd_t fd_in, assuan_fd_t fd_out,
assuan_fd_t *fd_child_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue, unsigned int flags);
int __assuan_socketpair (assuan_context_t ctx, int _namespace, int style,
int protocol, assuan_fd_t filedes[2]);
assuan_fd_t __assuan_socket (assuan_context_t ctx, int _namespace,
int style, int protocol);
int __assuan_connect (assuan_context_t ctx, assuan_fd_t sock,
struct sockaddr *addr, socklen_t length);
ssize_t __assuan_read (assuan_context_t ctx, assuan_fd_t fd,
void *buffer, size_t size);
ssize_t __assuan_write (assuan_context_t ctx, assuan_fd_t fd,
const void *buffer, size_t size);
int __assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd,
assuan_msghdr_t msg, int flags);
int __assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd,
const assuan_msghdr_t msg, int flags);
assuan_pid_t __assuan_waitpid (assuan_context_t ctx, assuan_pid_t pid,
int nowait, int *status, int options);
/*-- assuan-pipe-server.c --*/
void _assuan_release_context (assuan_context_t ctx);
/*-- assuan-uds.c --*/
void _assuan_uds_close_fds (assuan_context_t ctx);
void _assuan_uds_deinit (assuan_context_t ctx);
void _assuan_init_uds_io (assuan_context_t ctx);
/*-- assuan-handler.c --*/
gpg_error_t _assuan_register_std_commands (assuan_context_t ctx);
/*-- assuan-buffer.c --*/
gpg_error_t _assuan_read_line (assuan_context_t ctx);
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie);
gpg_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len);
/*-- client.c --*/
gpg_error_t _assuan_read_from_server (assuan_context_t ctx,
assuan_response_t *okay, int *off,
int convey_comments);
/*-- assuan-error.c --*/
/*-- assuan-inquire.c --*/
gpg_error_t _assuan_inquire_ext_cb (assuan_context_t ctx);
void _assuan_inquire_release (assuan_context_t ctx);
/* Check if ERR means EAGAIN. */
int _assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err);
#define set_error(c,e,t) \
assuan_set_error ((c), _assuan_error (c,e), (t))
#ifdef HAVE_W32_SYSTEM
char *_assuan_w32_strerror (assuan_context_t ctx, int ec);
gpg_error_t w32_fdpass_send (assuan_context_t ctx, assuan_fd_t fd);
gpg_error_t w32_fdpass_recv (assuan_context_t ctx, assuan_fd_t *fd);
#endif /*HAVE_W32_SYSTEM*/
/*-- assuan-logging.c --*/
void _assuan_init_log_envvars (void);
void _assuan_log_control_channel (assuan_context_t ctx, int outbound,
const char *string,
const void *buffer1, size_t length1,
const void *buffer2, size_t length2);
/*-- assuan-io.c --*/
ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size);
ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer,
size_t size);
/*-- assuan-socket.c --*/
assuan_fd_t _assuan_sock_new (assuan_context_t ctx, int domain, int type,
int proto);
int _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen);
int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen);
int _assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
int *r_redirected);
int _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
int addrlen, assuan_sock_nonce_t *nonce);
int _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
assuan_sock_nonce_t *nonce);
#ifdef HAVE_W32_SYSTEM
wchar_t *_assuan_utf8_to_wchar (const char *string);
int _assuan_sock_wsa2errno (int err);
#endif
#ifdef HAVE_FOPENCOOKIE
/* We have to implement funopen in terms of glibc's fopencookie. */
FILE *_assuan_funopen(void *cookie,
cookie_read_function_t *readfn,
cookie_write_function_t *writefn,
cookie_seek_function_t *seekfn,
cookie_close_function_t *closefn);
#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
#endif /*HAVE_FOPENCOOKIE*/
/*-- sysutils.c --*/
const char *_assuan_sysutils_blurb (void);
/* Prototypes for replacement functions. */
#ifndef HAVE_MEMRCHR
void *memrchr (const void *block, int c, size_t size);
#endif
#ifndef HAVE_STPCPY
char *stpcpy (char *dest, const char *src);
#endif
#ifndef HAVE_SETENV
#define setenv _assuan_setenv
#define unsetenv _assuan_unsetenv
#define clearenv _assuan_clearenv
int setenv (const char *name, const char *value, int replace);
#endif
#ifndef HAVE_PUTC_UNLOCKED
int putc_unlocked (int c, FILE *stream);
#endif
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
/* To avoid that a compiler optimizes memset calls away, these macros
can be used. */
#define wipememory2(_ptr,_set,_len) do { \
volatile char *_vptr=(volatile char *)(_ptr); \
size_t _vlen=(_len); \
while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
} while(0)
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
#if HAVE_W64_SYSTEM
# define SOCKET2HANDLE(s) ((void *)(s))
# define HANDLE2SOCKET(h) ((uintptr_t)(h))
#elif HAVE_W32_SYSTEM
# define SOCKET2HANDLE(s) ((void *)(s))
# define HANDLE2SOCKET(h) ((unsigned int)(h))
#else
# define SOCKET2HANDLE(s) (s)
# define HANDLE2SOCKET(h) (h)
#endif
void _assuan_client_finish (assuan_context_t ctx);
void _assuan_client_release (assuan_context_t ctx);
void _assuan_server_finish (assuan_context_t ctx);
void _assuan_server_release (assuan_context_t ctx);
/* Encode the C formatted string SRC and return the malloc'ed result. */
char *_assuan_encode_c_string (assuan_context_t ctx, const char *src);
void _assuan_pre_syscall (void);
void _assuan_post_syscall (void);
#endif /*ASSUAN_DEFS_H*/
diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c
index 9669cb3..ec2800f 100644
--- a/src/assuan-pipe-connect.c
+++ b/src/assuan-pipe-connect.c
@@ -1,490 +1,500 @@
/* assuan-pipe-connect.c - Establish a pipe connection (client)
* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010,
* 2011 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* On Windows systems signal.h is not needed and even not supported on
WindowsCE. */
#ifndef HAVE_DOSISH_SYSTEM
# include <signal.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifndef HAVE_W32_SYSTEM
# include <sys/wait.h>
#else
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
#endif
#include "assuan-defs.h"
#include "debug.h"
/* Hacks for Slowaris. */
#ifndef PF_LOCAL
# ifdef PF_UNIX
# define PF_LOCAL PF_UNIX
# else
# define PF_LOCAL AF_UNIX
# endif
#endif
#ifndef AF_LOCAL
# define AF_LOCAL AF_UNIX
#endif
/* This should be called to make sure that SIGPIPE gets ignored. */
static void
fix_signals (void)
{
#ifndef HAVE_DOSISH_SYSTEM /* No SIGPIPE for these systems. */
static int fixed_signals;
if (!fixed_signals)
{
struct sigaction act;
sigaction (SIGPIPE, NULL, &act);
if (act.sa_handler == SIG_DFL)
{
act.sa_handler = SIG_IGN;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGPIPE, &act, NULL);
}
fixed_signals = 1;
/* FIXME: This is not MT safe */
}
#endif /*HAVE_DOSISH_SYSTEM*/
}
/* Helper for pipe_connect. */
static gpg_error_t
initial_handshake (assuan_context_t ctx)
{
assuan_response_t response;
int off;
gpg_error_t err;
err = _assuan_read_from_server (ctx, &response, &off, 0);
if (err)
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx,
"can't connect server: %s", gpg_strerror (err));
else if (response == ASSUAN_RESPONSE_OK)
{
#if defined(HAVE_W32_SYSTEM)
const char *line = ctx->inbound.line + off;
int process_id = -1;
/* Parse the message: OK ..., process %i */
line = strchr (line, ',');
if (line)
{
line = strchr (line + 1, ' ');
if (line)
{
line = strchr (line + 1, ' ');
if (line)
process_id = atoi (line + 1);
}
}
if (process_id != -1)
ctx->process_id = process_id;
#else
;
#endif
}
else
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx,
"can't connect server: `%s'", ctx->inbound.line);
err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
}
return err;
}
struct at_pipe_fork
{
void (*user_atfork) (void *opaque, int reserved);
void *user_atforkvalue;
pid_t parent_pid;
};
static void
-at_pipe_fork_cb (void *opaque, int reserved)
+at_pipe_fork_cb (void *opaque)
{
struct at_pipe_fork *atp = opaque;
if (atp->user_atfork)
- atp->user_atfork (atp->user_atforkvalue, reserved);
+ atp->user_atfork (atp->user_atforkvalue, 0);
#ifndef HAVE_W32_SYSTEM
{
char mypidstr[50];
/* We store our parents pid in the environment so that the execed
assuan server is able to read the actual pid of the client.
The server can't use getppid because it might have been double
forked before the assuan server has been initialized. */
sprintf (mypidstr, "%lu", (unsigned long) atp->parent_pid);
setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
/* Make sure that we never pass a connection fd variable when
using a simple pipe. */
unsetenv ("_assuan_connection_fd");
}
#endif
}
static gpg_error_t
pipe_connect (assuan_context_t ctx,
const char *name, const char **argv,
assuan_fd_t *fd_child_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue, unsigned int flags)
{
gpg_error_t rc;
assuan_fd_t rp[2];
assuan_fd_t wp[2];
- assuan_pid_t pid;
int res;
struct at_pipe_fork atp;
unsigned int spawn_flags;
atp.user_atfork = atfork;
atp.user_atforkvalue = atforkvalue;
atp.parent_pid = getpid ();
if (!ctx || !name || !argv || !argv[0])
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (! ctx->flags.no_fixsignals)
fix_signals ();
if (_assuan_pipe (ctx, rp, 1) < 0)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
if (_assuan_pipe (ctx, wp, 0) < 0)
{
_assuan_close (ctx, rp[0]);
_assuan_close_inheritable (ctx, rp[1]);
return _assuan_error (ctx, gpg_err_code_from_syserror ());
}
spawn_flags = 0;
if (flags & ASSUAN_PIPE_CONNECT_DETACHED)
spawn_flags |= ASSUAN_SPAWN_DETACHED;
/* FIXME: Use atfork handler that closes child fds on Unix. */
- res = _assuan_spawn (ctx, &pid, name, argv, wp[0], rp[1],
+ res = _assuan_spawn (ctx, name, argv, wp[0], rp[1],
fd_child_list, at_pipe_fork_cb, &atp, spawn_flags);
if (res < 0)
{
rc = gpg_err_code_from_syserror ();
_assuan_close (ctx, rp[0]);
_assuan_close_inheritable (ctx, rp[1]);
_assuan_close_inheritable (ctx, wp[0]);
_assuan_close (ctx, wp[1]);
return _assuan_error (ctx, rc);
}
+ /* The fork feature on POSIX when NAME==NULL. */
+ if (!name)
+ {
+ /* Set ARGV[0] for backward compatibility. */
+ if (ctx->server_proc == NULL)
+ {
+ /* If this is the server child process, exit early. */
+ argv[0] = "server";
+ return 0;
+ }
+ else
+ argv[0] = "client";
+ }
+
/* Close the stdin/stdout child fds in the parent. */
_assuan_close_inheritable (ctx, rp[1]);
_assuan_close_inheritable (ctx, wp[0]);
ctx->engine.release = _assuan_client_release;
ctx->engine.readfnc = _assuan_simple_read;
ctx->engine.writefnc = _assuan_simple_write;
#ifdef HAVE_W32_SYSTEM
ctx->engine.sendfd = w32_fdpass_send;
#else
ctx->engine.sendfd = NULL;
#endif
ctx->engine.receivefd = NULL;
ctx->finish_handler = _assuan_client_finish;
ctx->max_accepts = 1;
ctx->accept_handler = NULL;
ctx->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
ctx->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
- ctx->server_proc = pid;
rc = initial_handshake (ctx);
if (rc)
_assuan_reset (ctx);
return rc;
}
/* FIXME: For socketpair_connect, use spawn function and add atfork
handler to do the right thing. Instead of stdin and stdout, we
extend the fd_child_list by fds[1]. */
#ifndef HAVE_W32_SYSTEM
struct at_socketpair_fork
{
assuan_fd_t peer_fd;
void (*user_atfork) (void *opaque, int reserved);
void *user_atforkvalue;
pid_t parent_pid;
};
static void
-at_socketpair_fork_cb (void *opaque, int reserved)
+at_socketpair_fork_cb (void *opaque)
{
struct at_socketpair_fork *atp = opaque;
if (atp->user_atfork)
- atp->user_atfork (atp->user_atforkvalue, reserved);
+ atp->user_atfork (atp->user_atforkvalue, 0);
#ifndef HAVE_W32_SYSTEM
{
char mypidstr[50];
/* We store our parents pid in the environment so that the execed
assuan server is able to read the actual pid of the client.
The server can't use getppid because it might have been double
forked before the assuan server has been initialized. */
sprintf (mypidstr, "%lu", (unsigned long) atp->parent_pid);
setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
/* Now set the environment variable used to convey the
connection's file descriptor. */
sprintf (mypidstr, "%d", atp->peer_fd);
if (setenv ("_assuan_connection_fd", mypidstr, 1))
_exit (4);
}
#endif
}
/* This function is similar to pipe_connect but uses a socketpair and
sets the I/O up to use sendmsg/recvmsg. */
static gpg_error_t
-socketpair_connect (assuan_context_t ctx,
- const char *name, const char **argv,
+socketpair_connect (assuan_context_t ctx, const char *name, const char **argv,
assuan_fd_t *fd_child_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue)
{
gpg_error_t err;
int idx;
int fds[2];
char mypidstr[50];
- pid_t pid;
int *child_fds = NULL;
int child_fds_cnt = 0;
struct at_socketpair_fork atp;
int rc;
TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx,
"name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)",
atfork, atforkvalue);
atp.user_atfork = atfork;
atp.user_atforkvalue = atforkvalue;
atp.parent_pid = getpid ();
if (!ctx
|| (name && (!argv || !argv[0]))
|| (!name && !argv))
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (! ctx->flags.no_fixsignals)
fix_signals ();
sprintf (mypidstr, "%lu", (unsigned long)getpid ());
if (fd_child_list)
while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD)
child_fds_cnt++;
child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int));
if (! child_fds)
return TRACE_ERR (gpg_err_code_from_syserror ());
child_fds[1] = ASSUAN_INVALID_FD;
if (fd_child_list)
memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int));
if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds))
{
TRACE_LOG1 ("socketpair failed: %s", strerror (errno));
_assuan_free (ctx, child_fds);
return TRACE_ERR (GPG_ERR_ASS_GENERAL);
}
atp.peer_fd = fds[1];
child_fds[0] = fds[1];
- rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD,
+ rc = _assuan_spawn (ctx, name, argv, ASSUAN_INVALID_FD,
ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb,
&atp, 0);
if (rc < 0)
{
err = gpg_err_code_from_syserror ();
_assuan_close (ctx, fds[0]);
_assuan_close (ctx, fds[1]);
_assuan_free (ctx, child_fds);
return TRACE_ERR (err);
}
/* For W32, the user needs to know the server-local names of the
inherited handles. Return them here. Note that the translation
of the peer socketpair fd (fd_child_list[0]) must be done by the
wrapper program based on the environment variable
_assuan_connection_fd. */
if (fd_child_list)
{
for (idx = 0; fd_child_list[idx] != -1; idx++)
/* We add 1 to skip over the socketpair end. */
fd_child_list[idx] = child_fds[idx + 1];
}
_assuan_free (ctx, child_fds);
- /* If this is the server child process, exit early. */
- if (! name && (*argv)[0] == 's')
+ /* The fork feature on POSIX when NAME==NULL. */
+ if (!name)
{
- _assuan_close (ctx, fds[0]);
- return 0;
+ /* Set ARGV[0] for backward compatibility. */
+ if (ctx->server_proc == NULL)
+ {
+ /* If this is the server child process, exit early. */
+ argv[0] = "server";
+ return 0;
+ }
+ else
+ argv[0] = "client";
}
_assuan_close (ctx, fds[1]);
ctx->engine.release = _assuan_client_release;
ctx->finish_handler = _assuan_client_finish;
ctx->max_accepts = 1;
ctx->inbound.fd = fds[0];
ctx->outbound.fd = fds[0];
_assuan_init_uds_io (ctx);
err = initial_handshake (ctx);
if (err)
_assuan_reset (ctx);
return err;
}
#endif /*!HAVE_W32_SYSTEM*/
/* Connect to a server over a full-duplex socket (i.e. created by
socketpair), creating the assuan context and returning it in CTX.
The server filename is NAME, the argument vector in ARGV.
FD_CHILD_LIST is a -1 terminated list of file descriptors not to
close in the child. ATFORK is called in the child right after the
fork; ATFORKVALUE is passed as the first argument and 0 is passed
as the second argument. The ATFORK function should only act if the
second value is 0.
FLAGS is a bit vector and controls how the function acts:
Bit 0: If cleared a simple pipe based server is expected and the
function behaves similar to `assuan_pipe_connect'.
If set a server based on full-duplex pipes is expected. Such
pipes are usually created using the `socketpair' function.
It also enables features only available with such servers.
Bit 7: If set and there is a need to start the server it will be
started as a background process. This flag is useful under
W32 systems, so that no new console is created and pops up a
console window when starting the server
If NAME is NULL, no exec is done but the same process is continued.
However all file descriptors are closed and some special
environment variables are set. To let the caller detect whether the
child or the parent continues, the child returns "client" or
"server" in *ARGV (but it is sufficient to check only the first
character). This feature is only available on POSIX platforms. */
gpg_error_t
assuan_pipe_connect (assuan_context_t ctx,
const char *name, const char *argv[],
assuan_fd_t *fd_child_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue, unsigned int flags)
{
TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect", ctx,
"name=%s, flags=0x%x", name ? name : "(null)", flags);
#ifndef HAVE_W32_SYSTEM
if (flags & ASSUAN_PIPE_CONNECT_FDPASSING)
return socketpair_connect (ctx, name, argv, fd_child_list,
atfork, atforkvalue);
else
#endif
return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue,
flags);
}
gpg_error_t
assuan_pipe_wait_server_termination (assuan_context_t ctx, int *status,
int no_hang)
{
- assuan_pid_t pid;
+ gpg_err_code_t ec;
- if (ctx->server_proc == -1)
+ if (ctx->server_proc == NULL)
return _assuan_error (ctx, GPG_ERR_NO_SERVICE);
- pid = _assuan_waitpid (ctx, ctx->server_proc, 0, status, no_hang);
- if (pid == -1)
- return _assuan_error (ctx, gpg_err_code_from_syserror ());
- else if (pid == 0)
- return _assuan_error (ctx, GPG_ERR_TIMEOUT);
+ ec = gpgrt_process_wait (ctx->server_proc, !no_hang);
+
+ if (ec)
+ return _assuan_error (ctx, ec);
- /* We did wait on the process already, so, not any more. */
- ctx->flags.no_waitpid = 1;
return 0;
}
gpg_error_t
assuan_pipe_kill_server (assuan_context_t ctx)
{
- if (ctx->server_proc == -1)
+ if (ctx->server_proc == NULL)
; /* No pid available can't send a kill. */
else
{
_assuan_pre_syscall ();
-#ifdef HAVE_W32_SYSTEM
- TerminateProcess ((HANDLE)ctx->server_proc, 1);
-#else
- kill (ctx->server_proc, SIGINT);
-#endif
+ gpgrt_process_terminate (ctx->server_proc);
_assuan_post_syscall ();
}
return 0;
}
diff --git a/src/assuan.c b/src/assuan.c
index b72df65..44f4c23 100644
--- a/src/assuan.c
+++ b/src/assuan.c
@@ -1,339 +1,339 @@
/* assuan.c - Global interface (not specific to context).
* Copyright (C) 2009 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2012, 2013 g10 Code GmbH
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "assuan-defs.h"
#include "debug.h"
#define digitp(a) ((a) >= '0' && (a) <= '9')
/* Global default state. */
/* Functions called before and after blocking syscalls. */
static void (*pre_syscall_func) (void);
static void (*post_syscall_func) (void);
/* Variable to see if functions above are initialized. */
static int _assuan_syscall_func_initialized;
/* The default error source gor generated error codes. */
static gpg_err_source_t _assuan_default_err_source = GPG_ERR_SOURCE_USER_1;
/* The default memory management functions. */
static struct assuan_malloc_hooks _assuan_default_malloc_hooks =
{ malloc, realloc, free };
/* The default logging handler. */
static assuan_log_cb_t _assuan_default_log_cb = _assuan_log_handler;
static void *_assuan_default_log_cb_data = NULL;
/* Set the default gpg error source. */
void
assuan_set_gpg_err_source (gpg_err_source_t errsource)
{
_assuan_default_err_source = errsource;
}
/* Get the default gpg error source. */
gpg_err_source_t
assuan_get_gpg_err_source (void)
{
return _assuan_default_err_source;
}
/* Set the default malloc hooks. */
void
assuan_set_malloc_hooks (assuan_malloc_hooks_t malloc_hooks)
{
_assuan_default_malloc_hooks = *malloc_hooks;
}
/* Get the default malloc hooks. */
assuan_malloc_hooks_t
assuan_get_malloc_hooks (void)
{
return &_assuan_default_malloc_hooks;
}
/* Set the default log callback handler. */
void
assuan_set_log_cb (assuan_log_cb_t log_cb, void *log_cb_data)
{
_assuan_default_log_cb = log_cb;
_assuan_default_log_cb_data = log_cb_data;
_assuan_init_log_envvars ();
}
/* Get the default log callback handler. */
void
assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data)
{
*log_cb = _assuan_default_log_cb;
*log_cb_data = _assuan_default_log_cb_data;
}
gpg_error_t
assuan_control (enum assuan_ctl_cmds cmd, void *arg)
{
gpg_error_t err = 0;
(void)arg;
switch (cmd)
{
case ASSUAN_CONTROL_NOP:
default:
/* Nothing to do. */
break;
case ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP:
gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
_assuan_syscall_func_initialized = 1;
break;
}
return err;
}
/* Used before blocking system calls. */
void
_assuan_pre_syscall (void)
{
again:
if (pre_syscall_func)
pre_syscall_func ();
else if (!_assuan_syscall_func_initialized)
{
gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
_assuan_syscall_func_initialized = 1;
goto again;
}
}
/* Used after blocking system calls. */
void
_assuan_post_syscall (void)
{
if (post_syscall_func)
post_syscall_func ();
}
/* Create a new Assuan context. The initial parameters are all needed
in the creation of the context. */
gpg_error_t
assuan_new_ext (assuan_context_t *r_ctx, gpg_err_source_t err_source,
assuan_malloc_hooks_t malloc_hooks, assuan_log_cb_t log_cb,
void *log_cb_data)
{
struct assuan_context_s wctx;
assuan_context_t ctx;
/* Set up a working context so we can use standard functions. */
memset (&wctx, 0, sizeof (wctx));
wctx.err_source = err_source;
wctx.malloc_hooks = *malloc_hooks;
wctx.log_cb = log_cb;
wctx.log_cb_data = log_cb_data;
/* Need a new block for the trace macros to work. */
{
TRACE_BEG8 (&wctx, ASSUAN_LOG_CTX, "assuan_new_ext", r_ctx,
"err_source = %i (%s), malloc_hooks = %p (%p, %p, %p), "
"log_cb = %p, log_cb_data = %p", err_source,
gpg_strsource (err_source), malloc_hooks, malloc_hooks->malloc,
malloc_hooks->realloc, malloc_hooks->free, log_cb, log_cb_data);
*r_ctx = NULL;
ctx = _assuan_malloc (&wctx, sizeof (*ctx));
if (!ctx)
return TRACE_ERR (gpg_err_code_from_syserror ());
memcpy (ctx, &wctx, sizeof (*ctx));
/* FIXME: Delegate to subsystems/engines, as the FDs are not our
responsibility (we don't deallocate them, for example). */
ctx->input_fd = ASSUAN_INVALID_FD;
ctx->output_fd = ASSUAN_INVALID_FD;
ctx->inbound.fd = ASSUAN_INVALID_FD;
ctx->outbound.fd = ASSUAN_INVALID_FD;
ctx->listen_fd = ASSUAN_INVALID_FD;
#if defined(HAVE_W32_SYSTEM)
ctx->process_id = -1;
#else
ctx->pid = ASSUAN_INVALID_PID;
#endif
- ctx->server_proc = -1;
+ ctx->server_proc = NULL;
*r_ctx = ctx;
return TRACE_SUC1 ("ctx=%p", ctx);
}
}
/* Create a new context with default arguments. */
gpg_error_t
assuan_new (assuan_context_t *r_ctx)
{
return assuan_new_ext (r_ctx, _assuan_default_err_source,
&_assuan_default_malloc_hooks,
_assuan_default_log_cb,
_assuan_default_log_cb_data);
}
/* Release all resources associated with an engine operation. */
void
_assuan_reset (assuan_context_t ctx)
{
if (ctx->engine.release)
{
(*ctx->engine.release) (ctx);
ctx->engine.release = NULL;
}
/* FIXME: Clean standard commands */
}
/* Release all resources associated with the given context. */
void
assuan_release (assuan_context_t ctx)
{
if (! ctx)
return;
TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx);
_assuan_reset (ctx);
/* None of the members that are our responsibility requires
deallocation. To avoid sensitive data in the line buffers we
wipe them out, though. Note that we can't wipe the entire
context because it also has a pointer to the actual free(). */
wipememory (&ctx->inbound, sizeof ctx->inbound);
wipememory (&ctx->outbound, sizeof ctx->outbound);
_assuan_free (ctx, ctx);
}
/*
Version number stuff.
*/
static const char*
parse_version_number (const char *s, int *number)
{
int val = 0;
if (*s == '0' && digitp (s[1]))
return NULL; /* Leading zeros are not allowed. */
for (; digitp (*s); s++)
{
val *= 10;
val += *s - '0';
}
*number = val;
return val < 0 ? NULL : s;
}
static const char *
parse_version_string (const char *s, int *major, int *minor, int *micro)
{
s = parse_version_number (s, major);
if (!s || *s != '.')
return NULL;
s++;
s = parse_version_number (s, minor);
if (!s || *s != '.')
return NULL;
s++;
s = parse_version_number (s, micro);
if (!s)
return NULL;
return s; /* Patchlevel. */
}
static const char *
compare_versions (const char *my_version, const char *req_version)
{
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl, *rq_plvl;
if (!req_version)
return my_version;
if (!my_version)
return NULL;
my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
if (!my_plvl)
return NULL; /* Very strange: our own version is bogus. */
rq_plvl = parse_version_string(req_version,
&rq_major, &rq_minor, &rq_micro);
if (!rq_plvl)
return NULL; /* Requested version string is invalid. */
if (my_major > rq_major
|| (my_major == rq_major && my_minor > rq_minor)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro > rq_micro)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro == rq_micro))
{
return my_version;
}
return NULL;
}
/*
* Check that the the version of the library is at minimum REQ_VERSION
* and return the actual version string; return NULL if the condition
* is not met. If NULL is passed to this function, no check is done
* and the version string is simply returned.
*/
const char *
assuan_check_version (const char *req_version)
{
if (req_version && req_version[0] == 1 && req_version[1] == 1)
return _assuan_sysutils_blurb ();
return compare_versions (PACKAGE_VERSION, req_version);
}
diff --git a/src/client.c b/src/client.c
index 410f940..afb9abc 100644
--- a/src/client.c
+++ b/src/client.c
@@ -1,349 +1,348 @@
/* client.c - Functions common to all clients.
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include "assuan-defs.h"
#include "debug.h"
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
void
_assuan_client_finish (assuan_context_t ctx)
{
if (ctx->inbound.fd != ASSUAN_INVALID_FD)
{
_assuan_close (ctx, ctx->inbound.fd);
if (ctx->inbound.fd == ctx->outbound.fd)
ctx->outbound.fd = ASSUAN_INVALID_FD;
ctx->inbound.fd = ASSUAN_INVALID_FD;
}
if (ctx->outbound.fd != ASSUAN_INVALID_FD)
{
_assuan_close (ctx, ctx->outbound.fd);
ctx->outbound.fd = ASSUAN_INVALID_FD;
}
- if (ctx->server_proc != -1)
+ if (ctx->server_proc != NULL)
{
- if (!ctx->flags.is_socket)
- _assuan_waitpid (ctx, ctx->server_proc, ctx->flags.no_waitpid, NULL, 0);
- ctx->server_proc = -1;
+ gpgrt_process_release (ctx->server_proc);
+ ctx->server_proc = NULL;
}
_assuan_uds_deinit (ctx);
}
/* Disconnect and release the context CTX. */
void
_assuan_client_release (assuan_context_t ctx)
{
assuan_write_line (ctx, "BYE");
_assuan_client_finish (ctx);
}
/* This function also does deescaping for data lines. */
gpg_error_t
assuan_client_read_response (assuan_context_t ctx,
char **line_r, int *linelen_r)
{
gpg_error_t rc;
char *line = NULL;
int linelen = 0;
*line_r = NULL;
*linelen_r = 0;
do
{
do
{
rc = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (ctx, rc));
if (rc)
return rc;
line = ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (!linelen);
/* For data lines, we deescape immediately. The user will never
have to worry about it. */
if (linelen >= 1 && line[0] == 'D' && line[1] == ' ')
{
char *s, *d;
for (s=d=line; linelen; linelen--)
{
if (*s == '%' && linelen > 2)
{ /* handle escaping */
s++;
*d++ = xtoi_2 (s);
s += 2;
linelen -= 2;
}
else
*d++ = *s++;
}
*d = 0; /* add a hidden string terminator */
linelen = d - line;
ctx->inbound.linelen = linelen;
}
*line_r = line;
*linelen_r = linelen;
return 0;
}
gpg_error_t
assuan_client_parse_response (assuan_context_t ctx, char *line, int linelen,
assuan_response_t *response, int *off)
{
*response = ASSUAN_RESPONSE_ERROR;
*off = 0;
if (linelen >= 1
&& line[0] == 'D' && line[1] == ' ')
{
*response = ASSUAN_RESPONSE_DATA; /* data line */
*off = 2;
}
else if (linelen >= 1
&& line[0] == 'S'
&& (line[1] == '\0' || line[1] == ' '))
{
*response = ASSUAN_RESPONSE_STATUS;
*off = 1;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
{
*response = ASSUAN_RESPONSE_OK;
*off = 2;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
*response = ASSUAN_RESPONSE_ERROR;
*off = 3;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
*response = ASSUAN_RESPONSE_INQUIRE;
*off = 7;
while (line[*off] == ' ')
++*off;
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
&& (line[3] == '\0' || line[3] == ' '))
{
*response = ASSUAN_RESPONSE_END;
*off = 3;
}
else if (linelen >= 1 && line[0] == '#')
{
*response = ASSUAN_RESPONSE_COMMENT;
*off = 1;
}
else
return _assuan_error (ctx, GPG_ERR_ASS_INV_RESPONSE);
return 0;
}
gpg_error_t
_assuan_read_from_server (assuan_context_t ctx, assuan_response_t *response,
int *off, int convey_comments)
{
gpg_error_t rc;
char *line;
int linelen;
do
{
*response = ASSUAN_RESPONSE_ERROR;
*off = 0;
rc = assuan_client_read_response (ctx, &line, &linelen);
if (!rc)
rc = assuan_client_parse_response (ctx, line, linelen, response, off);
}
while (!rc && *response == ASSUAN_RESPONSE_COMMENT && !convey_comments);
return rc;
}
/**
* assuan_transact:
* @ctx: The Assuan context
* @command: Command line to be send to the server
* @data_cb: Callback function for data lines
* @data_cb_arg: first argument passed to @data_cb
* @inquire_cb: Callback function for a inquire response
* @inquire_cb_arg: first argument passed to @inquire_cb
* @status_cb: Callback function for a status response
* @status_cb_arg: first argument passed to @status_cb
*
* FIXME: Write documentation
*
* Return value: 0 on success or an error code. The error code may be
* the one one returned by the server via error lines or from the
* callback functions. Take care: If a callback returns an error
* this function returns immediately with this error.
**/
gpg_error_t
assuan_transact (assuan_context_t ctx,
const char *command,
gpg_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
gpg_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
gpg_error_t (*status_cb)(void*, const char *),
void *status_cb_arg)
{
gpg_error_t rc;
assuan_response_t response;
int off;
char *line;
int linelen;
rc = assuan_write_line (ctx, command);
if (rc)
return rc;
if (*command == '#' || !*command)
return 0; /* Don't expect a response for a comment line. */
again:
rc = _assuan_read_from_server (ctx, &response, &off,
ctx->flags.convey_comments);
if (rc)
return rc; /* error reading from server */
line = ctx->inbound.line + off;
linelen = ctx->inbound.linelen - off;
if (response == ASSUAN_RESPONSE_ERROR)
rc = atoi (line);
else if (response == ASSUAN_RESPONSE_DATA)
{
if (!data_cb)
rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB);
else
{
rc = data_cb (data_cb_arg, line, linelen);
if (ctx->flags.confidential)
wipememory (ctx->inbound.line, LINELENGTH);
if (!rc)
goto again;
}
}
else if (response == ASSUAN_RESPONSE_INQUIRE)
{
if (!inquire_cb)
{
assuan_write_line (ctx, "END"); /* get out of inquire mode */
_assuan_read_from_server (ctx, &response, &off, 0); /* dummy read */
rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB);
}
else
{
ctx->flags.confidential_inquiry = 0;
ctx->flags.in_inq_cb = 1;
rc = inquire_cb (inquire_cb_arg, line);
if (!rc)
rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
else
{ /* Flush and send CAN. */
/* Note that in this error case we don't want to return
an error code from sending the cancel. The dummy
read is to remove the response from the server which
we are not interested in. */
assuan_send_data (ctx, NULL, 1);
_assuan_read_from_server (ctx, &response, &off, 0);
}
if (ctx->flags.confidential_inquiry)
wipememory (ctx->outbound.data.line, LINELENGTH);
ctx->flags.confidential_inquiry = 0;
ctx->flags.in_inq_cb = 0;
if (!rc)
goto again;
}
}
else if (response == ASSUAN_RESPONSE_STATUS)
{
if (status_cb)
rc = status_cb (status_cb_arg, line);
if (!rc)
goto again;
}
else if (response == ASSUAN_RESPONSE_COMMENT && ctx->flags.convey_comments)
{
line -= off; /* Send line with the comment marker. */
if (status_cb)
rc = status_cb (status_cb_arg, line);
if (!rc)
goto again;
}
else if (response == ASSUAN_RESPONSE_END)
{
if (!data_cb)
rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB);
else
{
rc = data_cb (data_cb_arg, NULL, 0);
if (!rc)
goto again;
}
}
return rc;
}
diff --git a/src/context.c b/src/context.c
index 4246039..7877136 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1,241 +1,233 @@
/* context.c - Context specific interface.
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "assuan-defs.h"
#include "debug.h"
/* Set user-data in a context. */
void
assuan_set_pointer (assuan_context_t ctx, void *user_pointer)
{
TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_set_pointer", ctx,
"user_pointer=%p", user_pointer);
if (ctx)
ctx->user_pointer = user_pointer;
}
/* Get user-data in a context. */
void *
assuan_get_pointer (assuan_context_t ctx)
{
#if 0
/* This is called often. */
TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pointer", ctx,
"ctx->user_pointer=%p", ctx ? ctx->user_pointer : NULL);
#endif
if (! ctx)
return NULL;
return ctx->user_pointer;
}
/* For context CTX, set the flag FLAG to VALUE. Values for flags
are usually 1 or 0 but certain flags might allow for other values;
see the description of the type assuan_flag_t for details. */
void
assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value)
{
TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_flag", ctx,
"flag=%i,value=%i", flag, value);
if (!ctx)
return;
switch (flag)
{
- case ASSUAN_NO_WAITPID:
- ctx->flags.no_waitpid = value;
- break;
-
case ASSUAN_CONFIDENTIAL:
ctx->flags.confidential = value;
if (ctx->flags.in_inq_cb && value)
ctx->flags.confidential_inquiry = value;
break;
case ASSUAN_NO_FIXSIGNALS:
ctx->flags.no_fixsignals = value;
break;
case ASSUAN_CONVEY_COMMENTS:
ctx->flags.convey_comments = value;
break;
case ASSUAN_NO_LOGGING:
ctx->flags.no_logging = value;
break;
case ASSUAN_FORCE_CLOSE:
ctx->flags.force_close = 1;
break;
}
}
/* Return the VALUE of FLAG in context CTX. */
int
assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag)
{
int res = 0;
TRACE_BEG1 (ctx, ASSUAN_LOG_CTX, "assuan_get_flag", ctx,
"flag=%i", flag);
if (! ctx)
return 0;
switch (flag)
{
- case ASSUAN_NO_WAITPID:
- res = ctx->flags.no_waitpid;
- break;
-
case ASSUAN_CONFIDENTIAL:
res = ctx->flags.confidential;
break;
case ASSUAN_NO_FIXSIGNALS:
res = ctx->flags.no_fixsignals;
break;
case ASSUAN_CONVEY_COMMENTS:
res = ctx->flags.convey_comments;
break;
case ASSUAN_NO_LOGGING:
res = ctx->flags.no_logging;
break;
case ASSUAN_FORCE_CLOSE:
res = ctx->flags.force_close;
break;
}
return TRACE_SUC1 ("flag_value=%i", res);
}
/* Same as assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1). */
void
assuan_begin_confidential (assuan_context_t ctx)
{
assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1);
}
/* Same as assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0) but first
* flushes pending data. */
void
assuan_end_confidential (assuan_context_t ctx)
{
_assuan_cookie_write_flush (ctx);
assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0);
}
/* Set the IO monitor function. */
void assuan_set_io_monitor (assuan_context_t ctx,
assuan_io_monitor_t io_monitor, void *hook_data)
{
TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_io_monitor", ctx,
"io_monitor=%p,hook_data=%p", io_monitor, hook_data);
if (! ctx)
return;
ctx->io_monitor = io_monitor;
ctx->io_monitor_data = hook_data;
}
/* Store the error in the context so that the error sending function
can take out a descriptive text. Inside the assuan code, use the
macro set_error instead of this function. */
gpg_error_t
assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text)
{
TRACE4 (ctx, ASSUAN_LOG_CTX, "assuan_set_error", ctx,
"err=%i (%s,%s),text=%s", err, gpg_strsource (err),
gpg_strerror (err), text?text:"(none)");
ctx->err_no = err;
ctx->err_str = text;
return err;
}
/* Return the PID of the peer or ASSUAN_INVALID_PID if not known.
This function works in some situations where assuan_get_peercred
fails. */
pid_t
assuan_get_pid (assuan_context_t ctx)
{
#if defined(HAVE_W32_SYSTEM)
TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pid", ctx,
"pid=%i", ctx ? ctx->process_id : -1);
#else
TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pid", ctx,
"pid=%i", ctx ? ctx->pid : -1);
#endif
if (!ctx)
return ASSUAN_INVALID_PID;
if (ctx->flags.is_server)
#if defined(HAVE_W32_SYSTEM)
return ctx->process_id;
#else
return ctx->pid;
#endif
else
/*
* This use case of getting internal process reference by the
* application should be fixed. It's here, only for backward
* compatibility.
*/
- return ctx->server_proc;
+ return (pid_t)-1;
}
/* Return user credentials. For getting the pid of the peer the
assuan_get_pid is usually better suited. */
gpg_error_t
assuan_get_peercred (assuan_context_t ctx, assuan_peercred_t *peercred)
{
TRACE (ctx, ASSUAN_LOG_CTX, "assuan_get_peercred", ctx);
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!ctx->peercred_valid)
return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
*peercred = &ctx->peercred;
return 0;
}
diff --git a/src/system.c b/src/system.c
index c6f0b3d..0327abf 100644
--- a/src/system.c
+++ b/src/system.c
@@ -1,415 +1,451 @@
/* system.c - System support functions.
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
/* Solaris 8 needs sys/types.h before time.h. */
# include <sys/types.h>
#endif
#include <time.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#include <gpg-error.h>
+
#include "assuan-defs.h"
#include "debug.h"
#define DEBUG_SYSIO 0
/* Manage memory specific to a context. */
void *
_assuan_malloc (assuan_context_t ctx, size_t cnt)
{
return ctx->malloc_hooks.malloc (cnt);
}
void *
_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt)
{
return ctx->malloc_hooks.realloc (ptr, cnt);
}
void *
_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize)
{
void *ptr;
size_t nbytes;
nbytes = cnt * elsize;
/* Check for overflow. */
if (elsize && nbytes / elsize != cnt)
{
gpg_err_set_errno (ENOMEM);
return NULL;
}
ptr = ctx->malloc_hooks.malloc (nbytes);
if (ptr)
memset (ptr, 0, nbytes);
return ptr;
}
void
_assuan_free (assuan_context_t ctx, void *ptr)
{
if (ptr)
ctx->malloc_hooks.free (ptr);
}
/* Release the memory at PTR using the allocation handler of the
context CTX. This is a convenience function. */
void
assuan_free (assuan_context_t ctx, void *ptr)
{
_assuan_free (ctx, ptr);
}
/* Sleep for the given number of microseconds. */
void
_assuan_usleep (assuan_context_t ctx, unsigned int usec)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_usleep", ctx,
"usec=%u", usec);
_assuan_pre_syscall ();
__assuan_usleep (ctx, usec);
_assuan_post_syscall ();
}
/* Create a pipe with one inheritable end. */
int
_assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
{
int err;
TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "_assuan_pipe", ctx,
"inherit_idx=%i (Assuan uses it for %s)",
inherit_idx, inherit_idx ? "reading" : "writing");
err = __assuan_pipe (ctx, fd, inherit_idx);
if (err)
return TRACE_SYSRES (err);
return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]);
}
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. */
int
_assuan_close (assuan_context_t ctx, assuan_fd_t fd)
{
int res;
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
"fd=0x%x", fd);
_assuan_pre_syscall ();
res = __assuan_close (ctx, fd);
_assuan_post_syscall ();
return res;
}
/* Same as assuan_close but used for the inheritable end of a
pipe. */
int
_assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd)
{
int res;
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close_inheritable", ctx,
"fd=0x%x", fd);
_assuan_pre_syscall ();
res = __assuan_close (ctx, fd);
_assuan_post_syscall ();
return res;
}
ssize_t
_assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_read", ctx,
"fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
_assuan_pre_syscall ();
res = __assuan_read (ctx, fd, buffer, size);
_assuan_post_syscall ();
return TRACE_SYSRES (res);
#else
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_read (ctx, fd, buffer, size);
_assuan_post_syscall ();
return res;
#endif
}
ssize_t
_assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_write", ctx,
"fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
_assuan_pre_syscall ();
res = __assuan_write (ctx, fd, buffer, size);
_assuan_post_syscall ();
return TRACE_SYSRES (res);
#else
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_write (ctx, fd, buffer, size);
_assuan_post_syscall ();
return res;
#endif
}
int
_assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
#if DEBUG_SYSIO
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_recvmsg", ctx,
"fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
_assuan_pre_syscall ();
res = __assuan_recvmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
if (res > 0)
{
struct cmsghdr *cmptr;
TRACE_LOG2 ("msg->msg_iov[0] = { iov_base=%p, iov_len=%i }",
msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
TRACE_LOGBUF (msg->msg_iov[0].iov_base, res);
cmptr = CMSG_FIRSTHDR (msg);
if (cmptr)
{
void *data = CMSG_DATA (cmptr);
TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
"cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
}
}
return TRACE_SYSRES (res);
#else
int res;
_assuan_pre_syscall ();
res = __assuan_recvmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
return res;
#endif
}
int
_assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
#if DEBUG_SYSIO
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_sendmsg", ctx,
"fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
{
struct cmsghdr *cmptr;
TRACE_LOG2 ("msg->iov[0] = { iov_base=%p, iov_len=%i }",
msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
TRACE_LOGBUF (msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
cmptr = CMSG_FIRSTHDR (msg);
if (cmptr)
{
void *data = CMSG_DATA (cmptr);
TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
"cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
}
}
_assuan_pre_syscall ();
res = __assuan_sendmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
return TRACE_SYSRES (res);
#else
int res;
_assuan_pre_syscall ();
res = __assuan_sendmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
return res;
#endif
}
/* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT
as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated
FD_CHILD_LIST as given (no remapping), which must be inheritable.
On Unix, call ATFORK with ATFORKVALUE after fork and before exec. */
int
-_assuan_spawn (assuan_context_t ctx, assuan_pid_t *r_pid, const char *name,
- const char **argv,
+_assuan_spawn (assuan_context_t ctx, const char *name, const char **argv,
assuan_fd_t fd_in, assuan_fd_t fd_out,
assuan_fd_t *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
+ void (*atfork) (void *opaque),
void *atforkvalue, unsigned int flags)
{
int res;
int i;
+ gpgrt_spawn_actions_t act = NULL;
+ unsigned int spawn_flags;
+ gpg_err_code_t ec;
+ gpgrt_process_t proc = NULL;
+ int keep_stderr = 0;
+ assuan_fd_t *fdp;
+
TRACE_BEG6 (ctx, ASSUAN_LOG_CTX, "_assuan_spawn", ctx,
"name=%s,fd_in=0x%x,fd_out=0x%x,"
"atfork=%p,atforkvalue=%p,flags=%i",
name ? name : "(null)", fd_in, fd_out,
atfork, atforkvalue, flags);
if (name)
{
i = 0;
while (argv[i])
{
TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
i++;
}
}
i = 0;
if (fd_child_list)
{
while (fd_child_list[i] != ASSUAN_INVALID_FD)
{
TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]);
i++;
}
}
- res = __assuan_spawn (ctx, r_pid, name, argv, fd_in, fd_out,
- fd_child_list, atfork, atforkvalue, flags);
+ spawn_flags = GPGRT_PROCESS_STDIN_PIPE|GPGRT_PROCESS_STDOUT_PIPE;
+ if ((flags & ASSUAN_SPAWN_DETACHED))
+ spawn_flags |= GPGRT_PROCESS_NO_CONSOLE;
- if (name)
+ if (fd_child_list)
+ {
+ for (fdp = fd_child_list; *fdp != ASSUAN_INVALID_FD; fdp++)
+ if (*fdp == (assuan_fd_t)STDERR_FILENO)
+ {
+ keep_stderr = 1;
+ break;
+ }
+ }
+ if (keep_stderr)
+ spawn_flags |= GPGRT_PROCESS_STDERR_KEEP;
+
+ ec = gpgrt_spawn_actions_new (&act);
+ if (ec)
{
- TRACE_LOG1 ("pid = 0x%x", *r_pid);
+ return -1;
}
- else
+
+#ifdef HAVE_W32_SYSTEM
+ /*FIXME*/
+ gpgrt_spawn_actions_set_inherit_handles (act, fd_child_list);
+ gpgrt_spawn_actions_set_redirect (act, fd_in, fd_out, -1);
+#else
+ gpgrt_spawn_actions_set_inherit_fds (act, fd_child_list);
+ gpgrt_spawn_actions_set_redirect (act, fd_in, fd_out, -1);
+ gpgrt_spawn_actions_set_atfork (act, atfork, atforkvalue);
+#endif
+ ec = gpgrt_process_spawn (name, argv+1, spawn_flags, act, &proc);
+ gpgrt_spawn_actions_release (act);
+ if (ec)
{
- TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv);
+ return -1;
}
+ ctx->server_proc = proc;
+ res = 0;
return TRACE_SYSERR (res);
}
/* FIXME: Add some sort of waitpid function that covers GPGME and
gpg-agent's use of assuan. */
assuan_pid_t
_assuan_waitpid (assuan_context_t ctx, assuan_pid_t pid, int action,
int *status, int options)
{
#if DEBUG_SYSIO
assuan_pid_t res;
TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx,
"pid=%i, action=%i, status=%p, options=%i",
pid, action, status, options);
_assuan_pre_syscall ();
res = __assuan_waitpid (ctx, pid, action, status, options);
_assuan_post_syscall ();
#else
assuan_pid_t res;
_assuan_pre_syscall ();
res = __assuan_waitpid (ctx, pid, action, status, options);
_assuan_post_syscall ();
return res;
#endif
}
int
_assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2])
{
int res;
TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socketpair", ctx,
"namespace=%i,style=%i,protocol=%i,filedes=%p",
namespace, style, protocol, filedes);
res = __assuan_socketpair (ctx, namespace, style, protocol, filedes);
if (res == 0)
TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]);
return TRACE_SYSERR (res);
}
assuan_fd_t
_assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
{
assuan_fd_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socket", ctx,
"namespace=%i,style=%i,protocol=%i",
namespace, style, protocol);
res = __assuan_socket (ctx, namespace, style, protocol);
return TRACE_SYSRES (res);
}
int
_assuan_connect (assuan_context_t ctx, assuan_fd_t sock,
struct sockaddr *addr, socklen_t length)
{
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_connect", ctx,
"socket=%i,addr=%p,length=%i", sock, addr, length);
_assuan_pre_syscall ();
res = __assuan_connect (ctx, sock, addr, length);
_assuan_post_syscall ();
return TRACE_SYSRES (res);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Apr 25, 3:11 PM (1 d, 15 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
eb/13/84ca9b4fa1a015c1c80783060325
Attached To
rA Assuan
Event Timeline
Log In to Comment