diff --git a/Makefile.am b/Makefile.am
index 4ffb113..ba01f60 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,75 +1,76 @@
# Assuan top level Makefile
# Copyright (C) 2001, 2002, 2003, 2007, 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 .
+# SPDX-License-Identifier: LGPL-2.1+
## Process this file with automake to produce Makefile.in
ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = --enable-doc
# (A suitable gitlog-to-changelog script can be found in GnuPG master.)
GITLOG_TO_CHANGELOG=gitlog-to-changelog
EXTRA_DIST = autogen.sh autogen.rc README.GIT \
ChangeLog-2011 doc/ChangeLog-2011 src/ChangeLog-2011 \
tests/ChangeLog-2011 contrib/ChangeLog-2011 \
build-aux/git-log-footer build-aux/git-log-fix
if BUILD_DOC
doc = doc
else
doc =
endif
SUBDIRS = m4 src $(doc) tests
dist-hook: gen-ChangeLog
echo "$(VERSION)" > $(distdir)/VERSION
distcheck-hook:
set -e; ( \
pref="#+macro: $$(echo $(PACKAGE_NAME)|tr '-' '_')_" ;\
reldate="$$(date -u +%Y-%m-%d)" ;\
echo "$${pref}ver $(PACKAGE_VERSION)" ;\
echo "$${pref}date $${reldate}" ;\
list='$(DIST_ARCHIVES)'; for i in $$list; do \
case "$$i" in *.tar.bz2) \
echo "$${pref}size $$(wc -c <$$i|awk '{print int($$1/1024)}')k" ;\
echo "$${pref}sha1 $$(sha1sum <$$i|cut -d' ' -f1)" ;\
echo "$${pref}sha2 $$(sha256sum <$$i|cut -d' ' -f1)" ;;\
esac;\
done ) | tee $(distdir).swdb
gen_start_date = 2011-12-01T00:00:00
.PHONY: gen-ChangeLog
gen-ChangeLog:
set -e; \
if test -d $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
$(GITLOG_TO_CHANGELOG) --append-dot --tear-off \
--amend=build-aux/git-log-fix --tear-off \
--since=$(gen_start_date) ) > $(distdir)/cl-t; \
cat $(top_srcdir)/build-aux/git-log-footer >> $(distdir)/cl-t;\
rm -f $(distdir)/ChangeLog; \
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
fi
stowinstall:
$(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/libassuan
diff --git a/configure.ac b/configure.ac
index 118e047..731449d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,494 +1,495 @@
# 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 .
+# SPDX-License-Identifier: LGPL-2.1+
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
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], [2])
m4_define([mym4_minor], [4])
m4_define([mym4_micro], [4])
# 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))
AC_INIT([mym4_package],[mym4_version], [http://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=7
LIBASSUAN_LT_AGE=7
LIBASSUAN_LT_REVISION=3
# If the API is changed in an incompatible way: increment the next counter.
LIBASSUAN_CONFIG_API_VERSION=2
##############################################
AC_SUBST(LIBASSUAN_LT_CURRENT)
AC_SUBST(LIBASSUAN_LT_AGE)
AC_SUBST(LIBASSUAN_LT_REVISION)
PACKAGE=$PACKAGE_NAME
VERSION=$PACKAGE_VERSION
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)
AM_CONFIG_HEADER(config.h)
AC_CANONICAL_HOST
AM_SILENT_RULES
AB_INIT
AC_GNU_SOURCE
AC_SUBST(PACKAGE)
AC_SUBST(VERSION)
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package])
AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT, "$PACKAGE_BUGREPORT",[Bug report address])
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
check_descriptor_passing=yes
case "${host}" in
*-*-cygwin*)
check_descriptor_passing=no
;;
*-*-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, 900000L,
Expose all libc features (__DARWIN_C_FULL))
;;
esac
AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
AH_TOP([
#ifndef _ASSUAN_CONFIG_H_INCLUDED
#define _ASSUAN_CONFIG_H_INCLUDED
/* Enable gpg-error's strerror macro under W32CE. */
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
/* 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. A
# comment in libgpg-error says that the AC_PROG_CC_FOR_BUILD macro in
# the AC archive is broken for autoconf 2.57. Given that there is no
# newer version of that macro, we assume that it is also broken for
# autoconf 2.61 and thus we use a simple but usually sufficient
# approach.
AC_MSG_CHECKING(for cc for build)
if test "$cross_compiling" = "yes"; then
CC_FOR_BUILD="${CC_FOR_BUILD-cc}"
else
CC_FOR_BUILD="${CC_FOR_BUILD-$CC}"
fi
AC_MSG_RESULT($CC_FOR_BUILD)
AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler])
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
have_w32ce_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
;;
*-mingw32ce*)
have_dosish_system=yes
have_w32_system=yes
have_w32ce_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
if test "$have_w32ce_system" = yes; then
AC_DEFINE(HAVE_W32CE_SYSTEM,1,[Defined if we run on WindowsCE])
fi
fi
AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
AM_CONDITIONAL(HAVE_W32CE_SYSTEM, test "$have_w32ce_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],
AC_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=""])
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
if test "$have_w32ce_system" = yes; then
NETLIBS="-lws2 $NETLIBS"
else
# FIXME: Check why we need to use ws2_32 and document that.
NETLIBS="-lws2_32 $NETLIBS"
fi
fi
#
# Provide info for src/libassuan-config.in
#
LIBASSUAN_CONFIG_LIB="-lassuan"
LIBASSUAN_CONFIG_CFLAGS=""
LIBASSUAN_CONFIG_HOST="$host"
LIBASSUAN_CONFIG_EXTRA_LIBS=
if test x"$NETLIBS" != x; then
LIBASSUAN_CONFIG_EXTRA_LIBS="$LIBASSUAN_CONFIG_EXTRA_LIBS $NETLIBS"
fi
AC_SUBST(LIBASSUAN_CONFIG_LIB)
AC_SUBST(LIBASSUAN_CONFIG_CFLAGS)
AC_SUBST(LIBASSUAN_CONFIG_HOST)
AC_SUBST(LIBASSUAN_CONFIG_API_VERSION)
AC_SUBST(LIBASSUAN_CONFIG_EXTRA_LIBS)
#
# Checks for header files.
#
AC_HEADER_STDC
AC_CHECK_HEADERS([string.h 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 ])
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
AC_TYPE_SIGNAL
AC_DECL_SYS_SIGLIST
gl_HEADER_SYS_SOCKET
gl_TYPE_SOCKLEN_T
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
#include
#include
#include
#include
#include
#if HAVE_SYS_UIO_H
#include
#endif
#include
])
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]))
#
# 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(putc_unlocked)
AC_REPLACE_FUNCS(memrchr)
AC_REPLACE_FUNCS(stpcpy)
AC_CHECK_HEADERS(unistd.h)
AC_REPLACE_FUNCS(setenv)
#
# Check for the getsockopt SO_PEERCRED
#
AC_MSG_CHECKING(for SO_PEERCRED)
AC_CACHE_VAL(assuan_cv_sys_so_peercred,
[AC_TRY_COMPILE([#include ],
[struct ucred cr;
int cl = sizeof cr;
getsockopt (1, SOL_SOCKET, SO_PEERCRED, &cr, &cl);],
assuan_cv_sys_so_peercred=yes,
assuan_cv_sys_so_peercred=no)
])
AC_MSG_RESULT($assuan_cv_sys_so_peercred)
if test $assuan_cv_sys_so_peercred = yes; then
AC_DEFINE(HAVE_SO_PEERCRED, 1,
[Defined if SO_PEERCRED is supported (Linux specific)])
else
# Check for the getsockopt LOCAL_PEEREID (NetBSD)
AC_MSG_CHECKING(for LOCAL_PEEREID)
AC_CACHE_VAL(assuan_cv_sys_so_local_peereid,
[AC_TRY_COMPILE([#include
#include ],
[struct unpcbid unp;
int unpl = sizeof unp;
getsockopt (1, SOL_SOCKET, LOCAL_PEEREID, &unp, &unpl);],
assuan_cv_sys_so_local_peereid=yes,
assuan_cv_sys_so_local_peereid=no)
])
AC_MSG_RESULT($assuan_cv_sys_so_local_peereid)
if test $assuan_cv_sys_so_local_peereid = yes; then
AC_DEFINE(HAVE_LOCAL_PEEREID, 1,
[Defined if LOCAL_PEEREID is supported (NetBSD specific)])
else
# (Open)Solaris
AC_CHECK_FUNCS([getpeerucred], AC_CHECK_HEADERS([ucred.h]))
if test $ac_cv_func_getpeerucred != yes; then
# FreeBSD
AC_CHECK_FUNCS([getpeereid])
fi
fi
fi
#
# Extra features
#
build_doc=yes
AC_ARG_ENABLE([doc], AC_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_OUTPUT
echo "
Libassuan v${VERSION} has been configured as follows:
Revision: mym4_revision (mym4_revision_dec)
Platform: $host
"
diff --git a/src/Makefile.am b/src/Makefile.am
index 8feef3a..f353e29 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,152 +1,154 @@
# Assuan Makefile
# Copyright (C) 2001, 2002, 2003, 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 .
+#
+# SPDX-License-Identifier: LGPL-2.1+
## Process this file with automake to produce Makefile.in
EXTRA_DIST = libassuan-config.in libassuan.m4 libassuan.vers \
versioninfo.rc.in libassuan.def mkheader.c gpgcedev.def
AM_CPPFLAGS = -I..
bin_SCRIPTS = libassuan-config
m4datadir = $(datadir)/aclocal
m4data_DATA = libassuan.m4
lib_LTLIBRARIES = libassuan.la
if HAVE_W32CE_SYSTEM
lib_LTLIBRARIES += libgpgcedev.la
bin_PROGRAMS = gpgcemgr
endif
nodist_include_HEADERS = assuan.h
if HAVE_LD_VERSION_SCRIPT
libassuan_version_script_cmd = -Wl,--version-script=$(srcdir)/libassuan.vers
else
libassuan_version_script_cmd =
endif
CLEANFILES = mkheader assuan.h
BUILT_SOURCES = assuan.h
parts_of_assuan_h = \
posix-includes.inc.h w32-includes.inc.h \
posix-types.inc.h w32-types.inc.h \
posix-fd-t.inc.h w32-fd-t.inc.h w32ce-fd-t.inc.h \
posix-sock-nonce.inc.h w32-sock-nonce.inc.h \
posix-sys-pth-impl.h w32-sys-pth-impl.h \
w32ce-add.h
common_sources = \
assuan.h.in $(parts_of_assuan_h) \
assuan-defs.h \
assuan.c context.c system.c \
debug.c debug.h conversion.c sysutils.c \
client.c server.c \
assuan-error.c \
assuan-buffer.c \
assuan-handler.c \
assuan-inquire.c \
assuan-listen.c \
assuan-pipe-server.c \
assuan-socket-server.c \
assuan-pipe-connect.c \
assuan-socket-connect.c \
assuan-uds.c \
assuan-logging.c \
assuan-socket.c
if HAVE_W32_SYSTEM
if HAVE_W32CE_SYSTEM
common_sources += system-w32ce.c
else
common_sources += system-w32.c
endif
else
common_sources += system-posix.c
endif
if HAVE_W32_SYSTEM
LTRCCOMPILE = $(LIBTOOL) --mode=compile $(RC) \
`echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
sed -e 's/-I/--include-dir /g;s/-D/--define /g'`
SUFFIXES: .rc .lo
.rc.lo:
$(LTRCCOMPILE) -i $< -o $@
libassuan_res = versioninfo.lo
libassuan_res_ldflag = -Wl,.libs/versioninfo.o
no_undefined = -no-undefined
export_symbols = -export-symbols $(srcdir)/libassuan.def
extra_ltoptions = -XCClinker -static-libgcc
install-def-file:
$(INSTALL) $(srcdir)/libassuan.def $(DESTDIR)$(libdir)/libassuan.def
uninstall-def-file:
-rm $(DESTDIR)$(libdir)/libassuan.def
libassuan_deps = $(libassuan_res) libassuan.def
else
libassuan_res =
libassuan_res_ldflag =
no_undefined =
export_symbols =
extra_ltoptions =
install-def-file:
uninstall-def-file:
libassuan_deps =
endif
libassuan_la_SOURCES = $(common_sources) assuan-io.c
nodist_libassuan_la_SOURCES = assuan.h
libassuan_la_CPPFLAGS = $(AM_CPPFLAGS) @GPG_ERROR_CFLAGS@
libassuan_la_LDFLAGS = $(libassuan_res_ldflag) $(no_undefined) \
$(extra_ltoptions) \
$(export_symbols) $(libassuan_version_script_cmd) -version-info \
@LIBASSUAN_LT_CURRENT@:@LIBASSUAN_LT_REVISION@:@LIBASSUAN_LT_AGE@
libassuan_la_DEPENDENCIES = @LTLIBOBJS@ \
$(srcdir)/libassuan.vers $(libassuan_deps)
libassuan_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@
if HAVE_W32CE_SYSTEM
libgpgcedev_la_SOURCES = gpgcedev.c
libgpgcedev_la_CPPFLAGS = $(AM_CPPFLAGS)
libgpgcedev_la_LDFLAGS = $(no_undefined) -export-symbols $(srcdir)/gpgcedev.def
libgpgcedev_la_DEPENDENCIES = gpgcedev.def
gpgcemgr_SOURCES = gpgcemgr.c
gpgcemgr_CPPFLAGS = $(AM_CPPFLAGS)
install-exec-hook:
mv -f $(DESTDIR)$(bindir)/libgpgcedev-0.dll \
$(DESTDIR)$(bindir)/gpgcedev.dll
endif
mkheader: mkheader.c Makefile
$(CC_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c
assuan.h: assuan.h.in mkheader $(parts_of_assuan_h)
./mkheader $(host_os) $(srcdir)/assuan.h.in \
@VERSION@ @VERSION_NUMBER@ >$@
diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c
index ef9ba41..be87280 100644
--- a/src/assuan-buffer.c
+++ b/src/assuan-buffer.c
@@ -1,548 +1,550 @@
/* assuan-buffer.c - read and send data
- Copyright (C) 2001-2004, 2006, 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 .
+ * Copyright (C) 2001-2004, 2006, 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 .
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#include
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#ifdef HAVE_W32_SYSTEM
#ifndef HAVE_W32CE_SYSTEM
# include
#endif
#endif
#include "assuan-defs.h"
/* Extended version of write(2) to guarantee that all bytes are
written. Returns 0 on success or -1 and ERRNO on failure. NOTE:
This function does not return the number of bytes written, so any
error must be treated as fatal for this connection as the state of
the receiver is unknown. This works best if blocking is allowed
(so EAGAIN cannot occur). */
static int
writen (assuan_context_t ctx, const char *buffer, size_t length)
{
while (length)
{
ssize_t nwritten = ctx->engine.writefnc (ctx, buffer, length);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
return -1; /* write error */
}
length -= nwritten;
buffer += nwritten;
}
return 0; /* okay */
}
/* Read an entire line. Returns 0 on success or -1 and ERRNO on
failure. EOF is indictated by setting the integer at address
R_EOF. Note: BUF, R_NREAD and R_EOF contain a valid result even if
an error is returned. */
static int
readline (assuan_context_t ctx, char *buf, size_t buflen,
int *r_nread, int *r_eof)
{
size_t nleft = buflen;
char *p;
*r_eof = 0;
*r_nread = 0;
while (nleft > 0)
{
ssize_t n = ctx->engine.readfnc (ctx, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
#ifdef HAVE_W32_SYSTEM
if (errno == EPIPE)
{
/* Under Windows we get EPIPE (actually ECONNRESET)
after termination of the client. Assume an EOF. */
*r_eof = 1;
break; /* allow incomplete lines */
}
#endif /*HAVE_W32_SYSTEM*/
return -1; /* read error */
}
else if (!n)
{
*r_eof = 1;
break; /* allow incomplete lines */
}
p = buf;
nleft -= n;
buf += n;
*r_nread += n;
p = memrchr (p, '\n', n);
if (p)
break; /* at least one full line available - that's enough for now */
}
return 0;
}
/* Read a line with buffering of partial lines. Function returns an
Assuan error. */
gpg_error_t
_assuan_read_line (assuan_context_t ctx)
{
gpg_error_t rc = 0;
char *line = ctx->inbound.line;
int nread, atticlen;
char *endp = 0;
if (ctx->inbound.eof)
return _assuan_error (ctx, GPG_ERR_EOF);
atticlen = ctx->inbound.attic.linelen;
if (atticlen)
{
memcpy (line, ctx->inbound.attic.line, atticlen);
ctx->inbound.attic.linelen = 0;
endp = memchr (line, '\n', atticlen);
if (endp)
{
/* Found another line in the attic. */
nread = atticlen;
atticlen = 0;
}
else
{
/* There is pending data but not a full line. */
assert (atticlen < LINELENGTH);
rc = readline (ctx, line + atticlen,
LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
}
}
else
/* No pending data. */
rc = readline (ctx, line, LINELENGTH,
&nread, &ctx->inbound.eof);
if (rc)
{
int saved_errno = errno;
char buf[100];
snprintf (buf, sizeof buf, "error: %s", strerror (errno));
_assuan_log_control_channel (ctx, 0, buf, NULL, 0, NULL, 0);
if (saved_errno == EAGAIN)
{
/* We have to save a partial line. Due to readline's
behaviour, we know that this is not a complete line yet
(no newline). So we don't set PENDING to true. */
memcpy (ctx->inbound.attic.line, line, atticlen + nread);
ctx->inbound.attic.pending = 0;
ctx->inbound.attic.linelen = atticlen + nread;
}
gpg_err_set_errno (saved_errno);
return _assuan_error (ctx, gpg_err_code_from_syserror ());
}
if (!nread)
{
assert (ctx->inbound.eof);
_assuan_log_control_channel (ctx, 0, "eof", NULL, 0, NULL, 0);
return _assuan_error (ctx, GPG_ERR_EOF);
}
ctx->inbound.attic.pending = 0;
nread += atticlen;
if (! endp)
endp = memchr (line, '\n', nread);
if (endp)
{
unsigned monitor_result;
int n = endp - line + 1;
if (n < nread)
/* LINE contains more than one line. We copy it to the attic
now as handlers are allowed to modify the passed
buffer. */
{
int len = nread - n;
memcpy (ctx->inbound.attic.line, endp + 1, len);
ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
ctx->inbound.attic.linelen = len;
}
if (endp != line && endp[-1] == '\r')
endp --;
*endp = 0;
ctx->inbound.linelen = endp - line;
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 0,
ctx->inbound.line,
ctx->inbound.linelen);
if (monitor_result & ASSUAN_IO_MONITOR_IGNORE)
ctx->inbound.linelen = 0;
if ( !(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 0, NULL,
ctx->inbound.line, ctx->inbound.linelen,
NULL, 0);
return 0;
}
else
{
_assuan_log_control_channel (ctx, 0, "invalid line",
NULL, 0, NULL, 0);
*line = 0;
ctx->inbound.linelen = 0;
return _assuan_error (ctx, ctx->inbound.eof
? GPG_ERR_ASS_INCOMPLETE_LINE
: GPG_ERR_ASS_LINE_TOO_LONG);
}
}
/* Read the next line from the client or server and return a pointer
in *LINE to a buffer holding the line. LINELEN is the length of
*LINE. The buffer is valid until the next read operation on it.
The caller may modify the buffer. The buffer is invalid (i.e. must
not be used) if an error is returned.
Returns 0 on success or an assuan error code.
See also: assuan_pending_line().
*/
gpg_error_t
assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
{
gpg_error_t err;
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
do
{
err = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (ctx, err));
*line = ctx->inbound.line;
*linelen = ctx->inbound.linelen;
return err;
}
/* Return true if a full line is buffered (i.e. an entire line may be
read without any I/O). */
int
assuan_pending_line (assuan_context_t ctx)
{
return ctx && ctx->inbound.attic.pending;
}
gpg_error_t
_assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len)
{
gpg_error_t rc = 0;
size_t prefixlen = prefix? strlen (prefix):0;
unsigned int monitor_result;
/* Make sure that the line is short enough. */
if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
{
_assuan_log_control_channel (ctx, 1,
"supplied line too long - truncated",
NULL, 0, NULL, 0);
if (prefixlen > 5)
prefixlen = 5;
if (len > ASSUAN_LINELENGTH - prefixlen - 2)
len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
}
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, line, len);
/* Fixme: we should do some kind of line buffering. */
if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 1, NULL,
prefixlen? prefix:NULL, prefixlen,
line, len);
if (prefixlen && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE))
{
rc = writen (ctx, prefix, prefixlen);
if (rc)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
}
if (!rc && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE))
{
rc = writen (ctx, line, len);
if (rc)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
if (!rc)
{
rc = writen (ctx, "\n", 1);
if (rc)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
}
}
return rc;
}
gpg_error_t
assuan_write_line (assuan_context_t ctx, const char *line)
{
size_t len;
const char *str;
if (! ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
/* Make sure that we never take a LF from the user - this might
violate the protocol. */
str = strchr (line, '\n');
len = str ? (str - line) : strlen (line);
if (str)
_assuan_log_control_channel (ctx, 1,
"supplied line with LF - truncated",
NULL, 0, NULL, 0);
return _assuan_write_line (ctx, NULL, line, len);
}
/* Write out the data in buffer as datalines with line wrapping and
percent escaping. This function is used for GNU's custom streams. */
int
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
{
assuan_context_t ctx = cookie;
size_t size = orig_size;
char *line;
size_t linelen;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
while (size)
{
unsigned int monitor_result;
/* Insert data line header. */
if (!linelen)
{
*line++ = 'D';
*line++ = ' ';
linelen += 2;
}
/* Copy data, keep space for the CRLF and to escape one character. */
while (size && linelen < LINELENGTH-2-2)
{
if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
{
sprintf (line, "%%%02X", *(unsigned char*)buffer);
line += 3;
linelen += 3;
buffer++;
}
else
{
*line++ = *buffer++;
linelen++;
}
size--;
}
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1,
ctx->outbound.data.line, linelen);
if (linelen >= LINELENGTH-2-2)
{
if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 1, NULL,
ctx->outbound.data.line, linelen,
NULL, 0);
*line++ = '\n';
linelen++;
if ( !(monitor_result & ASSUAN_IO_MONITOR_IGNORE)
&& writen (ctx, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = gpg_err_code_from_syserror ();
return 0;
}
line = ctx->outbound.data.line;
linelen = 0;
}
}
ctx->outbound.data.linelen = linelen;
return (int) orig_size;
}
/* Write out any buffered data
This function is used for GNU's custom streams */
int
_assuan_cookie_write_flush (void *cookie)
{
assuan_context_t ctx = cookie;
char *line;
size_t linelen;
unsigned int monitor_result;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1,
ctx->outbound.data.line, linelen);
if (linelen)
{
if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 1, NULL,
ctx->outbound.data.line, linelen,
NULL, 0);
*line++ = '\n';
linelen++;
if (! (monitor_result & ASSUAN_IO_MONITOR_IGNORE)
&& writen (ctx, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = gpg_err_code_from_syserror ();
return 0;
}
ctx->outbound.data.linelen = 0;
}
return 0;
}
/**
* assuan_send_data:
* @ctx: An assuan context
* @buffer: Data to send or NULL to flush
* @length: length of the data to send/
*
* This function may be used by the server or the client to send data
* lines. The data will be escaped as required by the Assuan protocol
* and may get buffered until a line is full. To force sending the
* data out @buffer may be passed as NULL (in which case @length must
* also be 0); however when used by a client this flush operation does
* also send the terminating "END" command to terminate the response on
* a INQUIRE response. However, when assuan_transact() is used, this
* function takes care of sending END itself.
*
* If BUFFER is NULL and LENGTH is 1 and we are a client, a "CAN" is
* send instead of an "END".
*
* Return value: 0 on success or an error code
**/
gpg_error_t
assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!buffer && length > 1)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!buffer)
{ /* flush what we have */
_assuan_cookie_write_flush (ctx);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
if (!ctx->is_server)
return assuan_write_line (ctx, length == 1? "CAN":"END");
}
else
{
_assuan_cookie_write_data (ctx, buffer, length);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
}
return 0;
}
gpg_error_t
assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd)
{
/* It is explicitly allowed to use (NULL, -1) as a runtime test to
check whether descriptor passing is available. */
if (!ctx && fd == ASSUAN_INVALID_FD)
#ifdef USE_DESCRIPTOR_PASSING
return 0;
#else
return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
#endif
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (! ctx->engine.sendfd)
return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED,
"server does not support sending and receiving "
"of file descriptors");
return ctx->engine.sendfd (ctx, fd);
}
gpg_error_t
assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (! ctx->engine.receivefd)
return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED,
"server does not support sending and receiving "
"of file descriptors");
return ctx->engine.receivefd (ctx, fd);
}
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index 97b053d..6688198 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -1,434 +1,435 @@
/* 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef ASSUAN_DEFS_H
#define ASSUAN_DEFS_H
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifndef HAVE_W32_SYSTEM
# include
# include
#else
# ifdef HAVE_WINSOCK2_H
# /* Avoid inclusion of winsock.h via windows.h. */
# include
# endif
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#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;
} flags;
/* If set, this is called right before logging an I/O line. */
assuan_io_monitor_t io_monitor;
void *io_monitor_data;
/* Callback handlers replacing system I/O functions. */
struct assuan_system_hooks system;
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;
int is_server; /* Set if this is context belongs to a server */
int in_inquire;
int in_process_next;
int process_complete;
int in_command;
/* 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. */
pid_t pid; /* The pid of the peer. */
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, 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);
pid_t _assuan_waitpid (assuan_context_t ctx, 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]);
int _assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol);
int _assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
socklen_t length);
extern struct assuan_system_hooks _assuan_system_hooks;
/* Copy the system hooks struct, paying attention to version
differences. SRC is usually from the user, DST MUST be from the
library. */
void
_assuan_system_hooks_copy (assuan_system_hooks_t dst,
assuan_system_hooks_t src);
/*-- 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);
#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
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);
#ifdef HAVE_W32CE_SYSTEM
#define getpid() GetCurrentProcessId ()
char *_assuan_getenv (const char *name);
#define getenv(a) _assuan_getenv ((a))
#endif /*HAVE_W32CE_SYSTEM*/
/* 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);
#endif /*ASSUAN_DEFS_H*/
diff --git a/src/assuan-error.c b/src/assuan-error.c
index cc1ff5c..8799203 100644
--- a/src/assuan-error.c
+++ b/src/assuan-error.c
@@ -1,67 +1,68 @@
/* assuan-error.c
- 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#undef _ASSUAN_IN_LIBASSUAN /* undef to get all error codes. */
#include "assuan.h"
#include "assuan-defs.h"
/* A small helper function to treat EAGAIN transparently to the
caller. */
int
_assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err)
{
if (gpg_err_code (err) == GPG_ERR_EAGAIN)
{
/* Avoid spinning by sleeping for one tenth of a second. */
_assuan_usleep (ctx, 100000);
return 1;
}
else
return 0;
}
#ifdef HAVE_W32_SYSTEM
char *
_assuan_w32_strerror (assuan_context_t ctx, int ec)
{
if (ec == -1)
ec = (int)GetLastError ();
#ifdef HAVE_W32CE_SYSTEM
snprintf (ctx->w32_strerror, sizeof (ctx->w32_strerror) - 1,
"ec=%d", (int)GetLastError ());
#else
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
ctx->w32_strerror, sizeof (ctx->w32_strerror) - 1, NULL);
#endif
return ctx->w32_strerror;
}
#endif
diff --git a/src/assuan-handler.c b/src/assuan-handler.c
index dec0f1b..2299fcd 100644
--- a/src/assuan-handler.c
+++ b/src/assuan-handler.c
@@ -1,1068 +1,1069 @@
/* assuan-handler.c - dispatch commands
- Copyright (C) 2001, 2002, 2003, 2007, 2009,
- 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 .
+ * Copyright (C) 2001, 2002, 2003, 2007, 2009,
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include "assuan-defs.h"
#include "debug.h"
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
#define digitp(a) ((a) >= '0' && (a) <= '9')
static int my_strcasecmp (const char *a, const char *b);
#define PROCESS_DONE(ctx, rc) \
((ctx)->in_process_next ? assuan_process_done ((ctx), (rc)) : (rc))
static gpg_error_t
dummy_handler (assuan_context_t ctx, char *line)
{
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASSUAN_SERVER_FAULT,
"no handler registered"));
}
static const char std_help_nop[] =
"NOP\n"
"\n"
"No operation. Returns OK without any action.";
static gpg_error_t
std_handler_nop (assuan_context_t ctx, char *line)
{
return PROCESS_DONE (ctx, 0); /* okay */
}
static const char std_help_cancel[] =
"CANCEL\n"
"\n"
"Run the server's cancel handler if one has been registered.";
static gpg_error_t
std_handler_cancel (assuan_context_t ctx, char *line)
{
if (ctx->cancel_notify_fnc)
/* Return value ignored. */
ctx->cancel_notify_fnc (ctx, line);
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
static const char std_help_option[] =
"OPTION [ [=] ]\n"
"\n"
"Set option to configure server operation. Leading and\n"
"trailing spaces around and are allowed but should be\n"
"ignored. For compatibility reasons, may be prefixed with two\n"
"dashes. The use of the equal sign is optional but suggested if\n"
" is given.";
static gpg_error_t
std_handler_option (assuan_context_t ctx, char *line)
{
char *key, *value, *p;
for (key=line; spacep (key); key++)
;
if (!*key)
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX, "argument required"));
if (*key == '=')
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX,
"no option name given"));
for (value=key; *value && !spacep (value) && *value != '='; value++)
;
if (*value)
{
if (spacep (value))
*value++ = 0; /* terminate key */
for (; spacep (value); value++)
;
if (*value == '=')
{
*value++ = 0; /* terminate key */
for (; spacep (value); value++)
;
if (!*value)
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX,
"option argument expected"));
}
if (*value)
{
for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
;
if (p > value)
*++p = 0; /* strip trailing spaces */
}
}
if (*key == '-' && key[1] == '-' && key[2])
key += 2; /* the double dashes are optional */
if (*key == '-')
return PROCESS_DONE (ctx,
set_error (ctx, GPG_ERR_ASS_SYNTAX,
"option should not begin with one dash"));
if (ctx->option_handler_fnc)
return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value));
return PROCESS_DONE (ctx, 0);
}
static const char std_help_bye[] =
"BYE\n"
"\n"
"Close the connection. The server will reply with OK.";
static gpg_error_t
std_handler_bye (assuan_context_t ctx, char *line)
{
if (ctx->bye_notify_fnc)
/* Return value ignored. */
ctx->bye_notify_fnc (ctx, line);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
/* pretty simple :-) */
ctx->process_complete = 1;
return PROCESS_DONE (ctx, 0);
}
static const char std_help_auth[] =
"AUTH\n"
"\n"
"Reserved for future extensions.";
static gpg_error_t
std_handler_auth (assuan_context_t ctx, char *line)
{
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
static const char std_help_reset[] =
"RESET\n"
"\n"
"Reset the connection but not any existing authentication. The server\n"
"should release all resources associated with the connection.";
static gpg_error_t
std_handler_reset (assuan_context_t ctx, char *line)
{
gpg_error_t err = 0;
if (ctx->reset_notify_fnc)
err = ctx->reset_notify_fnc (ctx, line);
if (! err)
{
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
_assuan_uds_close_fds (ctx);
}
return PROCESS_DONE (ctx, err);
}
static const char std_help_help[] =
"HELP []\n"
"\n"
"Lists all commands that the server understands as comment lines on\n"
"the status channel. If is given, list detailed help for\n"
"that command.";
static gpg_error_t
std_handler_help (assuan_context_t ctx, char *line)
{
unsigned int i;
char buf[ASSUAN_LINELENGTH];
const char *helpstr;
size_t n;
n = strcspn (line, " \t\n");
if (!n)
{
/* Print all commands. If a help string is available and that
starts with the command name, print the first line of the
help string. */
for (i = 0; i < ctx->cmdtbl_used; i++)
{
n = strlen (ctx->cmdtbl[i].name);
helpstr = ctx->cmdtbl[i].helpstr;
if (helpstr
&& !strncmp (ctx->cmdtbl[i].name, helpstr, n)
&& (!helpstr[n] || helpstr[n] == '\n' || helpstr[n] == ' ')
&& (n = strcspn (helpstr, "\n")) )
snprintf (buf, sizeof (buf), "# %.*s", (int)n, helpstr);
else
snprintf (buf, sizeof (buf), "# %s", ctx->cmdtbl[i].name);
buf[ASSUAN_LINELENGTH - 1] = '\0';
assuan_write_line (ctx, buf);
}
}
else
{
/* Print the help for the given command. */
int c = line[n];
line[n] = 0;
for (i=0; ctx->cmdtbl[i].name; i++)
if (!my_strcasecmp (line, ctx->cmdtbl[i].name))
break;
line[n] = c;
if (!ctx->cmdtbl[i].name)
return PROCESS_DONE (ctx, set_error (ctx,GPG_ERR_UNKNOWN_COMMAND,NULL));
helpstr = ctx->cmdtbl[i].helpstr;
if (!helpstr)
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_FOUND, NULL));
do
{
n = strcspn (helpstr, "\n");
snprintf (buf, sizeof (buf), "# %.*s", (int)n, helpstr);
helpstr += n;
if (*helpstr == '\n')
helpstr++;
buf[ASSUAN_LINELENGTH - 1] = '\0';
assuan_write_line (ctx, buf);
}
while (*helpstr);
}
return PROCESS_DONE (ctx, 0);
}
static const char std_help_end[] =
"END\n"
"\n"
"Used by a client to mark the end of raw data.";
static gpg_error_t
std_handler_end (assuan_context_t ctx, char *line)
{
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
gpg_error_t
assuan_command_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd)
{
char *endp;
if ((strncmp (line, "FD", 2) && strncmp (line, "fd", 2))
|| (line[2] != '=' && line[2] != '\0' && !spacep(&line[2])))
return set_error (ctx, GPG_ERR_ASS_SYNTAX, "FD[=] expected");
line += 2;
if (*line == '=')
{
line ++;
if (!digitp (*line))
return set_error (ctx, GPG_ERR_ASS_SYNTAX, "number required");
#if HAVE_W64_SYSTEM
*rfd = (void*)strtoull (line, &endp, 10);
#elif HAVE_W32_SYSTEM
*rfd = (void*)strtoul (line, &endp, 10);
#else
*rfd = strtoul (line, &endp, 10);
#endif
/* Remove that argument so that a notify handler won't see it. */
memset (line, ' ', endp? (endp-line):strlen(line));
if (*rfd == ctx->inbound.fd)
return set_error (ctx, GPG_ERR_ASS_PARAMETER, "fd same as inbound fd");
if (*rfd == ctx->outbound.fd)
return set_error (ctx, GPG_ERR_ASS_PARAMETER, "fd same as outbound fd");
return 0;
}
else
/* Our peer has sent the file descriptor. */
return assuan_receivefd (ctx, rfd);
}
static const char std_help_input[] =
"INPUT FD[=]\n"
"\n"
"Used by a client to pass an input file descriptor to the server.\n"
"The server opens as a local file descriptor. Without , the\n"
"server opens the file descriptor just sent by the client using\n"
"assuan_sendfd.";
static gpg_error_t
std_handler_input (assuan_context_t ctx, char *line)
{
gpg_error_t rc;
assuan_fd_t fd, oldfd;
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
return PROCESS_DONE (ctx, rc);
#ifdef HAVE_W32CE_SYSTEM
oldfd = fd;
fd = _assuan_w32ce_finish_pipe ((int)fd, 0);
if (fd == INVALID_HANDLE_VALUE)
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_PARAMETER,
"rvid conversion failed"));
TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_input", ctx,
"turned RVID 0x%x into handle 0x%x", oldfd, fd);
#endif
if (ctx->input_notify_fnc)
{
oldfd = ctx->input_fd;
ctx->input_fd = fd;
rc = ctx->input_notify_fnc (ctx, line);
if (rc)
ctx->input_fd = oldfd;
}
else if (!rc)
ctx->input_fd = fd;
return PROCESS_DONE (ctx, rc);
}
static const char std_help_output[] =
"OUTPUT FD[=]\n"
"\n"
"Used by a client to pass an output file descriptor to the server.\n"
"The server opens as a local file descriptor. Without , the\n"
"server opens the file descriptor just sent by the client using\n"
"assuan_sendfd.";
static gpg_error_t
std_handler_output (assuan_context_t ctx, char *line)
{
gpg_error_t rc;
assuan_fd_t fd, oldfd;
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
return PROCESS_DONE (ctx, rc);
#ifdef HAVE_W32CE_SYSTEM
oldfd = fd;
fd = _assuan_w32ce_finish_pipe ((int)fd, 1);
if (fd == INVALID_HANDLE_VALUE)
return PROCESS_DONE (ctx, set_error (ctx, gpg_err_code_from_syserror (),
"rvid conversion failed"));
TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_output", ctx,
"turned RVID 0x%x into handle 0x%x", oldfd, fd);
#endif
if (ctx->output_notify_fnc)
{
oldfd = ctx->output_fd;
ctx->output_fd = fd;
rc = ctx->output_notify_fnc (ctx, line);
if (rc)
ctx->output_fd = oldfd;
}
else if (!rc)
ctx->output_fd = fd;
return PROCESS_DONE (ctx, rc);
}
/* This is a table with the standard commands and handler for them.
The table is used to initialize a new context and associate strings
with default handlers */
static struct {
const char *name;
gpg_error_t (*handler)(assuan_context_t, char *line);
const char *help;
int always; /* always initialize this command */
} std_cmd_table[] = {
{ "NOP", std_handler_nop, std_help_nop, 1 },
{ "CANCEL", std_handler_cancel, std_help_cancel, 1 },
{ "OPTION", std_handler_option, std_help_option, 1 },
{ "BYE", std_handler_bye, std_help_bye, 1 },
{ "AUTH", std_handler_auth, std_help_auth, 1 },
{ "RESET", std_handler_reset, std_help_reset, 1 },
{ "END", std_handler_end, std_help_end, 1 },
{ "HELP", std_handler_help, std_help_help, 1 },
{ "INPUT", std_handler_input, std_help_input, 0 },
{ "OUTPUT", std_handler_output, std_help_output, 0 },
{ } };
/**
* assuan_register_command:
* @ctx: the server context
* @cmd_name: A string with the command name
* @handler: The handler function to be called or NULL to use a default
* handler.
* HELPSTRING
*
* Register a handler to be used for a given command. Note that
* several default handlers are already regsitered with a new context.
* This function however allows to override them.
*
* Return value: 0 on success or an error code
**/
gpg_error_t
assuan_register_command (assuan_context_t ctx, const char *cmd_name,
assuan_handler_t handler, const char *help_string)
{
int i, cmd_index = -1;
const char *s;
if (cmd_name && !*cmd_name)
cmd_name = NULL;
if (!cmd_name)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!handler)
{ /* find a default handler. */
for (i=0; (s=std_cmd_table[i].name) && strcmp (cmd_name, s); i++)
;
if (!s)
{ /* Try again but case insensitive. */
for (i=0; (s=std_cmd_table[i].name)
&& my_strcasecmp (cmd_name, s); i++)
;
}
if (s)
handler = std_cmd_table[i].handler;
if (!handler)
handler = dummy_handler; /* Last resort is the dummy handler. */
}
if (!ctx->cmdtbl)
{
ctx->cmdtbl_size = 50;
ctx->cmdtbl = _assuan_calloc (ctx, ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
if (!ctx->cmdtbl)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
ctx->cmdtbl_used = 0;
}
else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
{
struct cmdtbl_s *x;
x = _assuan_realloc (ctx, ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
ctx->cmdtbl = x;
ctx->cmdtbl_size += 50;
}
for (i=0; icmdtbl_used; i++)
{
if (!my_strcasecmp (cmd_name, ctx->cmdtbl[i].name))
{
cmd_index = i;
break;
}
}
if (cmd_index == -1)
cmd_index = ctx->cmdtbl_used++;
ctx->cmdtbl[cmd_index].name = cmd_name;
ctx->cmdtbl[cmd_index].handler = handler;
ctx->cmdtbl[cmd_index].helpstr = help_string;
return 0;
}
/* Return the name of the command currently processed by a handler.
The string returned is valid until the next call to an assuan
function on the same context. Returns NULL if no handler is
executed or the command is not known. */
const char *
assuan_get_command_name (assuan_context_t ctx)
{
return ctx? ctx->current_cmd_name : NULL;
}
gpg_error_t
assuan_register_pre_cmd_notify (assuan_context_t ctx,
gpg_error_t (*fnc)(assuan_context_t,
const char *cmd))
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->pre_cmd_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_post_cmd_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t, gpg_error_t))
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->post_cmd_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_bye_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->bye_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_reset_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->reset_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_cancel_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->cancel_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_option_handler (assuan_context_t ctx,
gpg_error_t (*fnc)(assuan_context_t,
const char*, const char*))
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->option_handler_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_input_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->input_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_output_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->output_notify_fnc = fnc;
return 0;
}
/* Helper to register the standards commands */
gpg_error_t
_assuan_register_std_commands (assuan_context_t ctx)
{
gpg_error_t rc;
int i;
for (i = 0; std_cmd_table[i].name; i++)
{
if (std_cmd_table[i].always)
{
rc = assuan_register_command (ctx, std_cmd_table[i].name, NULL, NULL);
if (rc)
return rc;
}
}
return 0;
}
/* Process the special data lines. The "D " has already been removed
from the line. As all handlers this function may modify the line. */
static gpg_error_t
handle_data_line (assuan_context_t ctx, char *line, int linelen)
{
return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL);
}
/* like ascii_strcasecmp but assume that B is already uppercase */
static int
my_strcasecmp (const char *a, const char *b)
{
if (a == b)
return 0;
for (; *a && *b; a++, b++)
{
if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
break;
}
return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
}
/* Parse the line, break out the command, find it in the command
table, remove leading and white spaces from the arguments, call the
handler with the argument line and return the error. */
static gpg_error_t
dispatch_command (assuan_context_t ctx, char *line, int linelen)
{
gpg_error_t err;
char *p;
const char *s;
int shift, i;
/* Note that as this function is invoked by assuan_process_next as
well, we need to hide non-critical errors with PROCESS_DONE. */
if (*line == 'D' && line[1] == ' ') /* divert to special handler */
/* FIXME: Depending on the final implementation of
handle_data_line, this may be wrong here. For example, if a
user callback is invoked, and that callback is responsible for
calling assuan_process_done, then this is wrong. */
return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2));
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
;
if (p==line)
return PROCESS_DONE
(ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX, "leading white-space"));
if (*p)
{ /* Skip over leading WS after the keyword */
*p++ = 0;
while ( *p == ' ' || *p == '\t')
p++;
}
shift = p - line;
for (i=0; (s=ctx->cmdtbl[i].name); i++)
{
if (!strcmp (line, s))
break;
}
if (!s)
{ /* and try case insensitive */
for (i=0; (s=ctx->cmdtbl[i].name); i++)
{
if (!my_strcasecmp (line, s))
break;
}
}
if (!s)
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_UNKNOWN_CMD, NULL));
line += shift;
/* linelen -= shift; -- not needed. */
if (ctx->pre_cmd_notify_fnc) {
err = ctx->pre_cmd_notify_fnc(ctx, ctx->cmdtbl[i].name);
if (err)
return PROCESS_DONE(ctx, err);
}
/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
ctx->current_cmd_name = ctx->cmdtbl[i].name;
err = ctx->cmdtbl[i].handler (ctx, line);
ctx->current_cmd_name = NULL;
return err;
}
/* Call this to acknowledge the current command. */
gpg_error_t
assuan_process_done (assuan_context_t ctx, gpg_error_t rc)
{
if (!ctx->in_command)
return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
if (ctx->flags.force_close)
ctx->process_complete = 1;
ctx->in_command = 0;
/* Check for data write errors. */
if (ctx->outbound.data.fp)
{
/* Flush the data lines. */
fclose (ctx->outbound.data.fp);
ctx->outbound.data.fp = NULL;
if (!rc && ctx->outbound.data.error)
rc = ctx->outbound.data.error;
}
else
{
/* Flush any data send without using the data FP. */
assuan_send_data (ctx, NULL, 0);
if (!rc && ctx->outbound.data.error)
rc = ctx->outbound.data.error;
}
/* Error handling. */
if (!rc)
{
if (ctx->process_complete)
{
/* No error checking because the peer may have already
disconnect. */
assuan_write_line (ctx, "OK closing connection");
ctx->finish_handler (ctx);
}
else
rc = assuan_write_line (ctx, ctx->okay_line ? ctx->okay_line : "OK");
}
else
{
char errline[300];
const char *text = ctx->err_no == rc ? ctx->err_str : NULL;
char ebuf[50];
if (ctx->flags.force_close)
text = "[closing connection]";
gpg_strerror_r (rc, ebuf, sizeof (ebuf));
snprintf (errline, sizeof errline, "ERR %d %.50s <%.30s>%s%.100s",
rc, ebuf, gpg_strsource (rc),
text? " - ":"", text?text:"");
rc = assuan_write_line (ctx, errline);
if (ctx->flags.force_close)
ctx->finish_handler (ctx);
}
if (ctx->post_cmd_notify_fnc)
ctx->post_cmd_notify_fnc (ctx, rc);
ctx->flags.confidential = 0;
if (ctx->okay_line)
{
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = NULL;
}
return rc;
}
static gpg_error_t
process_next (assuan_context_t ctx)
{
gpg_error_t rc;
/* What the next thing to do is depends on the current state.
However, we will always first read the next line. The client is
required to write full lines without blocking long after starting
a partial line. */
rc = _assuan_read_line (ctx);
if (_assuan_error_is_eagain (ctx, rc))
return 0;
if (gpg_err_code (rc) == GPG_ERR_EOF)
{
ctx->process_complete = 1;
return 0;
}
if (rc)
return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
/* Comment lines are ignored. */
return 0;
/* Now we have a line that really means something. It could be one
of the following things: First, if we are not in a command
already, it is the next command to dispatch. Second, if we are
in a command, it can only be the response to an INQUIRE
reply. */
if (!ctx->in_command)
{
ctx->in_command = 1;
ctx->outbound.data.error = 0;
ctx->outbound.data.linelen = 0;
/* Dispatch command and return reply. */
ctx->in_process_next = 1;
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
ctx->in_process_next = 0;
}
else if (ctx->in_inquire)
{
/* FIXME: Pick up the continuation. */
rc = _assuan_inquire_ext_cb (ctx);
}
else
{
/* Should not happen. The client is sending data while we are
in a command and not waiting for an inquire. We log an error
and discard it. */
TRACE0 (ctx, ASSUAN_LOG_DATA, "process_next", ctx,
"unexpected client data");
rc = 0;
}
return rc;
}
/* This function should be invoked when the assuan connected FD is
ready for reading. If the equivalent to EWOULDBLOCK is returned
(this should be done by the command handler), assuan_process_next
should be invoked the next time the connected FD is readable.
Eventually, the caller will finish by invoking assuan_process_done.
DONE is set to 1 if the connection has ended. */
gpg_error_t
assuan_process_next (assuan_context_t ctx, int *done)
{
gpg_error_t rc;
if (done)
*done = 0;
ctx->process_complete = 0;
do
{
rc = process_next (ctx);
}
while (!rc && !ctx->process_complete && assuan_pending_line (ctx));
if (done)
*done = !!ctx->process_complete;
return rc;
}
static gpg_error_t
process_request (assuan_context_t ctx)
{
gpg_error_t rc;
if (ctx->in_inquire)
return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
do
{
rc = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (ctx, rc));
if (gpg_err_code (rc) == GPG_ERR_EOF)
{
ctx->process_complete = 1;
return 0;
}
if (rc)
return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
return 0; /* comment line - ignore */
ctx->in_command = 1;
ctx->outbound.data.error = 0;
ctx->outbound.data.linelen = 0;
/* dispatch command and return reply */
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
return assuan_process_done (ctx, rc);
}
/**
* assuan_process:
* @ctx: assuan context
*
* This function is used to handle the assuan protocol after a
* connection has been established using assuan_accept(). This is the
* main protocol handler.
*
* Return value: 0 on success or an error code if the assuan operation
* failed. Note, that no error is returned for operational errors.
**/
gpg_error_t
assuan_process (assuan_context_t ctx)
{
gpg_error_t rc;
ctx->process_complete = 0;
do {
rc = process_request (ctx);
} while (!rc && !ctx->process_complete);
return rc;
}
/**
* assuan_get_active_fds:
* @ctx: Assuan context
* @what: 0 for read fds, 1 for write fds
* @fdarray: Caller supplied array to store the FDs
* @fdarraysize: size of that array
*
* Return all active filedescriptors for the given context. This
* function can be used to select on the fds and call
* assuan_process_next() if there is an active one. The first fd in
* the array is the one used for the command connection.
*
* Note, that write FDs are not yet supported.
*
* Return value: number of FDs active and put into @fdarray or -1 on
* error which is most likely a too small fdarray.
**/
int
assuan_get_active_fds (assuan_context_t ctx, int what,
assuan_fd_t *fdarray, int fdarraysize)
{
int n = 0;
if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
return -1;
if (!what)
{
if (ctx->inbound.fd != ASSUAN_INVALID_FD)
fdarray[n++] = ctx->inbound.fd;
}
else
{
if (ctx->outbound.fd != ASSUAN_INVALID_FD)
fdarray[n++] = ctx->outbound.fd;
if (ctx->outbound.data.fp)
#if defined(HAVE_W32CE_SYSTEM)
fdarray[n++] = (void*)fileno (ctx->outbound.data.fp);
#elif defined(HAVE_W32_SYSTEM)
fdarray[n++] = (void*)_get_osfhandle (fileno (ctx->outbound.data.fp));
#else
fdarray[n++] = fileno (ctx->outbound.data.fp);
#endif
}
return n;
}
/* Two simple wrappers to make the expected function types match. */
#ifdef HAVE_FUNOPEN
static int
fun1_cookie_write (void *cookie, const char *buffer, int orig_size)
{
return _assuan_cookie_write_data (cookie, buffer, orig_size);
}
#endif /*HAVE_FUNOPEN*/
#ifdef HAVE_FOPENCOOKIE
static ssize_t
fun2_cookie_write (void *cookie, const char *buffer, size_t orig_size)
{
return _assuan_cookie_write_data (cookie, buffer, orig_size);
}
#endif /*HAVE_FOPENCOOKIE*/
/* Return a FP to be used for data output. The FILE pointer is valid
until the end of a handler. So a close is not needed. Assuan does
all the buffering needed to insert the status line as well as the
required line wappping and quoting for data lines.
We use GNU's custom streams here. There should be an alternative
implementaion for systems w/o a glibc, a simple implementation
could use a child process */
FILE *
assuan_get_data_fp (assuan_context_t ctx)
{
#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
if (ctx->outbound.data.fp)
return ctx->outbound.data.fp;
#ifdef HAVE_FUNOPEN
ctx->outbound.data.fp = funopen (ctx, 0, fun1_cookie_write,
0, _assuan_cookie_write_flush);
#else
ctx->outbound.data.fp = funopen (ctx, 0, fun2_cookie_write,
0, _assuan_cookie_write_flush);
#endif
ctx->outbound.data.error = 0;
return ctx->outbound.data.fp;
#else
gpg_err_set_errno (ENOSYS);
return NULL;
#endif
}
/* Set the text used for the next OK response. This string is
automatically reset to NULL after the next command. */
gpg_error_t
assuan_set_okay_line (assuan_context_t ctx, const char *line)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!line)
{
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = NULL;
}
else
{
/* FIXME: we need to use gcry_is_secure() to test whether
we should allocate the entire line in secure memory */
char *buf = _assuan_malloc (ctx, 3 + strlen(line) + 1);
if (!buf)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
strcpy (buf, "OK ");
strcpy (buf+3, line);
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = buf;
}
return 0;
}
gpg_error_t
assuan_write_status (assuan_context_t ctx,
const char *keyword, const char *text)
{
char buffer[256];
char *helpbuf;
size_t n;
gpg_error_t ae;
if ( !ctx || !keyword)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!text)
text = "";
n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
if (n < sizeof (buffer))
{
strcpy (buffer, "S ");
strcat (buffer, keyword);
if (*text)
{
strcat (buffer, " ");
strcat (buffer, text);
}
ae = assuan_write_line (ctx, buffer);
}
else if ( (helpbuf = _assuan_malloc (ctx, n)) )
{
strcpy (helpbuf, "S ");
strcat (helpbuf, keyword);
if (*text)
{
strcat (helpbuf, " ");
strcat (helpbuf, text);
}
ae = assuan_write_line (ctx, helpbuf);
_assuan_free (ctx, helpbuf);
}
else
ae = 0;
return ae;
}
diff --git a/src/assuan-inquire.c b/src/assuan-inquire.c
index f863935..fa227a6 100644
--- a/src/assuan-inquire.c
+++ b/src/assuan-inquire.c
@@ -1,414 +1,415 @@
/* assuan-inquire.c - handle inquire stuff
- Copyright (C) 2001-2003, 2005, 2007, 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 .
+ * Copyright (C) 2001-2003, 2005, 2007, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include "assuan-defs.h"
#define digitp(a) ((a) >= '0' && (a) <= '9')
#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))
struct membuf
{
size_t len;
size_t size;
char *buf;
int out_of_core;
int too_large;
size_t maxlen;
};
/* A simple implementation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
the code with out of core checks. */
static void
init_membuf (assuan_context_t ctx,
struct membuf *mb, int initiallen, size_t maxlen)
{
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
mb->too_large = 0;
mb->maxlen = maxlen;
/* we need to allocate one byte more for get_membuf */
mb->buf = _assuan_malloc (ctx, initiallen + 1);
if (!mb->buf)
mb->out_of_core = 1;
}
static void
put_membuf (assuan_context_t ctx,
struct membuf *mb, const void *buf, size_t len)
{
if (mb->out_of_core || mb->too_large)
return;
if (mb->maxlen && mb->len + len > mb->maxlen)
{
mb->too_large = 1;
return;
}
if (mb->len + len >= mb->size)
{
char *p;
mb->size += len + 1024;
/* we need to allocate one byte more for get_membuf */
p = _assuan_realloc (ctx, mb->buf, mb->size + 1);
if (!p)
{
mb->out_of_core = 1;
return;
}
mb->buf = p;
}
memcpy (mb->buf + mb->len, buf, len);
mb->len += len;
}
static void *
get_membuf (assuan_context_t ctx, struct membuf *mb, size_t *len)
{
char *p;
if (mb->out_of_core || mb->too_large)
{
_assuan_free (ctx, mb->buf);
mb->buf = NULL;
return NULL;
}
mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */
p = mb->buf;
*len = mb->len;
mb->buf = NULL;
mb->out_of_core = 1; /* don't allow a reuse */
return p;
}
static void
free_membuf (assuan_context_t ctx, struct membuf *mb)
{
_assuan_free (ctx, mb->buf);
mb->buf = NULL;
}
/**
* assuan_inquire:
* @ctx: An assuan context
* @keyword: The keyword used for the inquire
* @r_buffer: Returns an allocated buffer
* @r_length: Returns the length of this buffer
* @maxlen: If not 0, the size limit of the inquired data.
*
* A server may use this to send an inquire. r_buffer, r_length and
* maxlen may all be NULL/0 to indicate that no real data is expected.
* The returned buffer is guaranteed to have an extra 0-byte after the
* length. Thus it can be used as a string if embedded 0 bytes are
* not an issue.
*
* Return value: 0 on success or an ASSUAN error code
**/
gpg_error_t
assuan_inquire (assuan_context_t ctx, const char *keyword,
unsigned char **r_buffer, size_t *r_length, size_t maxlen)
{
gpg_error_t rc;
struct membuf mb;
char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
unsigned char *line, *p;
int linelen;
int nodataexpected;
if (r_buffer)
*r_buffer = NULL;
if (r_length)
*r_length = 0;
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
nodataexpected = !r_buffer && !r_length && !maxlen;
if (!nodataexpected && (!r_buffer || !r_length))
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!ctx->is_server)
return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER);
if (ctx->in_inquire)
return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
ctx->in_inquire = 1;
if (nodataexpected)
memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
else
init_membuf (ctx, &mb, maxlen? maxlen:1024, maxlen);
strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
rc = assuan_write_line (ctx, cmdbuf);
if (rc)
goto out;
for (;;)
{
do
{
do
rc = _assuan_read_line (ctx);
while (_assuan_error_is_eagain (ctx, rc));
if (rc)
goto out;
line = (unsigned char *) ctx->inbound.line;
linelen = ctx->inbound.linelen;
}
while (*line == '#' || !linelen);
/* Note: As a convenience for manual testing we allow case
insensitive keywords. */
if ((line[0] == 'E'||line[0] == 'e')
&& (line[1] == 'N' || line[1] == 'n')
&& (line[2] == 'D' || line[2] == 'd')
&& (!line[3] || line[3] == ' '))
break; /* END command received*/
if ((line[0] == 'C' || line[0] == 'c')
&& (line[1] == 'A' || line[1] == 'a')
&& (line[2] == 'N' || line[2] == 'n'))
{
rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
goto out;
}
if ((line[0] != 'D' && line[0] != 'd')
|| line[1] != ' ' || nodataexpected)
{
rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
goto out;
}
if (linelen < 3)
continue;
line += 2;
linelen -= 2;
if (mb.too_large)
continue; /* Need to read up the remaining data. */
p = line;
while (linelen)
{
for (;linelen && *p != '%'; linelen--, p++)
;
put_membuf (ctx, &mb, line, p-line);
if (linelen > 2)
{ /* handle escaping */
unsigned char tmp[1];
p++;
*tmp = xtoi_2 (p);
p += 2;
linelen -= 3;
put_membuf (ctx, &mb, tmp, 1);
}
line = p;
}
}
if (!nodataexpected)
{
if (mb.too_large)
rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA);
else
{
*r_buffer = get_membuf (ctx, &mb, r_length);
if (!*r_buffer)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
}
}
out:
if (!nodataexpected)
free_membuf (ctx, &mb);
ctx->in_inquire = 0;
return rc;
}
void
_assuan_inquire_release (assuan_context_t ctx)
{
if (ctx->in_inquire)
{
if (ctx->inquire_membuf)
{
free_membuf (ctx, ctx->inquire_membuf);
free (ctx->inquire_membuf);
}
ctx->in_inquire = 0;
}
}
gpg_error_t
_assuan_inquire_ext_cb (assuan_context_t ctx)
{
gpg_error_t rc;
unsigned char *line;
int linelen;
struct membuf *mb;
unsigned char *p;
line = (unsigned char *) ctx->inbound.line;
linelen = ctx->inbound.linelen;
mb = ctx->inquire_membuf;
if ((line[0] == 'C' || line[0] == 'c')
&& (line[1] == 'A' || line[1] == 'a')
&& (line[2] == 'N' || line[2] == 'n'))
{
rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
goto out;
}
if ((line[0] == 'E'||line[0] == 'e')
&& (line[1] == 'N' || line[1] == 'n')
&& (line[2] == 'D' || line[2] == 'd')
&& (!line[3] || line[3] == ' '))
{
rc = 0;
goto out;
}
if ((line[0] != 'D' && line[0] != 'd') || line[1] != ' ' || mb == NULL)
{
rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
goto out;
}
if (linelen < 3)
return 0;
line += 2;
linelen -= 2;
p = line;
while (linelen)
{
for (;linelen && *p != '%'; linelen--, p++)
;
put_membuf (ctx, mb, line, p-line);
if (linelen > 2)
{ /* handle escaping */
unsigned char tmp[1];
p++;
*tmp = xtoi_2 (p);
p += 2;
linelen -= 3;
put_membuf (ctx, mb, tmp, 1);
}
line = p;
}
if (mb->too_large)
{
rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA);
goto out;
}
return 0;
out:
{
size_t buf_len = 0;
unsigned char *buf = NULL;
if (mb)
{
buf = get_membuf (ctx, mb, &buf_len);
if (!buf)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
free_membuf (ctx, mb);
free (mb);
ctx->inquire_membuf = NULL;
}
ctx->in_inquire = 0;
rc = (ctx->inquire_cb) (ctx->inquire_cb_data, rc, buf, buf_len);
}
return rc;
}
/**
* assuan_inquire_ext:
* @ctx: An assuan context
* @keyword: The keyword used for the inquire
* @maxlen: If not 0, the size limit of the inquired data.
* @cb: A callback handler which is invoked after the operation completed.
* @cb_data: A user-provided value passed to the callback handler.
*
* A server may use this to send an inquire. R_BUFFER, R_LENGTH and
* MAXLEN may all be NULL/0 to indicate that no real data is expected.
*
* Return value: 0 on success or an ASSUAN error code
**/
gpg_error_t
assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen,
gpg_error_t (*cb) (void *cb_data, gpg_error_t rc,
unsigned char *buf, size_t len),
void *cb_data)
{
gpg_error_t rc;
struct membuf *mb = NULL;
char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!ctx->is_server)
return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER);
if (ctx->in_inquire)
return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
mb = malloc (sizeof (struct membuf));
if (!mb)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
init_membuf (ctx, mb, maxlen ? maxlen : 1024, maxlen);
strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
rc = assuan_write_line (ctx, cmdbuf);
if (rc)
{
free_membuf (ctx, mb);
free (mb);
return rc;
}
ctx->in_inquire = 1;
/* Set up the continuation. */
ctx->inquire_cb = cb;
ctx->inquire_cb_data = cb_data;
ctx->inquire_membuf = mb;
return 0;
}
diff --git a/src/assuan-io.c b/src/assuan-io.c
index 8bb8ed9..b3b22fd 100644
--- a/src/assuan-io.c
+++ b/src/assuan-io.c
@@ -1,61 +1,62 @@
/* assuan-io.c - Wraps the read and write functions.
- Copyright (C) 2002, 2004, 2006-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 .
+ * Copyright (C) 2002, 2004, 2006-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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#ifdef HAVE_SYS_TIME_H
# include
#endif
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifdef HAVE_SYS_SOCKET_H
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
-# endif
+# endif
# include
#else
# include
#endif
#include "assuan-defs.h"
ssize_t
_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
{
return _assuan_read (ctx, ctx->inbound.fd, buffer, size);
}
ssize_t
_assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
{
return _assuan_write (ctx, ctx->outbound.fd, buffer, size);
}
diff --git a/src/assuan-listen.c b/src/assuan-listen.c
index 2c589ab..6755d59 100644
--- a/src/assuan-listen.c
+++ b/src/assuan-listen.c
@@ -1,175 +1,176 @@
-/* assuan-listen.c - Wait for a connection (server)
- Copyright (C) 2001, 2002, 2004, 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 .
+/* assuan-listen.c - Wait for a connection (server)
+ * Copyright (C) 2001, 2002, 2004, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#include "assuan-defs.h"
gpg_error_t
assuan_set_hello_line (assuan_context_t ctx, const char *line)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!line)
{
_assuan_free (ctx, ctx->hello_line);
ctx->hello_line = NULL;
}
else
{
char *buf = _assuan_malloc (ctx, 3 + strlen (line) + 1);
if (!buf)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
if (strchr (line, '\n'))
strcpy (buf, line);
else
{
strcpy (buf, "OK ");
strcpy (buf+3, line);
}
_assuan_free (ctx, ctx->hello_line);
ctx->hello_line = buf;
}
return 0;
}
/**
* assuan_accept:
* @ctx: context
- *
+ *
* Cancel any existing connection and wait for a connection from a
* client. The initial handshake is performed which may include an
* initial authentication or encryption negotiation.
- *
+ *
* Return value: 0 on success or an error if the connection could for
* some reason not be established.
**/
gpg_error_t
assuan_accept (assuan_context_t ctx)
{
gpg_error_t rc = 0;
const char *p, *pend;
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (ctx->max_accepts != -1)
{
if (ctx->max_accepts-- == 0)
return -1; /* second invocation for pipemode -> terminate */
}
if (ctx->accept_handler)
{
/* FIXME: This should be superfluous, if everything else is
correct. */
ctx->finish_handler (ctx);
rc = ctx->accept_handler (ctx);
if (rc)
return rc;
}
/* Send the hello. */
p = ctx->hello_line;
if (p && (pend = strchr (p, '\n')))
{ /* This is a multi line hello. Send all but the last line as
comments. */
do
{
rc = _assuan_write_line (ctx, "# ", p, pend - p);
if (rc)
return rc;
p = pend + 1;
pend = strchr (p, '\n');
}
while (pend);
rc = _assuan_write_line (ctx, "OK ", p, strlen (p));
}
else if (p)
rc = assuan_write_line (ctx, p);
else
{
static char const okstr[] = "OK Pleased to meet you";
pid_t apid = assuan_get_pid (ctx);
if (apid != ASSUAN_INVALID_PID)
{
char tmpbuf[50];
snprintf (tmpbuf, sizeof tmpbuf, "%s, process %i", okstr, (int)apid);
rc = assuan_write_line (ctx, tmpbuf);
}
else
rc = assuan_write_line (ctx, okstr);
}
if (rc)
return rc;
-
+
return 0;
}
assuan_fd_t
assuan_get_input_fd (assuan_context_t ctx)
{
return ctx ? ctx->input_fd : ASSUAN_INVALID_FD;
}
assuan_fd_t
assuan_get_output_fd (assuan_context_t ctx)
{
return ctx ? ctx->output_fd : ASSUAN_INVALID_FD;
}
/* Close the fd descriptor set by the command INPUT FD=n. We handle
this fd inside assuan so that we can do some initial checks */
gpg_error_t
assuan_close_input_fd (assuan_context_t ctx)
{
if (!ctx || ctx->input_fd == ASSUAN_INVALID_FD)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
_assuan_close (ctx, ctx->input_fd);
ctx->input_fd = ASSUAN_INVALID_FD;
return 0;
}
/* Close the fd descriptor set by the command OUTPUT FD=n. We handle
this fd inside assuan so that we can do some initial checks */
gpg_error_t
assuan_close_output_fd (assuan_context_t ctx)
{
if (!ctx || ctx->output_fd == ASSUAN_INVALID_FD)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
_assuan_close (ctx, ctx->output_fd);
ctx->output_fd = ASSUAN_INVALID_FD;
return 0;
}
diff --git a/src/assuan-logging.c b/src/assuan-logging.c
index fd47582..8ee6aa2 100644
--- a/src/assuan-logging.c
+++ b/src/assuan-logging.c
@@ -1,304 +1,305 @@
/* assuan-logging.c - Default logging function.
- Copyright (C) 2002, 2003, 2004, 2007, 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 .
+ * Copyright (C) 2002, 2003, 2004, 2007, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
#endif /*HAVE_W32_SYSTEM*/
#include
#include
#include "assuan-defs.h"
/* The default log handler is useful for global logging, but it should
only be used by one user of libassuan at a time. Libraries that
use libassuan can register their own log handler. */
/* A common prefix for all log messages. */
static char prefix_buffer[80];
/* A global flag read from the environment to check if to enable full
logging of buffer data. This is also used by custom log
handlers. */
static int full_logging;
/* A bitfield that specifies the categories to log. */
static int log_cats;
#define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
static FILE *_assuan_log;
void
_assuan_init_log_envvars (void)
{
char *flagstr;
full_logging = !!getenv ("ASSUAN_FULL_LOGGING");
flagstr = getenv ("ASSUAN_DEBUG");
if (flagstr)
log_cats = atoi (flagstr);
else /* Default to log the control channel. */
log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
_assuan_sysutils_blurb (); /* Make sure this code gets linked in. */
}
void
assuan_set_assuan_log_stream (FILE *fp)
{
_assuan_log = fp;
_assuan_init_log_envvars ();
}
/* Set the per context log stream. Also enable the default log stream
if it has not been set. */
void
assuan_set_log_stream (assuan_context_t ctx, FILE *fp)
{
if (ctx)
{
if (ctx->log_fp)
fflush (ctx->log_fp);
ctx->log_fp = fp;
if (! _assuan_log)
assuan_set_assuan_log_stream (fp);
}
}
/* Set the prefix to be used for logging to TEXT or resets it to the
default if TEXT is NULL. */
void
assuan_set_assuan_log_prefix (const char *text)
{
if (text)
{
strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
prefix_buffer[sizeof (prefix_buffer)-1] = 0;
}
else
*prefix_buffer = 0;
}
/* Get the prefix to be used for logging. */
const char *
assuan_get_assuan_log_prefix (void)
{
return prefix_buffer;
}
/* Default log handler. */
int
_assuan_log_handler (assuan_context_t ctx, void *hook, unsigned int cat,
const char *msg)
{
FILE *fp;
const char *prf;
int saved_errno = errno;
/* For now. */
if (msg == NULL)
return TEST_LOG_CAT (cat);
if (! TEST_LOG_CAT (cat))
return 0;
fp = ctx->log_fp ? ctx->log_fp : _assuan_log;
if (!fp)
return 0;
prf = assuan_get_assuan_log_prefix ();
if (*prf)
fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ());
fprintf (fp, "%s", msg);
/* If the log stream is a file, the output would be buffered. This
is bad for debugging, thus we flush the stream if FORMAT ends
with a LF. */
if (msg && *msg && msg[strlen (msg) - 1] == '\n')
fflush (fp);
gpg_err_set_errno (saved_errno);
return 0;
}
/* Log a control channel message. This is either a STRING with a
diagnostic or actual data in (BUFFER1,LENGTH1) and
(BUFFER2,LENGTH2). If OUTBOUND is true the data is intended for
the peer. */
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)
{
int res;
char *outbuf;
int saved_errno;
/* Check whether logging is enabled and do a quick check to see
whether the callback supports our category. */
if (!ctx
|| !ctx->log_cb
|| ctx->flags.no_logging
|| !(*ctx->log_cb) (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, NULL))
return;
saved_errno = errno;
/* Note that we use the inbound channel fd as the printed channel
number for both directions. */
#ifdef HAVE_W32_SYSTEM
# define CHANNEL_FMT "%p"
#else
# define CHANNEL_FMT "%d"
#endif
#define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a'))
if (!buffer1 && buffer2)
{
buffer1 = buffer2;
length1 = length2;
buffer2 = NULL;
length2 = 0;
}
if (ctx->flags.confidential && !string && buffer1)
string = "[Confidential data not shown]";
if (string)
{
/* Print the diagnostic. */
res = gpgrt_asprintf (&outbuf, "chan_" CHANNEL_FMT " %s [%s]\n",
ctx->inbound.fd, outbound? "->":"<-", string);
}
else if (buffer1)
{
/* Print the control channel data. */
const unsigned char *s;
unsigned int n, x;
for (n = length1, s = buffer1; n; n--, s++)
if ((!isascii (*s) || iscntrl (*s) || !isprint (*s) || !*s)
&& !(*s >= 0x80))
break;
if (!n && buffer2)
{
for (n = length2, s = buffer2; n; n--, s++)
if ((!isascii (*s) || iscntrl (*s) || !isprint (*s) || !*s)
&& !(*s >= 0x80))
break;
}
if (!buffer2)
length2 = 0;
if (!n && (length1 && *(const char*)buffer1 != '['))
{
/* No control characters and not starting with our error
message indicator. Log it verbatim. */
res = gpgrt_asprintf (&outbuf, "chan_" CHANNEL_FMT " %s %.*s%.*s\n",
ctx->inbound.fd, outbound? "->":"<-",
(int)length1, (const char*)buffer1,
(int)length2, buffer2? (const char*)buffer2:"");
}
else
{
/* The buffer contains control characters - do a hex dump.
Even in full logging mode we limit the line length -
however this is no real limit because the provided
buffers will never be larger than the maximum assuan line
length. */
char *hp;
unsigned int nbytes;
unsigned int maxbytes = full_logging? (2*LINELENGTH) : 16;
nbytes = length1 + length2;
if (nbytes > maxbytes)
nbytes = maxbytes;
if (!(outbuf = malloc (50 + 3*nbytes + 60 + 3 + 1)))
res = -1;
else
{
res = 0;
hp = outbuf;
snprintf (hp, 50, "chan_" CHANNEL_FMT " %s [",
ctx->inbound.fd, outbound? "->":"<-");
hp += strlen (hp);
n = 0;
for (s = buffer1, x = 0; x < length1 && n < nbytes; x++, n++)
{
*hp++ = ' ';
*hp++ = TOHEX (*s >> 4);
*hp++ = TOHEX (*s & 0x0f);
s++;
}
for (s = buffer2, x = 0; x < length2 && n < nbytes; x++, n++)
{
*hp++ = ' ';
*hp++ = TOHEX (*s >> 4);
*hp++ = TOHEX (*s & 0x0f);
s++;
}
if (nbytes < length1 + length2)
{
snprintf (hp, 60, " ...(%u byte(s) skipped)",
(unsigned int)((length1+length2) - nbytes));
hp += strlen (hp);
}
strcpy (hp, " ]\n");
}
}
}
else
{
res = 0;
outbuf = NULL;
}
if (res < 0)
ctx->log_cb (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL,
"[libassuan failed to format the log message]");
else if (outbuf)
{
ctx->log_cb (ctx, ctx->log_cb_data, ASSUAN_LOG_CONTROL, outbuf);
gpgrt_free (outbuf);
}
#undef TOHEX
#undef CHANNEL_FMT
gpg_err_set_errno (saved_errno);
}
diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c
index a657c94..1589d79 100644
--- a/src/assuan-pipe-connect.c
+++ b/src/assuan-pipe-connect.c
@@ -1,428 +1,429 @@
/* 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
/* On Windows systems signal.h is not needed and even not supported on
WindowsCE. */
#ifndef HAVE_DOSISH_SYSTEM
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#ifdef HAVE_FCNTL_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifndef HAVE_W32_SYSTEM
# include
#else
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
#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)
{
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)
{
struct at_pipe_fork *atp = opaque;
if (atp->user_atfork)
atp->user_atfork (atp->user_atforkvalue, reserved);
#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];
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],
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);
}
/* 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;
ctx->engine.sendfd = NULL;
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->pid = 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)
{
struct at_socketpair_fork *atp = opaque;
if (atp->user_atfork)
atp->user_atfork (atp->user_atforkvalue, reserved);
#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,
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,
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')
{
_assuan_close (ctx, fds[0]);
return 0;
}
_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);
if (flags & ASSUAN_PIPE_CONNECT_FDPASSING)
{
#ifdef HAVE_W32_SYSTEM
return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
#else
return socketpair_connect (ctx, name, argv, fd_child_list,
atfork, atforkvalue);
#endif
}
else
return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue,
flags);
}
diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c
index 017dc7b..c78abcd 100644
--- a/src/assuan-pipe-server.c
+++ b/src/assuan-pipe-server.c
@@ -1,134 +1,135 @@
-/* assuan-pipe-server.c - Assuan server working over a pipe
- Copyright (C) 2001, 2002, 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 .
+/* assuan-pipe-server.c - Assuan server working over a pipe
+ * Copyright (C) 2001, 2002, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifdef HAVE_SYS_STAT_H
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
-# endif
+# endif
# include
#ifdef HAVE_FCNTL_H
# include
#endif
#endif
#include "assuan-defs.h"
#include "debug.h"
/* Returns true if atoi(S) denotes a valid socket. */
#ifndef HAVE_W32_SYSTEM
static int
is_valid_socket (const char *s)
{
struct stat buf;
if ( fstat (atoi (s), &buf ) )
return 0;
return S_ISSOCK (buf.st_mode);
}
#endif /*!HAVE_W32_SYSTEM*/
/* This actually is a int file descriptor (and not assuan_fd_t) as
_get_osfhandle is called on W32 systems. */
gpg_error_t
assuan_init_pipe_server (assuan_context_t ctx, assuan_fd_t filedes[2])
{
const char *s;
unsigned long ul;
gpg_error_t rc;
assuan_fd_t infd = ASSUAN_INVALID_FD;
assuan_fd_t outfd = ASSUAN_INVALID_FD;
int is_usd = 0;
TRACE_BEG (ctx, ASSUAN_LOG_CTX, "assuan_init_pipe_server", ctx);
if (filedes)
{
TRACE_LOG2 ("fd[0]=0x%x, fd[1]=0x%x", filedes[0], filedes[1]);
}
-
+
rc = _assuan_register_std_commands (ctx);
if (rc)
return TRACE_ERR (rc);
#ifdef HAVE_W32_SYSTEM
infd = filedes[0];
outfd = filedes[1];
#else
s = getenv ("_assuan_connection_fd");
if (s && *s && is_valid_socket (s))
{
/* Well, we are called with an bi-directional file descriptor.
Prepare for using sendmsg/recvmsg. In this case we ignore
the passed file descriptors. */
infd = atoi (s);
outfd = atoi (s);
is_usd = 1;
}
- else if (filedes && filedes[0] != ASSUAN_INVALID_FD
+ else if (filedes && filedes[0] != ASSUAN_INVALID_FD
&& filedes[1] != ASSUAN_INVALID_FD )
{
/* Standard pipe server. */
infd = filedes[0];
outfd = filedes[1];
}
else
{
rc = _assuan_error (ctx, GPG_ERR_ASS_SERVER_START);
return TRACE_ERR (rc);
}
#endif
ctx->is_server = 1;
ctx->engine.release = _assuan_server_release;
ctx->engine.readfnc = _assuan_simple_read;
ctx->engine.writefnc = _assuan_simple_write;
ctx->engine.sendfd = NULL;
ctx->engine.receivefd = NULL;
ctx->max_accepts = 1;
s = getenv ("_assuan_pipe_connect_pid");
if (s && (ul=strtoul (s, NULL, 10)) && ul)
ctx->pid = (pid_t)ul;
else
ctx->pid = (pid_t)-1;
ctx->accept_handler = NULL;
ctx->finish_handler = _assuan_server_finish;
ctx->inbound.fd = infd;
ctx->outbound.fd = outfd;
if (is_usd)
_assuan_init_uds_io (ctx);
return TRACE_SUC();
}
diff --git a/src/assuan-socket-connect.c b/src/assuan-socket-connect.c
index 3d3176e..c54c44d 100644
--- a/src/assuan-socket-connect.c
+++ b/src/assuan-socket-connect.c
@@ -1,349 +1,350 @@
/* assuan-socket-connect.c - Assuan socket based client
- Copyright (C) 2002, 2003, 2004, 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 .
+ * Copyright (C) 2002, 2003, 2004, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#include
#include
#include
#include
#include
#include
#ifdef HAVE_STDINT_H
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
#else
# include
# include
# include
# include
#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
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long)(-1))
#endif /*INADDR_NONE*/
#ifndef SUN_LEN
# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ strlen ((ptr)->sun_path))
#endif
#undef WITH_IPV6
#if defined (AF_INET6) && defined(PF_INET) \
&& defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON)
# define WITH_IPV6 1
#endif
/* Returns true if STR represents a valid port number in decimal
notation and no garbage is following. */
static int
parse_portno (const char *str, uint16_t *r_port)
{
unsigned int value;
for (value=0; *str && (*str >= '0' && *str <= '9'); str++)
{
value = value * 10 + (*str - '0');
if (value > 65535)
return 0;
}
if (*str || !value)
return 0;
*r_port = value;
return 1;
}
static gpg_error_t
_assuan_connect_finalize (assuan_context_t ctx, assuan_fd_t fd,
unsigned int flags)
{
gpg_error_t err;
ctx->engine.release = _assuan_client_release;
ctx->engine.readfnc = _assuan_simple_read;
ctx->engine.writefnc = _assuan_simple_write;
ctx->engine.sendfd = NULL;
ctx->engine.receivefd = NULL;
ctx->finish_handler = _assuan_client_finish;
ctx->inbound.fd = fd;
ctx->outbound.fd = fd;
ctx->max_accepts = -1;
if (flags & ASSUAN_SOCKET_CONNECT_FDPASSING)
_assuan_init_uds_io (ctx);
/* initial handshake */
{
assuan_response_t response;
int off;
err = _assuan_read_from_server (ctx, &response, &off, 0);
if (err)
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
"can't connect to server: %s\n", gpg_strerror (err));
else if (response != ASSUAN_RESPONSE_OK)
{
char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line);
if (sname)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
"can't connect to server: %s", sname);
_assuan_free (ctx, sname);
}
err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
}
}
return err;
}
/* Attach an existing connected file descriptor FD to an allocated handle CTX
* and initialize the connection.
*/
gpg_error_t
assuan_socket_connect_fd (assuan_context_t ctx, int fd, unsigned int flags)
{
gpg_error_t err;
assuan_fd_t afd;
if (!ctx || fd < 0)
return GPG_ERR_INV_ARG;
afd = assuan_fd_from_posix_fd (fd);
if (afd == ASSUAN_INVALID_FD)
return GPG_ERR_INV_ARG;
err = _assuan_connect_finalize(ctx, afd, flags);
if (err)
_assuan_reset (ctx);
return err;
}
/* Make a connection to the Unix domain socket NAME and return a new
Assuan context in CTX. SERVER_PID is currently not used but may
become handy in the future. Defined flag bits are:
ASSUAN_SOCKET_CONNECT_FDPASSING
sendmsg and recvmsg are used.
NAME must either start with a slash and optional with a drive
prefix ("c:") or use one of these URL schemata:
file://
This is the same as the default just with an explicit schemata.
assuan://:
assuan://[]:
Connect using TCP to PORT of the server with the numerical
IPADDR. Note that '[' and ']' are literal characters.
*/
gpg_error_t
assuan_socket_connect (assuan_context_t ctx, const char *name,
pid_t server_pid, unsigned int flags)
{
gpg_error_t err = 0;
assuan_fd_t fd;
#ifdef WITH_IPV6
struct sockaddr_in6 srvr_addr_in6;
#endif
struct sockaddr_un srvr_addr_un;
struct sockaddr_in srvr_addr_in;
struct sockaddr *srvr_addr = NULL;
uint16_t port = 0;
size_t len = 0;
const char *s;
int af = AF_LOCAL;
int pf = PF_LOCAL;
TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_socket_connect", ctx,
"name=%s, flags=0x%x", name ? name : "(null)", flags);
if (!ctx || !name)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!strncmp (name, "file://", 7) && name[7])
name += 7;
else if (!strncmp (name, "assuan://", 9) && name[9])
{
name += 9;
af = AF_INET;
pf = PF_INET;
}
else /* Default. */
{
/* We require that the name starts with a slash if no URL
schemata is used. To make things easier we allow an optional
drive prefix. */
s = name;
if (*s && s[1] == ':')
s += 2;
if (*s != DIRSEP_C && *s != '/')
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
}
if (af == AF_LOCAL)
{
int redirected;
if (_assuan_sock_set_sockaddr_un (name, (struct sockaddr *)&srvr_addr_un,
&redirected))
return _assuan_error (ctx, gpg_err_code_from_syserror ());
len = SUN_LEN (&srvr_addr_un);
srvr_addr = (struct sockaddr *)&srvr_addr_un;
}
else
{
char *addrstr, *p;
#ifdef HAVE_INET_PTON
void *addrbuf = NULL;
#endif
addrstr = _assuan_malloc (ctx, strlen (name) + 1);
if (!addrstr)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
if (*name == '[')
{
strcpy (addrstr, name+1);
p = strchr (addrstr, ']');
if (!p || p[1] != ':' || !parse_portno (p+2, &port))
err = _assuan_error (ctx, GPG_ERR_BAD_URI);
else
{
*p = 0;
#ifdef WITH_IPV6
af = AF_INET6;
pf = PF_INET6;
memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
srvr_addr_in6.sin6_family = af;
srvr_addr_in6.sin6_port = htons (port);
#ifdef HAVE_INET_PTON
addrbuf = &srvr_addr_in6.sin6_addr;
#endif
srvr_addr = (struct sockaddr *)&srvr_addr_in6;
len = sizeof srvr_addr_in6;
#else
err = _assuan_error (ctx, GPG_ERR_EAFNOSUPPORT);
#endif
}
}
else
{
strcpy (addrstr, name);
p = strchr (addrstr, ':');
if (!p || !parse_portno (p+1, &port))
err = _assuan_error (ctx, GPG_ERR_BAD_URI);
else
{
*p = 0;
memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
srvr_addr_in.sin_family = af;
srvr_addr_in.sin_port = htons (port);
#ifdef HAVE_INET_PTON
addrbuf = &srvr_addr_in.sin_addr;
#endif
srvr_addr = (struct sockaddr *)&srvr_addr_in;
len = sizeof srvr_addr_in;
}
}
if (!err)
{
#ifdef HAVE_INET_PTON
switch (inet_pton (af, addrstr, addrbuf))
{
case 1: break;
case 0: err = _assuan_error (ctx, GPG_ERR_BAD_URI); break;
default: err = _assuan_error (ctx, gpg_err_code_from_syserror ());
}
#else /*!HAVE_INET_PTON*/
/* We need to use the old function. If we are here v6
support isn't enabled anyway and thus we can do fine
without. Note that Windows as a compatible inet_pton
function named inetPton, but only since Vista. */
srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
err = _assuan_error (ctx, GPG_ERR_BAD_URI);
#endif /*!HAVE_INET_PTON*/
}
_assuan_free (ctx, addrstr);
if (err)
return err;
}
fd = _assuan_sock_new (ctx, pf, SOCK_STREAM, 0);
if (fd == ASSUAN_INVALID_FD)
{
err = _assuan_error (ctx, gpg_err_code_from_syserror ());
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
"can't create socket: %s", strerror (errno));
return err;
}
if (_assuan_sock_connect (ctx, fd, srvr_addr, len) == -1)
{
TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
"can't connect to `%s': %s\n", name, strerror (errno));
_assuan_close (ctx, fd);
return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
}
err = _assuan_connect_finalize (ctx, fd, flags);
if (err)
_assuan_reset (ctx);
return err;
}
diff --git a/src/assuan-socket-server.c b/src/assuan-socket-server.c
index 964720b..a5b7fd7 100644
--- a/src/assuan-socket-server.c
+++ b/src/assuan-socket-server.c
@@ -1,227 +1,228 @@
/* assuan-socket-server.c - Assuan socket based server
- Copyright (C) 2002, 2007, 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 .
+ * Copyright (C) 2002, 2007, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifdef HAVE_UCRED_H
#include
#endif
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
-# endif
+# endif
# include
# if HAVE_SYS_SOCKET_H
# include
# elif HAVE_WS2TCPIP_H
# include
# endif
#else
# include
# include
#endif
#include "debug.h"
#include "assuan-defs.h"
static gpg_error_t
accept_connection_bottom (assuan_context_t ctx)
{
assuan_fd_t fd = ctx->connected_fd;
TRACE (ctx, ASSUAN_LOG_SYSIO, "accept_connection_bottom", ctx);
ctx->peercred_valid = 0;
#ifdef HAVE_SO_PEERCRED
{
struct ucred cr;
socklen_t cl = sizeof cr;
if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
{
ctx->peercred.pid = cr.pid;
ctx->peercred.uid = cr.uid;
ctx->peercred.gid = cr.gid;
ctx->peercred_valid = 1;
/* This overrides any already set PID if the function returns
a valid one. */
if (cr.pid != ASSUAN_INVALID_PID && cr.pid)
ctx->pid = cr.pid;
}
}
#elif defined (HAVE_GETPEERUCRED)
{
ucred_t *ucred = NULL;
if (getpeerucred (fd, &ucred) != -1)
{
ctx->peercred.uid = ucred_geteuid (ucred);
ctx->peercred.gid = ucred_getegid (ucred);
ctx->peercred.pid = ucred_getpid (ucred);
ctx->peercred_valid = 1;
ucred_free (ucred);
}
}
#elif defined (HAVE_LOCAL_PEEREID)
{
struct unpcbid unp;
socklen_t unpl = sizeof unp;
if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
{
ctx->peercred.pid = unp.unp_pid;
ctx->peercred.uid = unp.unp_euid;
ctx->peercred.gid = unp.unp_egid;
ctx->peercred_valid = 1;
}
}
#elif defined(HAVE_GETPEEREID)
{
if (getpeereid (fd, &ctx->peercred.uid, &ctx->peercred.gid) != -1)
{
ctx->peercred.pid = ASSUAN_INVALID_PID;
ctx->peercred_valid = 1;
}
}
#endif
ctx->inbound.fd = fd;
ctx->inbound.eof = 0;
ctx->inbound.linelen = 0;
ctx->inbound.attic.linelen = 0;
ctx->inbound.attic.pending = 0;
ctx->outbound.fd = fd;
ctx->outbound.data.linelen = 0;
ctx->outbound.data.error = 0;
-
+
ctx->flags.confidential = 0;
return 0;
}
static gpg_error_t
accept_connection (assuan_context_t ctx)
{
assuan_fd_t fd;
struct sockaddr_un clnt_addr;
socklen_t len = sizeof clnt_addr;
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "accept_connection", ctx,
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "accept_connection", ctx,
"listen_fd=0x%x", ctx->listen_fd);
- fd = SOCKET2HANDLE(accept (HANDLE2SOCKET(ctx->listen_fd),
+ fd = SOCKET2HANDLE(accept (HANDLE2SOCKET(ctx->listen_fd),
(struct sockaddr*)&clnt_addr, &len ));
if (fd == ASSUAN_INVALID_FD)
{
return _assuan_error (ctx, gpg_err_code_from_syserror ());
}
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "accept_connection", ctx,
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "accept_connection", ctx,
"fd->0x%x", fd);
if (_assuan_sock_check_nonce (ctx, fd, &ctx->listen_nonce))
{
_assuan_close (ctx, fd);
return _assuan_error (ctx, GPG_ERR_ASS_ACCEPT_FAILED);
}
ctx->connected_fd = fd;
return accept_connection_bottom (ctx);
}
-/*
+/*
Flag bits: 0 - use sendmsg/recvmsg to allow descriptor passing
1 - FD has already been accepted.
*/
gpg_error_t
assuan_init_socket_server (assuan_context_t ctx, assuan_fd_t fd,
unsigned int flags)
{
gpg_error_t rc;
TRACE_BEG2 (ctx, ASSUAN_LOG_CTX, "assuan_init_socket_server", ctx,
"fd=0x%x, flags=0x%x", fd, flags);
-
+
rc = _assuan_register_std_commands (ctx);
if (rc)
return TRACE_ERR (rc);
ctx->engine.release = _assuan_server_release;
ctx->engine.readfnc = _assuan_simple_read;
ctx->engine.writefnc = _assuan_simple_write;
ctx->engine.sendfd = NULL;
ctx->engine.receivefd = NULL;
ctx->is_server = 1;
if (flags & ASSUAN_SOCKET_SERVER_ACCEPTED)
/* We want a second accept to indicate EOF. */
ctx->max_accepts = 1;
else
ctx->max_accepts = -1;
ctx->input_fd = ASSUAN_INVALID_FD;
ctx->output_fd = ASSUAN_INVALID_FD;
ctx->inbound.fd = ASSUAN_INVALID_FD;
ctx->outbound.fd = ASSUAN_INVALID_FD;
if (flags & ASSUAN_SOCKET_SERVER_ACCEPTED)
{
ctx->listen_fd = ASSUAN_INVALID_FD;
ctx->connected_fd = fd;
}
else
{
ctx->listen_fd = fd;
ctx->connected_fd = ASSUAN_INVALID_FD;
}
ctx->accept_handler = ((flags & ASSUAN_SOCKET_SERVER_ACCEPTED)
- ? accept_connection_bottom
+ ? accept_connection_bottom
: accept_connection);
ctx->finish_handler = _assuan_server_finish;
if (flags & ASSUAN_SOCKET_SERVER_FDPASSING)
_assuan_init_uds_io (ctx);
rc = _assuan_register_std_commands (ctx);
if (rc)
_assuan_reset (ctx);
return TRACE_ERR (rc);
}
/* Save a copy of NONCE in context CTX. This should be used to
register the server's nonce with an context established by
assuan_init_socket_server. */
void
assuan_set_sock_nonce (assuan_context_t ctx, assuan_sock_nonce_t *nonce)
{
if (ctx && nonce)
ctx->listen_nonce = *nonce;
}
diff --git a/src/assuan-socket.c b/src/assuan-socket.c
index 147ec2a..adcd40a 100644
--- a/src/assuan-socket.c
+++ b/src/assuan-socket.c
@@ -1,1496 +1,1497 @@
/* assuan-socket.c - Socket wrapper
- Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
- Copyright (C) 2001-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 .
+ * Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2001-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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef HAVE_W32_SYSTEM
# define WIN32_LEAN_AND_MEAN
# include
# include
#ifndef HAVE_W32CE_SYSTEM
# include
#endif
#else
# include
# include
# include
# include
#endif
#include
#ifdef HAVE_SYS_STAT_H
# include
#endif
#ifdef HAVE_FCNTL_H
#include
#endif
#include
#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
#ifdef HAVE_W32_SYSTEM
#ifndef S_IRUSR
# define S_IRUSR 0
# define S_IWUSR 0
#endif
#ifndef S_IRGRP
# define S_IRGRP 0
# define S_IWGRP 0
#endif
#ifndef ENOTSUP
#define ENOTSUP 129
#endif
#ifndef EPROTO
#define EPROTO 134
#endif
#ifndef EPROTONOSUPPORT
#define EPROTONOSUPPORT 135
#endif
#ifndef ENETDOWN
#define ENETDOWN 116
#endif
#ifndef ENETUNREACH
#define ENETUNREACH 118
#endif
#ifndef EHOSTUNREACH
#define EHOSTUNREACH 110
#endif
#ifndef ECONNREFUSED
#define ECONNREFUSED 107
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT 138
#endif
#endif
#ifndef ENAMETOOLONG
# define ENAMETOOLONG EINVAL
#endif
#ifndef SUN_LEN
# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ strlen ((ptr)->sun_path))
#endif
#ifndef INADDR_LOOPBACK
# define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) /* 127.0.0.1. */
#endif
/* The standard SOCKS and TOR port. */
#define SOCKS_PORT 1080
#define TOR_PORT 9050
#define TOR_PORT2 9150 /* The Tor browser is listening there. */
/* In the future, we can allow access to sock_ctx, if that context's
hook functions need to be overridden. There can only be one global
assuan_sock_* user (one library or one application) with this
convenience interface, if non-standard hook functions are
needed. */
static assuan_context_t sock_ctx;
/* This global flag can be set using assuan_sock_set_flag to enable
TOR or SOCKS mode for all sockets. It may not be reset. The value
is the port to be used. */
static unsigned short tor_mode;
#ifdef HAVE_W32_SYSTEM
/* A table of active Cygwin connections. This is only used for
listening socket which should be only a few. We do not enter
sockets after a connect into this table. */
static assuan_fd_t cygwin_fdtable[16];
/* A critical section to guard access to the table of Cygwin
connections. */
static CRITICAL_SECTION cygwin_fdtable_cs;
/* Return true if SOCKFD is listed as Cygwin socket. */
static int
is_cygwin_fd (assuan_fd_t sockfd)
{
int ret = 0;
int i;
EnterCriticalSection (&cygwin_fdtable_cs);
for (i=0; i < DIM(cygwin_fdtable); i++)
{
if (cygwin_fdtable[i] == sockfd)
{
ret = 1;
break;
}
}
LeaveCriticalSection (&cygwin_fdtable_cs);
return ret;
}
/* Insert SOCKFD into the table of Cygwin sockets. Return 0 on
success or -1 on error. */
static int
insert_cygwin_fd (assuan_fd_t sockfd)
{
int ret = 0;
int mark = -1;
int i;
EnterCriticalSection (&cygwin_fdtable_cs);
for (i=0; i < DIM(cygwin_fdtable); i++)
{
if (cygwin_fdtable[i] == sockfd)
goto leave; /* Already in table. */
else if (cygwin_fdtable[i] == ASSUAN_INVALID_FD)
mark = i;
}
if (mark == -1)
{
gpg_err_set_errno (EMFILE);
ret = -1;
}
else
cygwin_fdtable[mark] = sockfd;
leave:
LeaveCriticalSection (&cygwin_fdtable_cs);
return ret;
}
/* Delete SOCKFD from the table of Cygwin sockets. */
static void
delete_cygwin_fd (assuan_fd_t sockfd)
{
int i;
EnterCriticalSection (&cygwin_fdtable_cs);
for (i=0; i < DIM(cygwin_fdtable); i++)
{
if (cygwin_fdtable[i] == sockfd)
{
cygwin_fdtable[i] = ASSUAN_INVALID_FD;
break;
}
}
LeaveCriticalSection (&cygwin_fdtable_cs);
return;
}
#ifdef HAVE_W32CE_SYSTEM
static wchar_t *
utf8_to_wchar (const char *string)
{
int n;
size_t nbytes;
wchar_t *result;
if (!string)
return NULL;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
if (n < 0)
return NULL;
nbytes = (size_t)(n+1) * sizeof(*result);
if (nbytes / sizeof(*result) != (n+1))
{
SetLastError (ERROR_INVALID_PARAMETER);
return NULL;
}
result = malloc (nbytes);
if (!result)
return NULL;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
if (n < 0)
{
n = GetLastError ();
free (result);
result = NULL;
SetLastError (n);
}
return result;
}
static HANDLE
MyCreateFile (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
wchar_t *filename;
HANDLE result;
int err;
filename = utf8_to_wchar (lpFileName);
if (!filename)
return INVALID_HANDLE_VALUE;
result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
err = GetLastError ();
free (filename);
SetLastError (err);
return result;
}
static int
MyDeleteFile (LPCSTR lpFileName)
{
wchar_t *filename;
int result, err;
filename = utf8_to_wchar (lpFileName);
if (!filename)
return 0;
result = DeleteFileW (filename);
err = GetLastError ();
free (filename);
SetLastError (err);
return result;
}
#else /*!HAVE_W32CE_SYSTEM*/
#define MyCreateFile CreateFileA
#define MyDeleteFile DeleteFileA
#endif /*!HAVE_W32CE_SYSTEM*/
int
_assuan_sock_wsa2errno (int err)
{
switch (err)
{
case WSAENOTSOCK:
return EINVAL;
case WSAEWOULDBLOCK:
return EAGAIN;
case ERROR_BROKEN_PIPE:
return EPIPE;
case WSANOTINITIALISED:
return ENOSYS;
case WSAECONNREFUSED:
return ECONNREFUSED;
default:
return EIO;
}
}
/* W32: Fill BUFFER with LENGTH bytes of random. Returns -1 on
failure, 0 on success. Sets errno on failure. */
static int
get_nonce (char *buffer, size_t nbytes)
{
HCRYPTPROV prov;
int ret = -1;
if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
(CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
gpg_err_set_errno (ENODEV);
else
{
if (!CryptGenRandom (prov, nbytes, (unsigned char *) buffer))
gpg_err_set_errno (ENODEV);
else
ret = 0;
CryptReleaseContext (prov, 0);
}
return ret;
}
/* W32: The buffer for NONCE needs to be at least 16 bytes. Returns 0
on success and sets errno on failure. If FNAME has a Cygwin socket
descriptor True is stored at CYGWIN. */
static int
read_port_and_nonce (const char *fname, unsigned short *port, char *nonce,
int *cygwin)
{
FILE *fp;
char buffer[50], *p;
size_t nread;
int aval;
*cygwin = 0;
fp = fopen (fname, "rb");
if (!fp)
return -1;
nread = fread (buffer, 1, sizeof buffer - 1, fp);
fclose (fp);
if (!nread)
{
gpg_err_set_errno (ENOENT);
return -1;
}
buffer[nread] = 0;
if (!strncmp (buffer, "!", 10))
{
/* This is the Cygwin compatible socket emulation. The format
* of the file is:
*
* "!%u %c %08x-%08x-%08x-%08x\x00"
*
* %d for port number, %c for kind of socket (s for STREAM), and
* we have 16-byte random bytes for nonce. We only support
* stream mode.
*/
unsigned int u0;
int narr[4];
if (sscanf (buffer+10, "%u s %08x-%08x-%08x-%08x",
&u0, narr+0, narr+1, narr+2, narr+3) != 5
|| u0 < 1 || u0 > 65535)
{
gpg_err_set_errno (EINVAL);
return -1;
}
*port = u0;
memcpy (nonce, narr, 16);
*cygwin = 1;
}
else
{
/* This is our own socket emulation. */
aval = atoi (buffer);
if (aval < 1 || aval > 65535)
{
gpg_err_set_errno (EINVAL);
return -1;
}
*port = (unsigned int)aval;
for (p=buffer; nread && *p != '\n'; p++, nread--)
;
if (*p != '\n' || nread != 17)
{
gpg_err_set_errno (EINVAL);
return -1;
}
p++; nread--;
memcpy (nonce, p, 16);
}
return 0;
}
#endif /*HAVE_W32_SYSTEM*/
#ifndef HAVE_W32_SYSTEM
/* Find a redirected socket name for fname and return a malloced setup
filled sockaddr. If this does not work out NULL is returned and
ERRNO is set. If the file seems to be a redirect True is stored at
R_REDIRECT. Note that this function uses the standard malloc and
not the assuan wrapped one. The format of the file is:
%Assuan%
socket=NAME
where NAME is the actual socket to use. No white spaces are
allowed, both lines must be terminated by a single LF, extra lines
are not allowed. Environment variables are interpreted in NAME if
given in "${VAR} notation; no escape characters are defined, if
"${" shall be used verbatim, you need to use an environment
variable with that content.
The use of an absolute NAME is strongly suggested. The length of
the file is limited to 511 bytes which is more than sufficient for
that common value of 107 for sun_path. */
static struct sockaddr_un *
eval_redirection (const char *fname, int *r_redirect)
{
FILE *fp;
char buffer[512], *name;
size_t n;
struct sockaddr_un *addr;
char *p, *pend;
const char *s;
*r_redirect = 0;
fp = fopen (fname, "rb");
if (!fp)
return NULL;
n = fread (buffer, 1, sizeof buffer - 1, fp);
fclose (fp);
if (!n)
{
gpg_err_set_errno (ENOENT);
return NULL;
}
buffer[n] = 0;
/* Check that it is a redirection file. We also check that the
first byte of the name is not a LF because that would lead to an
zero length name. */
if (n < 17 || buffer[n-1] != '\n'
|| memcmp (buffer, "%Assuan%\nsocket=", 16)
|| buffer[16] == '\n')
{
gpg_err_set_errno (EINVAL);
return NULL;
}
buffer[n-1] = 0;
name = buffer + 16;
*r_redirect = 1;
addr = calloc (1, sizeof *addr);
if (!addr)
return NULL;
addr->sun_family = AF_LOCAL;
n = 0;
for (p=name; *p; p++)
{
if (*p == '$' && p[1] == '{')
{
p += 2;
pend = strchr (p, '}');
if (!pend)
{
free (addr);
gpg_err_set_errno (EINVAL);
return NULL;
}
*pend = 0;
if (*p && (s = getenv (p)))
{
for (; *s; s++)
{
if (n < sizeof addr->sun_path - 1)
addr->sun_path[n++] = *s;
else
{
free (addr);
gpg_err_set_errno (ENAMETOOLONG);
return NULL;
}
}
}
p = pend;
}
else if (*p == '\n')
break; /* Be nice and stop at the first LF. */
else if (n < sizeof addr->sun_path - 1)
addr->sun_path[n++] = *p;
else
{
free (addr);
gpg_err_set_errno (ENAMETOOLONG);
return NULL;
}
}
return addr;
}
#endif /*!HAVE_W32_SYSTEM*/
/* Return a new socket. Note that under W32 we consider a socket the
same as an System Handle; all functions using such a handle know
about this dual use and act accordingly. */
assuan_fd_t
_assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto)
{
#ifdef HAVE_W32_SYSTEM
assuan_fd_t res;
if (domain == AF_UNIX || domain == AF_LOCAL)
domain = AF_INET;
res = SOCKET2HANDLE(_assuan_socket (ctx, domain, type, proto));
return res;
#else
return _assuan_socket (ctx, domain, type, proto);
#endif
}
int
_assuan_sock_set_flag (assuan_context_t ctx, assuan_fd_t sockfd,
const char *name, int value)
{
(void)ctx;
if (!strcmp (name, "cygwin"))
{
#ifdef HAVE_W32_SYSTEM
if (!value)
delete_cygwin_fd (sockfd);
else if (insert_cygwin_fd (sockfd))
return -1;
#else
/* Setting the Cygwin flag on non-Windows is ignored. */
#endif
}
else if (!strcmp (name, "tor-mode") || !strcmp (name, "socks"))
{
/* If SOCKFD is ASSUAN_INVALID_FD this controls global flag to
switch AF_INET and AF_INET6 into TOR mode by using a SOCKS5
proxy on localhost:9050. It may only be switched on and this
needs to be done before any new threads are started. Once
TOR mode has been enabled, TOR mode can be disabled for a
specific socket by using SOCKFD with a VALUE of 0. */
if (sockfd == ASSUAN_INVALID_FD)
{
if (tor_mode && !value)
{
gpg_err_set_errno (EPERM);
return -1; /* Clearing the global flag is not allowed. */
}
else if (value)
{
if (*name == 's')
tor_mode = SOCKS_PORT;
else
tor_mode = TOR_PORT;
}
}
else if (tor_mode && sockfd != ASSUAN_INVALID_FD)
{
/* Fixme: Disable/enable tormode for the given context. */
}
else
{
gpg_err_set_errno (EINVAL);
return -1;
}
}
else
{
gpg_err_set_errno (EINVAL);
return -1;
}
return 0;
}
int
_assuan_sock_get_flag (assuan_context_t ctx, assuan_fd_t sockfd,
const char *name, int *r_value)
{
(void)ctx;
if (!strcmp (name, "cygwin"))
{
#ifdef HAVE_W32_SYSTEM
*r_value = is_cygwin_fd (sockfd);
#else
*r_value = 0;
#endif
}
else if (!strcmp (name, "tor-mode"))
{
/* FIXME: Find tor-mode for the given socket. */
*r_value = tor_mode == TOR_PORT;
}
else if (!strcmp (name, "socks"))
{
*r_value = tor_mode == SOCKS_PORT;
}
else
{
gpg_err_set_errno (EINVAL);
return -1;
}
return 0;
}
/* Read NBYTES from SOCKFD into BUFFER. Return 0 on success. Handle
EAGAIN and EINTR. */
static int
do_readn (assuan_context_t ctx, assuan_fd_t sockfd,
void *buffer, size_t nbytes)
{
char *p = buffer;
ssize_t n;
while (nbytes)
{
n = _assuan_read (ctx, sockfd, p, nbytes);
if (n < 0 && errno == EINTR)
;
else if (n < 0 && errno == EAGAIN)
_assuan_usleep (ctx, 100000); /* 100ms */
else if (n < 0)
return -1;
else if (!n)
{
gpg_err_set_errno (EIO);
return -1;
}
else
{
p += n;
nbytes -= n;
}
}
return 0;
}
/* Write NBYTES from BUFFER to SOCKFD. Return 0 on success; on error
return -1 and set ERRNO. */
static int
do_writen (assuan_context_t ctx, assuan_fd_t sockfd,
const void *buffer, size_t nbytes)
{
int ret;
ret = _assuan_write (ctx, sockfd, buffer, nbytes);
if (ret >= 0 && ret != nbytes)
{
gpg_err_set_errno (EIO);
ret = -1;
}
else if (ret >= 0)
ret = 0;
return ret;
}
/* Connect using the SOCKS5 protocol. */
static int
socks5_connect (assuan_context_t ctx, assuan_fd_t sock,
unsigned short socksport,
const char *credentials,
const char *hostname, unsigned short hostport,
struct sockaddr *addr, socklen_t length)
{
int ret;
/* struct sockaddr_in6 proxyaddr_in6; */
struct sockaddr_in proxyaddr_in;
struct sockaddr *proxyaddr;
size_t proxyaddrlen;
struct sockaddr_in6 *addr_in6;
struct sockaddr_in *addr_in;
unsigned char buffer[22+512]; /* The extra 512 gives enough space
for username/password or the
hostname. */
size_t buflen, hostnamelen;
int method;
/* memset (&proxyaddr_in6, 0, sizeof proxyaddr_in6); */
memset (&proxyaddr_in, 0, sizeof proxyaddr_in);
/* Either HOSTNAME or ADDR may be given. */
if (hostname && addr)
{
gpg_err_set_errno (EINVAL);
return -1;
}
/* If a hostname is given it must fit into our buffer and it must be
less than 256 so that its length can be encoded in one byte. */
hostnamelen = hostname? strlen (hostname) : 0;
if (hostnamelen > 255)
{
gpg_err_set_errno (ENAMETOOLONG);
return -1;
}
/* Connect to local host. */
/* Fixme: First try to use IPv6 but note that
_assuan_sock_connect_byname created the socket with AF_INET. */
proxyaddr_in.sin_family = AF_INET;
proxyaddr_in.sin_port = htons (socksport);
proxyaddr_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
proxyaddr = (struct sockaddr *)&proxyaddr_in;
proxyaddrlen = sizeof proxyaddr_in;
ret = _assuan_connect (ctx, HANDLE2SOCKET (sock), proxyaddr, proxyaddrlen);
if (ret && socksport == TOR_PORT && errno == ECONNREFUSED)
{
/* Standard Tor port failed - try the Tor browser port. */
proxyaddr_in.sin_port = htons (TOR_PORT2);
ret = _assuan_connect (ctx, HANDLE2SOCKET (sock),
proxyaddr, proxyaddrlen);
}
/* If we get an EINPROGRESS here the caller is trying to do a
* non-blocking connect (e.g. for custom time out handling) which
* fails here. The easiest fix would be to allow the client to tell
* us the timeout value and we do the timeout handling later on in the
* Socks protocol. */
if (ret)
return ret;
buffer[0] = 5; /* RFC-1928 VER field. */
buffer[1] = 1; /* NMETHODS */
if (credentials)
method = 2; /* Method: username/password authentication. */
else
method = 0; /* Method: No authentication required. */
buffer[2] = method;
/* Negotiate method. */
ret = do_writen (ctx, sock, buffer, 3);
if (ret)
return ret;
ret = do_readn (ctx, sock, buffer, 2);
if (ret)
return ret;
if (buffer[0] != 5 || buffer[1] != method )
{
/* Socks server returned wrong version or does not support our
requested method. */
gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
return -1;
}
if (credentials)
{
const char *password;
int ulen, plen;
password = strchr (credentials, ':');
if (!password)
{
gpg_err_set_errno (EINVAL); /* No password given. */
return -1;
}
ulen = password - credentials;
password++;
plen = strlen (password);
if (!ulen || ulen > 255 || !plen || plen > 255)
{
gpg_err_set_errno (EINVAL);
return -1;
}
buffer[0] = 1; /* VER of the sub-negotiation. */
buffer[1] = ulen;
buflen = 2;
memcpy (buffer+buflen, credentials, ulen);
buflen += ulen;
buffer[buflen++] = plen;
memcpy (buffer+buflen, password, plen);
buflen += plen;
ret = do_writen (ctx, sock, buffer, buflen);
wipememory (buffer, buflen);
if (ret)
return ret;
ret = do_readn (ctx, sock, buffer, 2);
if (ret)
return ret;
if (buffer[0] != 1)
{
/* SOCKS server returned wrong version. */
gpg_err_set_errno (EPROTONOSUPPORT);
return -1;
}
if (buffer[1])
{
/* SOCKS server denied access. */
gpg_err_set_errno (EACCES);
return -1;
}
}
if (hostname && !*hostname && !hostport)
{
/* Empty hostname given. Stop right here to allow the caller to
do the actual proxy request. */
return 0;
}
/* Send request details (rfc-1928, 4). */
buffer[0] = 5; /* VER */
buffer[1] = 1; /* CMD = CONNECT */
buffer[2] = 0; /* RSV */
if (hostname)
{
buffer[3] = 3; /* ATYP = DOMAINNAME */
buflen = 4;
buffer[buflen++] = hostnamelen;
memcpy (buffer+buflen, hostname, hostnamelen);
buflen += hostnamelen;
buffer[buflen++] = (hostport >> 8); /* DST.PORT */
buffer[buflen++] = hostport;
}
else if (addr->sa_family == AF_INET6)
{
addr_in6 = (struct sockaddr_in6 *)addr;
buffer[3] = 4; /* ATYP = IPv6 */
memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
memcpy (buffer+20, &addr_in6->sin6_port, 2); /* DST.PORT */
buflen = 22;
}
else
{
addr_in = (struct sockaddr_in *)addr;
buffer[3] = 1; /* ATYP = IPv4 */
memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
memcpy (buffer+8, &addr_in->sin_port, 2); /* DST.PORT */
buflen = 10;
}
ret = do_writen (ctx, sock, buffer, buflen);
if (ret)
return ret;
ret = do_readn (ctx, sock, buffer, 10 /* Length for IPv4 */);
if (ret)
return ret;
if (buffer[0] != 5 || buffer[2] != 0 )
{
/* Socks server returned wrong version or the reserved field is
not zero. */
gpg_err_set_errno (EPROTONOSUPPORT);
return -1;
}
if (buffer[1])
{
switch (buffer[1])
{
case 0x01: /* General SOCKS server failure. */
gpg_err_set_errno (ENETDOWN);
break;
case 0x02: /* Connection not allowed by ruleset. */
gpg_err_set_errno (EACCES);
break;
case 0x03: /* Network unreachable */
gpg_err_set_errno (ENETUNREACH);
break;
case 0x04: /* Host unreachable */
gpg_err_set_errno (EHOSTUNREACH);
break;
case 0x05: /* Connection refused */
gpg_err_set_errno (ECONNREFUSED);
break;
case 0x06: /* TTL expired */
gpg_err_set_errno (ETIMEDOUT);
break;
case 0x08: /* Address type not supported */
gpg_err_set_errno (EPROTONOSUPPORT);
break;
case 0x07: /* Command not supported */
default:
gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
}
return -1;
}
if (buffer[3] == 4)
{
/* ATYP indicates a v6 address. We need to read the remaining
12 bytes. */
ret = do_readn (ctx, sock, buffer+10, 12);
if (ret)
return ret;
}
/* FIXME: We have not way to store the actual address used by the
server. */
return 0;
}
/* Return true if SOCKS shall be used. This is the case if tor_mode
is enabled and the desired address is not the loopback
address. */
static int
use_socks (struct sockaddr *addr)
{
if (!tor_mode)
return 0;
else if (addr->sa_family == AF_INET6)
{
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
const unsigned char *s;
int i;
s = (unsigned char *)&addr_in6->sin6_addr.s6_addr;
if (s[15] != 1)
return 1; /* Last octet is not 1 - not the loopback address. */
for (i=0; i < 15; i++, s++)
if (*s)
return 1; /* Non-zero octet found - not the loopback address. */
return 0; /* This is the loopback address. */
}
else if (addr->sa_family == AF_INET)
{
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
if (*(unsigned char*)&addr_in->sin_addr.s_addr == 127)
return 0; /* Loopback (127.0.0.0/8) */
return 1;
}
else
return 0;
}
int
_assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen)
{
#ifdef HAVE_W32_SYSTEM
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_in myaddr;
struct sockaddr_un *unaddr;
unsigned short port;
char nonce[16];
int cygwin;
int ret;
unaddr = (struct sockaddr_un *)addr;
if (read_port_and_nonce (unaddr->sun_path, &port, nonce, &cygwin))
return -1;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons (port);
myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
/* Set return values. */
unaddr->sun_family = myaddr.sin_family;
unaddr->sun_port = myaddr.sin_port;
unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
ret = _assuan_connect (ctx, HANDLE2SOCKET(sockfd),
(struct sockaddr *)&myaddr, sizeof myaddr);
if (!ret)
{
/* Send the nonce. */
ret = do_writen (ctx, sockfd, nonce, 16);
if (!ret && cygwin)
{
char buffer[16];
/* The client sends the nonce back - not useful. We do
a dummy read. */
ret = do_readn (ctx, sockfd, buffer, 16);
if (!ret)
{
/* Send our credentials. */
int n = getpid ();
memcpy (buffer, &n, 4);
memset (buffer+4, 0, 4); /* uid = gid = 0 */
ret = do_writen (ctx, sockfd, buffer, 8);
if (!ret)
{
/* Receive credentials. We don't need them. */
ret = do_readn (ctx, sockfd, buffer, 8);
}
}
}
}
return ret;
}
else if (use_socks (addr))
{
return socks5_connect (ctx, sockfd, tor_mode,
NULL, NULL, 0, addr, addrlen);
}
else
{
return _assuan_connect (ctx, HANDLE2SOCKET (sockfd), addr, addrlen);
}
#else
# if HAVE_STAT
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_un *unaddr;
struct stat statbuf;
int redirect, res;
unaddr = (struct sockaddr_un *)addr;
if (!stat (unaddr->sun_path, &statbuf)
&& !S_ISSOCK (statbuf.st_mode)
&& S_ISREG (statbuf.st_mode))
{
/* The given socket file is not a socket but a regular file.
We use the content of that file to redirect to another
socket file. This can be used to use sockets on file
systems which do not support sockets or if for example a
home directory is shared by several machines. */
unaddr = eval_redirection (unaddr->sun_path, &redirect);
if (unaddr)
{
res = _assuan_connect (ctx, sockfd, (struct sockaddr *)unaddr,
SUN_LEN (unaddr));
free (unaddr);
return res;
}
if (redirect)
return -1;
/* Continue using the standard connect. */
}
}
# endif /*HAVE_STAT*/
if (use_socks (addr))
{
return socks5_connect (ctx, sockfd, tor_mode,
NULL, NULL, 0, addr, addrlen);
}
else
{
return _assuan_connect (ctx, sockfd, addr, addrlen);
}
#endif
}
/* Connect to HOST specified as host name on PORT. The current
implementation requires that either the flags ASSUAN_SOCK_SOCKS or
ASSUAN_SOCK_TOR are given in FLAGS. On success a new socket is
returned; on error ASSUAN_INVALID_FD is returned and ERRNO set. If
CREDENTIALS is not NULL, it is a string used for password based
authentication. Username and password are separated by a colon.
RESERVED must be 0. By passing HOST and PORT as 0 the function can
be used to check for proxy availability: If the proxy is available
a socket will be returned which the caller should then close. */
assuan_fd_t
_assuan_sock_connect_byname (assuan_context_t ctx, const char *host,
unsigned short port, int reserved,
const char *credentials, unsigned int flags)
{
assuan_fd_t fd;
unsigned short socksport;
if ((flags & ASSUAN_SOCK_TOR))
socksport = TOR_PORT;
else if ((flags & ASSUAN_SOCK_SOCKS))
socksport = SOCKS_PORT;
else
{
gpg_err_set_errno (ENOTSUP);
return ASSUAN_INVALID_FD;
}
if (host && !*host)
{
/* Error out early on an empty host name. See below. */
gpg_err_set_errno (EINVAL);
return ASSUAN_INVALID_FD;
}
fd = _assuan_sock_new (ctx, AF_INET, SOCK_STREAM, 0);
if (fd == ASSUAN_INVALID_FD)
return fd;
/* For HOST being NULL we pass an empty string which indicates to
socks5_connect to stop midway during the proxy negotiation. Note
that we can't pass NULL directly as this indicates IP address
mode to the called function. */
if (socks5_connect (ctx, fd, socksport,
credentials, host? host:"", port, NULL, 0))
{
int save_errno = errno;
assuan_sock_close (fd);
gpg_err_set_errno (save_errno);
return ASSUAN_INVALID_FD;
}
return fd;
}
int
_assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen)
{
#ifdef HAVE_W32_SYSTEM
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_in myaddr;
struct sockaddr_un *unaddr;
HANDLE filehd;
int len = sizeof myaddr;
int rc;
union {
char data[16];
int aint[4];
} nonce;
char tmpbuf[50+16];
DWORD nwritten;
if (get_nonce (nonce.data, 16))
return -1;
unaddr = (struct sockaddr_un *)addr;
myaddr.sin_port = 0;
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
filehd = MyCreateFile (unaddr->sun_path,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (filehd == INVALID_HANDLE_VALUE)
{
if (GetLastError () == ERROR_FILE_EXISTS)
gpg_err_set_errno (EADDRINUSE);
return -1;
}
rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len);
if (!rc)
rc = getsockname (HANDLE2SOCKET (sockfd),
(struct sockaddr *)&myaddr, &len);
if (rc)
{
int save_e = errno;
CloseHandle (filehd);
MyDeleteFile (unaddr->sun_path);
gpg_err_set_errno (save_e);
return rc;
}
if (is_cygwin_fd (sockfd))
{
snprintf (tmpbuf, sizeof tmpbuf,
"!%d s %08x-%08x-%08x-%08x",
ntohs (myaddr.sin_port),
nonce.aint[0], nonce.aint[1], nonce.aint[2], nonce.aint[3]);
len = strlen (tmpbuf) + 1;
}
else
{
snprintf (tmpbuf, sizeof tmpbuf-16, "%d\n", ntohs (myaddr.sin_port));
len = strlen (tmpbuf);
memcpy (tmpbuf+len, nonce.data,16);
len += 16;
}
if (!WriteFile (filehd, tmpbuf, len, &nwritten, NULL))
{
CloseHandle (filehd);
MyDeleteFile (unaddr->sun_path);
gpg_err_set_errno (EIO);
return -1;
}
CloseHandle (filehd);
return 0;
}
else
{
int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen);
if (res < 0)
gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
}
#else
return bind (sockfd, addr, addrlen);
#endif
}
/* Setup the ADDR structure for a Unix domain socket with the socket
name FNAME. If this is a redirected socket and R_REDIRECTED is not
NULL, it will be setup for the real socket. Returns 0 on success
and stores 1 at R_REDIRECTED if it is a redirected socket. On
error -1 is returned and ERRNO will be set. */
int
_assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
int *r_redirected)
{
struct sockaddr_un *unaddr = (struct sockaddr_un *)addr;
#if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
struct stat statbuf;
#endif
if (r_redirected)
*r_redirected = 0;
#if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
if (r_redirected
&& !stat (fname, &statbuf)
&& !S_ISSOCK (statbuf.st_mode)
&& S_ISREG (statbuf.st_mode))
{
/* The given socket file is not a socket but a regular file. We
use the content of that file to redirect to another socket
file. This can be used to use sockets on file systems which
do not support sockets or if for example a home directory is
shared by several machines. */
struct sockaddr_un *unaddr_new;
int redirect;
unaddr_new = eval_redirection (fname, &redirect);
if (unaddr_new)
{
memcpy (unaddr, unaddr_new, sizeof *unaddr);
free (unaddr_new);
*r_redirected = 1;
return 0;
}
if (redirect)
{
*r_redirected = 1;
return -1; /* Error. */
}
/* Fallback to standard setup. */
}
#endif /*!HAVE_W32_SYSTEM && HAVE_STAT*/
if (strlen (fname)+1 >= sizeof unaddr->sun_path)
{
gpg_err_set_errno (ENAMETOOLONG);
return -1;
}
memset (unaddr, 0, sizeof *unaddr);
unaddr->sun_family = AF_LOCAL;
strncpy (unaddr->sun_path, fname, sizeof unaddr->sun_path - 1);
unaddr->sun_path[sizeof unaddr->sun_path - 1] = 0;
return 0;
}
int
_assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
int addrlen, assuan_sock_nonce_t *nonce)
{
#ifdef HAVE_W32_SYSTEM
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_un *unaddr;
unsigned short port;
int dummy;
if (sizeof nonce->nonce != 16)
{
gpg_err_set_errno (EINVAL);
return -1;
}
nonce->length = 16;
unaddr = (struct sockaddr_un *)addr;
if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce, &dummy))
return -1;
}
else
{
nonce->length = 42; /* Arbitrary value to detect unitialized nonce. */
nonce->nonce[0] = 42;
}
#else
(void)addr;
(void)addrlen;
nonce->length = 0;
#endif
return 0;
}
int
_assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
assuan_sock_nonce_t *nonce)
{
#ifdef HAVE_W32_SYSTEM
char buffer[16];
int n;
if (sizeof nonce->nonce != 16)
{
gpg_err_set_errno (EINVAL);
return -1;
}
if (nonce->length == 42 && nonce->nonce[0] == 42)
return 0; /* Not a Unix domain socket. */
if (nonce->length != 16)
{
gpg_err_set_errno (EINVAL);
return -1;
}
if (do_readn (ctx, fd, buffer, 16))
return -1;
if (memcmp (buffer, nonce->nonce, 16))
{
gpg_err_set_errno (EACCES);
return -1;
}
if (is_cygwin_fd (fd))
{
/* Send the nonce back to the client. */
if (do_writen (ctx, fd, buffer, 16))
return -1;
/* Read the credentials. Cygwin uses the
struct ucred { pid_t pid; uid_t uid; gid_t gid; };
with pid_t being an int (4 bytes) and uid_t and gid_t being
shorts (2 bytes). Thus we need to read 8 bytes. However we
we ignore the values because they are not kernel controlled. */
if (do_readn (ctx, fd, buffer, 8))
return -1;
/* Send our credentials: We use the uid and gid we received but
our own pid. */
n = getpid ();
memcpy (buffer, &n, 4);
if (do_writen (ctx, fd, buffer, 8))
return -1;
}
#else
(void)fd;
(void)nonce;
#endif
return 0;
}
/* Public API. */
gpg_error_t
assuan_sock_init ()
{
gpg_error_t err;
#ifdef HAVE_W32_SYSTEM
WSADATA wsadat;
#endif
if (sock_ctx != NULL)
return 0;
#ifdef HAVE_W32_SYSTEM
InitializeCriticalSection (&cygwin_fdtable_cs);
#endif
err = assuan_new (&sock_ctx);
#ifdef HAVE_W32_SYSTEM
if (! err)
WSAStartup (0x202, &wsadat);
#endif
return err;
}
void
assuan_sock_deinit ()
{
if (sock_ctx == NULL)
return;
#ifdef HAVE_W32_SYSTEM
WSACleanup ();
#endif
assuan_release (sock_ctx);
sock_ctx = NULL;
#ifdef HAVE_W32_SYSTEM
DeleteCriticalSection (&cygwin_fdtable_cs);
#endif
}
int
assuan_sock_close (assuan_fd_t fd)
{
#ifdef HAVE_W32_SYSTEM
if (fd != ASSUAN_INVALID_FD)
delete_cygwin_fd (fd);
#endif
return _assuan_close (sock_ctx, fd);
}
assuan_fd_t
assuan_sock_new (int domain, int type, int proto)
{
return _assuan_sock_new (sock_ctx, domain, type, proto);
}
int
assuan_sock_set_flag (assuan_fd_t sockfd, const char *name, int value)
{
return _assuan_sock_set_flag (sock_ctx, sockfd, name, value);
}
int
assuan_sock_get_flag (assuan_fd_t sockfd, const char *name, int *r_value)
{
return _assuan_sock_get_flag (sock_ctx, sockfd, name, r_value);
}
int
assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
{
return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen);
}
assuan_fd_t
assuan_sock_connect_byname (const char *host, unsigned short port,
int reserved, const char *credentials,
unsigned int flags)
{
return _assuan_sock_connect_byname (sock_ctx,
host, port, reserved, credentials, flags);
}
int
assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
{
return _assuan_sock_bind (sock_ctx, sockfd, addr, addrlen);
}
int
assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
int *r_redirected)
{
return _assuan_sock_set_sockaddr_un (fname, addr, r_redirected);
}
int
assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
assuan_sock_nonce_t *nonce)
{
return _assuan_sock_get_nonce (sock_ctx, addr, addrlen, nonce);
}
int
assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
{
return _assuan_sock_check_nonce (sock_ctx, fd, nonce);
}
diff --git a/src/assuan-uds.c b/src/assuan-uds.c
index 59f3a6b..8712b02 100644
--- a/src/assuan-uds.c
+++ b/src/assuan-uds.c
@@ -1,300 +1,301 @@
/* assuan-uds.c - Assuan unix domain socket utilities
- Copyright (C) 2006, 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 .
+ * Copyright (C) 2006, 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifndef HAVE_W32_SYSTEM
# include
# include
#else
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
#endif
#if HAVE_SYS_UIO_H
#include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_FCNTL_H
#include
#endif
#include
#include
#include "assuan-defs.h"
#include "debug.h"
#ifdef USE_DESCRIPTOR_PASSING
/* Provide replacement for missing CMSG maccros. We assume that
size_t matches the alignment requirement. NOTE: This is not true
on Mac OS X, so be extra careful to define _DARWIN_C_SOURCE to get
those definitions instead of using these. */
#define MY_ALIGN(n) ((((n))+ sizeof(size_t)-1) & (size_t)~(sizeof(size_t)-1))
#ifndef CMSG_SPACE
#define CMSG_SPACE(n) (MY_ALIGN(sizeof(struct cmsghdr)) + MY_ALIGN((n)))
#endif
#ifndef CMSG_LEN
#define CMSG_LEN(n) (MY_ALIGN(sizeof(struct cmsghdr)) + (n))
#endif
#ifndef CMSG_FIRSTHDR
#define CMSG_FIRSTHDR(mhdr) \
((size_t)(mhdr)->msg_controllen >= sizeof (struct cmsghdr) \
? (struct cmsghdr*) (mhdr)->msg_control : (struct cmsghdr*)NULL)
#endif
#ifndef CMSG_DATA
#define CMSG_DATA(cmsg) ((unsigned char*)((struct cmsghdr*)(cmsg)+1))
#endif
#endif /*USE_DESCRIPTOR_PASSING*/
/* Read from a unix domain socket using sendmsg. */
static ssize_t
uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
{
#ifndef HAVE_W32_SYSTEM
int len = 0;
/* This loop should be OK. As FDs are followed by data, the
readable status of the socket does not change and no new
select/event-loop round is necessary. */
while (!len) /* No data is buffered. */
{
struct msghdr msg;
struct iovec iovec;
#ifdef USE_DESCRIPTOR_PASSING
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof (int))];
} control_u;
struct cmsghdr *cmptr;
#endif /*USE_DESCRIPTOR_PASSING*/
memset (&msg, 0, sizeof (msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iovec;
msg.msg_iovlen = 1;
iovec.iov_base = buf;
iovec.iov_len = buflen;
#ifdef USE_DESCRIPTOR_PASSING
msg.msg_control = control_u.control;
msg.msg_controllen = sizeof (control_u.control);
#endif
len = _assuan_recvmsg (ctx, ctx->inbound.fd, &msg, 0);
if (len < 0)
return -1;
if (len == 0)
return 0;
#ifdef USE_DESCRIPTOR_PASSING
cmptr = CMSG_FIRSTHDR (&msg);
if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int)))
{
if (cmptr->cmsg_level != SOL_SOCKET
|| cmptr->cmsg_type != SCM_RIGHTS)
TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
"unexpected ancillary data received");
else
{
int fd;
memcpy (&fd, CMSG_DATA (cmptr), sizeof (fd));
if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds))
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
"too many descriptors pending - "
"closing received descriptor %d", fd);
_assuan_close (ctx, fd);
}
else
ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd;
}
}
#endif /*USE_DESCRIPTOR_PASSING*/
}
return len;
#else /*HAVE_W32_SYSTEM*/
int res = recvfrom (HANDLE2SOCKET(ctx->inbound.fd), buf, buflen, 0, NULL, NULL);
if (res < 0)
gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
#endif /*HAVE_W32_SYSTEM*/
}
/* Write to the domain server. */
static ssize_t
uds_writer (assuan_context_t ctx, const void *buf, size_t buflen)
{
#ifndef HAVE_W32_SYSTEM
struct msghdr msg;
struct iovec iovec;
ssize_t len;
memset (&msg, 0, sizeof (msg));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iovlen = 1;
msg.msg_iov = &iovec;
iovec.iov_base = (void*)buf;
iovec.iov_len = buflen;
len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0);
return len;
#else /*HAVE_W32_SYSTEM*/
int res = sendto (HANDLE2SOCKET(ctx->outbound.fd), buf, buflen, 0,
(struct sockaddr *)&ctx->serveraddr,
sizeof (struct sockaddr_in));
if (res < 0)
gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
#endif /*HAVE_W32_SYSTEM*/
}
static gpg_error_t
uds_sendfd (assuan_context_t ctx, assuan_fd_t fd)
{
#ifdef USE_DESCRIPTOR_PASSING
struct msghdr msg;
struct iovec iovec;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof (int))];
} control_u;
struct cmsghdr *cmptr;
int len;
char buffer[80];
/* We need to send some real data so that a read won't return 0
which will be taken as an EOF. It also helps with debugging. */
snprintf (buffer, sizeof(buffer)-1, "# descriptor %d is in flight\n", fd);
buffer[sizeof(buffer)-1] = 0;
memset (&msg, 0, sizeof (msg));
memset (&control_u, 0, sizeof (control_u));
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iovlen = 1;
msg.msg_iov = &iovec;
iovec.iov_base = buffer;
iovec.iov_len = strlen (buffer);
msg.msg_control = control_u.control;
msg.msg_controllen = sizeof (control_u.control);
cmptr = CMSG_FIRSTHDR (&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
memcpy (CMSG_DATA (cmptr), &fd, sizeof (fd));
len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0);
if (len < 0)
{
int saved_errno = errno;
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_sendfd", ctx,
"uds_sendfd: %s", strerror (errno));
errno = saved_errno;
return _assuan_error (ctx, gpg_err_code_from_syserror ());
}
else
return 0;
#else
return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
#endif
}
static gpg_error_t
uds_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
{
#ifdef USE_DESCRIPTOR_PASSING
int i;
if (!ctx->uds.pendingfdscount)
{
TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_receivefd", ctx,
"no pending file descriptors");
return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
}
assert (ctx->uds.pendingfdscount <= DIM(ctx->uds.pendingfds));
*fd = ctx->uds.pendingfds[0];
for (i=1; i < ctx->uds.pendingfdscount; i++)
ctx->uds.pendingfds[i-1] = ctx->uds.pendingfds[i];
ctx->uds.pendingfdscount--;
return 0;
#else
return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
#endif
}
/* Close all pending fds. */
void
_assuan_uds_close_fds (assuan_context_t ctx)
{
int i;
for (i = 0; i < ctx->uds.pendingfdscount; i++)
_assuan_close (ctx, ctx->uds.pendingfds[i]);
ctx->uds.pendingfdscount = 0;
}
/* Deinitialize the unix domain socket I/O functions. */
void
_assuan_uds_deinit (assuan_context_t ctx)
{
_assuan_uds_close_fds (ctx);
}
/* Helper function to initialize a context for domain I/O. */
void
_assuan_init_uds_io (assuan_context_t ctx)
{
ctx->engine.readfnc = uds_reader;
ctx->engine.writefnc = uds_writer;
ctx->engine.sendfd = uds_sendfd;
ctx->engine.receivefd = uds_receivefd;
ctx->uds.pendingfdscount = 0;
}
diff --git a/src/assuan.c b/src/assuan.c
index d4c4b56..e59df65 100644
--- a/src/assuan.c
+++ b/src/assuan.c
@@ -1,284 +1,285 @@
/* 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "assuan-defs.h"
#include "debug.h"
#define digitp(a) ((a) >= '0' && (a) <= '9')
/* Global default state. */
/* 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;
}
void
assuan_set_system_hooks (assuan_system_hooks_t system_hooks)
{
_assuan_system_hooks_copy (&_assuan_system_hooks, system_hooks);
}
/* 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));
ctx->system = _assuan_system_hooks;
/* 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;
*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)
{
return compare_versions (PACKAGE_VERSION, req_version);
}
diff --git a/src/assuan.h.in b/src/assuan.h.in
index da1af25..acd4f45 100644
--- a/src/assuan.h.in
+++ b/src/assuan.h.in
@@ -1,595 +1,596 @@
/* assuan.h - Definitions for the Assuan IPC library -*- c -*-
- Copyright (C) 2001-2013 Free Software Foundation, Inc.
- Copyright (C) 2001-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 .
-
- @configure_input@
+ * Copyright (C) 2001-2013 Free Software Foundation, Inc.
+ * Copyright (C) 2001-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 .
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * @configure_input@
*/
#ifndef ASSUAN_H
#define ASSUAN_H
#include
@include:sys/types.h@
@include:unistd.h@
#include
#ifndef _ASSUAN_NO_SOCKET_WRAPPER
@include:includes@
#endif /*!_ASSUAN_NO_SOCKET_WRAPPER*/
@include:types@
#include
/* Compile time configuration:
#define _ASSUAN_NO_SOCKET_WRAPPER
Do not include the definitions for the socket wrapper feature. */
#ifdef __cplusplus
extern "C"
{
#if 0
}
#endif
#endif
/* The version of this header should match the one of the library. Do
not use this symbol in your application; use assuan_check_version
instead. */
#define ASSUAN_VERSION @version@
/* The version number of this header. It may be used to handle minor
API incompatibilities. */
#define ASSUAN_VERSION_NUMBER @version-number@
/* Check for compiler features. */
#if __GNUC__
#define _ASSUAN_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#if _ASSUAN_GCC_VERSION > 30100
#define _ASSUAN_DEPRECATED __attribute__ ((__deprecated__))
#endif
#endif
#ifndef _ASSUAN_DEPRECATED
#define _ASSUAN_DEPRECATED
#endif
#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
struct assuan_context_s;
typedef struct assuan_context_s *assuan_context_t;
@include:fd-t@
assuan_fd_t assuan_fdopen (int fd);
@include:sock-nonce@
/* Global interface. */
struct assuan_malloc_hooks
{
void *(*malloc) (size_t cnt);
void *(*realloc) (void *ptr, size_t cnt);
void (*free) (void *ptr);
};
typedef struct assuan_malloc_hooks *assuan_malloc_hooks_t;
/* Categories for log messages. */
#define ASSUAN_LOG_INIT 1
#define ASSUAN_LOG_CTX 2
#define ASSUAN_LOG_ENGINE 3
#define ASSUAN_LOG_DATA 4
#define ASSUAN_LOG_SYSIO 5
#define ASSUAN_LOG_CONTROL 8
/* If MSG is NULL, return true/false depending on if this category is
logged. This is used to probe before expensive log message
generation (buffer dumps). */
typedef int (*assuan_log_cb_t) (assuan_context_t ctx, void *hook,
unsigned int cat, const char *msg);
/* Return or check the version number. */
const char *assuan_check_version (const char *req_version);
/* Set the default gpg error source. */
void assuan_set_gpg_err_source (gpg_err_source_t errsource);
/* Get the default gpg error source. */
gpg_err_source_t assuan_get_gpg_err_source (void);
/* Set the default malloc hooks. */
void assuan_set_malloc_hooks (assuan_malloc_hooks_t malloc_hooks);
/* Get the default malloc hooks. */
assuan_malloc_hooks_t assuan_get_malloc_hooks (void);
/* Set the default log callback handler. */
void assuan_set_log_cb (assuan_log_cb_t log_cb, void *log_cb_data);
/* Get the default log callback handler. */
void assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data);
/* 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 *ctx, gpg_err_source_t errsource,
assuan_malloc_hooks_t malloc_hooks,
assuan_log_cb_t log_cb, void *log_cb_data);
/* Create a new context with default arguments. */
gpg_error_t assuan_new (assuan_context_t *ctx);
/* Release all resources associated with the given context. */
void assuan_release (assuan_context_t ctx);
/* 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);
/* Set user-data in a context. */
void assuan_set_pointer (assuan_context_t ctx, void *pointer);
/* Get user-data in a context. */
void *assuan_get_pointer (assuan_context_t ctx);
/* Definitions of flags for assuan_set_flag(). */
typedef unsigned int assuan_flag_t;
/* When using a pipe server, by default Assuan will wait for the
forked process to die in assuan_release. In certain cases this
is not desirable. By setting this flag, the waitpid will be
skipped and the caller is responsible to cleanup a forked
process. */
#define ASSUAN_NO_WAITPID 1
/* This flag indicates whether Assuan logging is in confidential mode.
You can use assuan_{begin,end}_condidential to change the mode. */
#define ASSUAN_CONFIDENTIAL 2
/* This flag suppresses fix up of signal handlers for pipes. */
#define ASSUAN_NO_FIXSIGNALS 3
/* This flag changes assuan_transact to return comment lines via the
status callback. The default is to skip comment lines. */
#define ASSUAN_CONVEY_COMMENTS 4
/* This flag disables logging for one context. */
#define ASSUAN_NO_LOGGING 5
/* This flag forces a connection close. */
#define ASSUAN_FORCE_CLOSE 6
/* 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);
/* Return the VALUE of FLAG in context CTX. */
int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag);
/* Same as assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1). */
void assuan_begin_confidential (assuan_context_t ctx);
/* Same as assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0). */
void assuan_end_confidential (assuan_context_t ctx);
/* Direction values for assuan_set_io_monitor. */
#define ASSUAN_IO_FROM_PEER 0
#define ASSUAN_IO_TO_PEER 1
/* Return flags of I/O monitor. */
#define ASSUAN_IO_MONITOR_NOLOG 1
#define ASSUAN_IO_MONITOR_IGNORE 2
/* The IO monitor gets to see all I/O on the context, and can return
ASSUAN_IO_MONITOR_* bits to control actions on it. */
typedef unsigned int (*assuan_io_monitor_t) (assuan_context_t ctx, void *hook,
int inout, const char *line,
size_t linelen);
/* Set the IO monitor function. */
void assuan_set_io_monitor (assuan_context_t ctx,
assuan_io_monitor_t io_monitor, void *hook_data);
#define ASSUAN_SYSTEM_HOOKS_VERSION 2
#define ASSUAN_SPAWN_DETACHED 128
struct assuan_system_hooks
{
/* Always set to ASSUAN_SYTEM_HOOKS_VERSION. */
int version;
/* Sleep for the given number of microseconds. */
void (*usleep) (assuan_context_t ctx, unsigned int usec);
/* Create a pipe with an inheritable end. */
int (*pipe) (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. */
int (*close) (assuan_context_t ctx, assuan_fd_t fd);
ssize_t (*read) (assuan_context_t ctx, assuan_fd_t fd, void *buffer,
size_t size);
ssize_t (*write) (assuan_context_t ctx, assuan_fd_t fd,
const void *buffer, size_t size);
int (*recvmsg) (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags);
int (*sendmsg) (assuan_context_t ctx, assuan_fd_t fd,
const assuan_msghdr_t msg, int flags);
/* If NAME is NULL, don't exec, just fork. FD_CHILD_LIST is
modified to reflect the value of the FD in the peer process (on
Windows). */
int (*spawn) (assuan_context_t ctx, 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);
/* If action is 0, like waitpid. If action is 1, just release the PID? */
pid_t (*waitpid) (assuan_context_t ctx, pid_t pid,
int action, int *status, int options);
int (*socketpair) (assuan_context_t ctx, int _namespace, int style,
int protocol, assuan_fd_t filedes[2]);
int (*socket) (assuan_context_t ctx, int _namespace, int style, int protocol);
int (*connect) (assuan_context_t ctx, int sock, struct sockaddr *addr, socklen_t length);
};
typedef struct assuan_system_hooks *assuan_system_hooks_t;
/* Configuration of the default log handler. */
/* Set the prefix to be used at the start of a line emitted by assuan
on the log stream. The default is the empty string. Note, that
this function is not thread-safe and should in general be used
right at startup. */
void assuan_set_assuan_log_prefix (const char *text);
/* Return a prefix to be used at the start of a line emitted by assuan
on the log stream. The default implementation returns the empty
string, i.e. "" */
const char *assuan_get_assuan_log_prefix (void);
/* Global default log stream. */
void assuan_set_assuan_log_stream (FILE *fp);
/* Set the per context log stream for the default log handler. */
void assuan_set_log_stream (assuan_context_t ctx, FILE *fp);
typedef gpg_error_t (*assuan_handler_t) (assuan_context_t, char *);
/*-- assuan-handler.c --*/
gpg_error_t assuan_register_command (assuan_context_t ctx,
const char *cmd_string,
assuan_handler_t handler,
const char *help_string);
gpg_error_t assuan_register_pre_cmd_notify (assuan_context_t ctx,
gpg_error_t (*fnc)(assuan_context_t, const char *cmd));
gpg_error_t assuan_register_post_cmd_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t,
gpg_error_t));
gpg_error_t assuan_register_bye_notify (assuan_context_t ctx,
assuan_handler_t handler);
gpg_error_t assuan_register_reset_notify (assuan_context_t ctx,
assuan_handler_t handler);
gpg_error_t assuan_register_cancel_notify (assuan_context_t ctx,
assuan_handler_t handler);
gpg_error_t assuan_register_input_notify (assuan_context_t ctx,
assuan_handler_t handler);
gpg_error_t assuan_register_output_notify (assuan_context_t ctx,
assuan_handler_t handler);
gpg_error_t assuan_register_option_handler (assuan_context_t ctx,
gpg_error_t (*fnc)(assuan_context_t,
const char*,
const char*));
gpg_error_t assuan_process (assuan_context_t ctx);
gpg_error_t assuan_process_next (assuan_context_t ctx, int *done);
gpg_error_t assuan_process_done (assuan_context_t ctx, gpg_error_t rc);
int assuan_get_active_fds (assuan_context_t ctx, int what,
assuan_fd_t *fdarray, int fdarraysize);
const char *assuan_get_command_name (assuan_context_t ctx);
FILE *assuan_get_data_fp (assuan_context_t ctx);
gpg_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line);
gpg_error_t assuan_write_status (assuan_context_t ctx,
const char *keyword, const char *text);
/* Negotiate a file descriptor. If LINE contains "FD=N", returns N
assuming a local file descriptor. If LINE contains "FD" reads a
file descriptor via CTX and stores it in *RDF (the CTX must be
capable of passing file descriptors). Under W32 the returned FD is
a libc-type one. */
gpg_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
assuan_fd_t *rfd);
/*-- assuan-listen.c --*/
gpg_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
gpg_error_t assuan_accept (assuan_context_t ctx);
assuan_fd_t assuan_get_input_fd (assuan_context_t ctx);
assuan_fd_t assuan_get_output_fd (assuan_context_t ctx);
gpg_error_t assuan_close_input_fd (assuan_context_t ctx);
gpg_error_t assuan_close_output_fd (assuan_context_t ctx);
/*-- assuan-pipe-server.c --*/
gpg_error_t assuan_init_pipe_server (assuan_context_t ctx,
assuan_fd_t filedes[2]);
/*-- assuan-socket-server.c --*/
#define ASSUAN_SOCKET_SERVER_FDPASSING 1
#define ASSUAN_SOCKET_SERVER_ACCEPTED 2
gpg_error_t assuan_init_socket_server (assuan_context_t ctx,
assuan_fd_t listen_fd,
unsigned int flags);
void assuan_set_sock_nonce (assuan_context_t ctx, assuan_sock_nonce_t *nonce);
/*-- assuan-pipe-connect.c --*/
#define ASSUAN_PIPE_CONNECT_FDPASSING 1
#define ASSUAN_PIPE_CONNECT_DETACHED 128
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 *, int),
void *atforkvalue,
unsigned int flags);
/*-- assuan-socket-connect.c --*/
#define ASSUAN_SOCKET_CONNECT_FDPASSING 1
gpg_error_t assuan_socket_connect (assuan_context_t ctx, const char *name,
pid_t server_pid, unsigned int flags);
/*-- assuan-socket-connect.c --*/
gpg_error_t assuan_socket_connect_fd (assuan_context_t ctx, int fd,
unsigned int flags);
/*-- context.c --*/
pid_t assuan_get_pid (assuan_context_t ctx);
struct _assuan_peercred
{
#ifdef _WIN32
/* Empty struct not allowed on some compilers. */
unsigned int _dummy;
#else
pid_t pid;
uid_t uid;
gid_t gid;
#endif
};
typedef struct _assuan_peercred *assuan_peercred_t;
gpg_error_t assuan_get_peercred (assuan_context_t ctx,
assuan_peercred_t *peercred);
/* Client interface. */
#define ASSUAN_RESPONSE_ERROR 0
#define ASSUAN_RESPONSE_OK 1
#define ASSUAN_RESPONSE_DATA 2
#define ASSUAN_RESPONSE_INQUIRE 3
#define ASSUAN_RESPONSE_STATUS 4
#define ASSUAN_RESPONSE_END 5
#define ASSUAN_RESPONSE_COMMENT 6
typedef int assuan_response_t;
/* This already de-escapes data lines. */
gpg_error_t assuan_client_read_response (assuan_context_t ctx,
char **line, int *linelen);
gpg_error_t assuan_client_parse_response (assuan_context_t ctx,
char *line, int linelen,
assuan_response_t *response,
int *off);
/*-- assuan-client.c --*/
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);
/*-- assuan-inquire.c --*/
gpg_error_t assuan_inquire (assuan_context_t ctx, const char *keyword,
unsigned char **r_buffer, size_t *r_length,
size_t maxlen);
gpg_error_t assuan_inquire_ext (assuan_context_t ctx, const char *keyword,
size_t maxlen,
gpg_error_t (*cb) (void *cb_data,
gpg_error_t rc,
unsigned char *buf,
size_t buf_len),
void *cb_data);
/*-- assuan-buffer.c --*/
gpg_error_t assuan_read_line (assuan_context_t ctx,
char **line, size_t *linelen);
int assuan_pending_line (assuan_context_t ctx);
gpg_error_t assuan_write_line (assuan_context_t ctx, const char *line);
gpg_error_t assuan_send_data (assuan_context_t ctx,
const void *buffer, size_t length);
/* The file descriptor must be pending before assuan_receivefd is
called. This means that assuan_sendfd should be called *before* the
trigger is sent (normally via assuan_write_line ("INPUT FD")). */
gpg_error_t assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd);
gpg_error_t assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd);
/*-- assuan-util.c --*/
gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err,
const char *text);
/*-- assuan-socket.c --*/
/* This flag is used with assuan_sock_connect_byname to
connect via SOCKS. */
#define ASSUAN_SOCK_SOCKS 1
/* This flag is used with assuan_sock_connect_byname to force a
connection via Tor even if the socket subsystem has not been
swicthed into Tor mode. This flags overrides ASSUAN_SOCK_SOCKS. */
#define ASSUAN_SOCK_TOR 2
/* These are socket wrapper functions to support an emulation of Unix
domain sockets on Windows W32. */
gpg_error_t assuan_sock_init (void);
void assuan_sock_deinit (void);
int assuan_sock_close (assuan_fd_t fd);
assuan_fd_t assuan_sock_new (int domain, int type, int proto);
int assuan_sock_set_flag (assuan_fd_t sockfd, const char *name, int value);
int assuan_sock_get_flag (assuan_fd_t sockfd, const char *name, int *r_value);
int assuan_sock_connect (assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen);
assuan_fd_t assuan_sock_connect_byname (const char *host, unsigned short port,
int reserved,
const char *credentials,
unsigned int flags);
int assuan_sock_bind (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 (struct sockaddr *addr, int addrlen,
assuan_sock_nonce_t *nonce);
int assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce);
/* Set the default or per context system callbacks. This is
irreversible. */
void assuan_set_system_hooks (assuan_system_hooks_t system_hooks);
void assuan_ctx_set_system_hooks (assuan_context_t ctx,
assuan_system_hooks_t 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_spawn (assuan_context_t ctx, 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]);
int __assuan_socket (assuan_context_t ctx, int _namespace, int style, int protocol);
int __assuan_connect (assuan_context_t ctx, int 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);
pid_t __assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait, int *status, int options);
#define ASSUAN_SYSTEM_PTH_IMPL \
static void _assuan_pth_usleep (assuan_context_t ctx, unsigned int usec) \
{ (void) ctx; pth_usleep (usec); } \
static ssize_t _assuan_pth_read (assuan_context_t ctx, assuan_fd_t fd, \
void *buffer, size_t size) \
{ (void) ctx; return pth_read (fd, buffer, size); } \
static ssize_t _assuan_pth_write (assuan_context_t ctx, assuan_fd_t fd, \
const void *buffer, size_t size) \
{ (void) ctx; return pth_write (fd, buffer, size); } \
@include:sys-pth-impl@
static pid_t _assuan_pth_waitpid (assuan_context_t ctx, pid_t pid, \
int nowait, int *status, int options) \
{ (void) ctx; \
if (!nowait) return pth_waitpid (pid, status, options); \
else return 0; } \
\
struct assuan_system_hooks _assuan_system_pth = \
{ ASSUAN_SYSTEM_HOOKS_VERSION, _assuan_pth_usleep, __assuan_pipe, \
__assuan_close, _assuan_pth_read, _assuan_pth_write, \
_assuan_pth_recvmsg, _assuan_pth_sendmsg, \
__assuan_spawn, _assuan_pth_waitpid, __assuan_socketpair, \
__assuan_socket, __assuan_connect }
extern struct assuan_system_hooks _assuan_system_pth;
#define ASSUAN_SYSTEM_PTH &_assuan_system_pth
#define ASSUAN_SYSTEM_NPTH_IMPL \
static void _assuan_npth_usleep (assuan_context_t ctx, unsigned int usec) \
{ (void) ctx; npth_usleep (usec); } \
static ssize_t _assuan_npth_read (assuan_context_t ctx, assuan_fd_t fd, \
void *buffer, size_t size) \
{ ssize_t res; (void) ctx; npth_unprotect(); \
res = __assuan_read (ctx, fd, buffer, size); \
npth_protect(); return res; } \
static ssize_t _assuan_npth_write (assuan_context_t ctx, assuan_fd_t fd, \
const void *buffer, size_t size) \
{ ssize_t res; (void) ctx; npth_unprotect(); \
res = __assuan_write (ctx, fd, buffer, size); \
npth_protect(); return res; } \
static int _assuan_npth_recvmsg (assuan_context_t ctx, assuan_fd_t fd, \
assuan_msghdr_t msg, int flags) \
{ int res; (void) ctx; npth_unprotect(); \
res = __assuan_recvmsg (ctx, fd, msg, flags); \
npth_protect(); return res; } \
static int _assuan_npth_sendmsg (assuan_context_t ctx, assuan_fd_t fd, \
const assuan_msghdr_t msg, int flags) \
{ int res; (void) ctx; npth_unprotect(); \
res = __assuan_sendmsg (ctx, fd, msg, flags); \
npth_protect(); return res; } \
static pid_t _assuan_npth_waitpid (assuan_context_t ctx, pid_t pid, \
int nowait, int *status, int options) \
{ pid_t res; (void) ctx; npth_unprotect(); \
res = __assuan_waitpid (ctx, pid, nowait, status, options); \
npth_protect(); return res; } \
static int _assuan_npth_connect (assuan_context_t ctx, int sock, \
struct sockaddr *addr, socklen_t len)\
{ int res; npth_unprotect(); \
res = __assuan_connect (ctx, sock, addr, len); \
npth_protect(); return res; } \
\
struct assuan_system_hooks _assuan_system_npth = \
{ ASSUAN_SYSTEM_HOOKS_VERSION, _assuan_npth_usleep, __assuan_pipe, \
__assuan_close, _assuan_npth_read, _assuan_npth_write, \
_assuan_npth_recvmsg, _assuan_npth_sendmsg, \
__assuan_spawn, _assuan_npth_waitpid, __assuan_socketpair, \
__assuan_socket, _assuan_npth_connect }
extern struct assuan_system_hooks _assuan_system_npth;
#define ASSUAN_SYSTEM_NPTH &_assuan_system_npth
@include:w32ce-add@
#ifdef __cplusplus
}
#endif
#endif /* ASSUAN_H */
diff --git a/src/client.c b/src/client.c
index de0e88b..8b357e6 100644
--- a/src/client.c
+++ b/src/client.c
@@ -1,335 +1,336 @@
/* 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#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->pid != ASSUAN_INVALID_PID && ctx->pid)
{
_assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
ctx->pid = ASSUAN_INVALID_PID;
}
_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 (!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
{
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 (!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 147edae..82166bb 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1,229 +1,230 @@
/* 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#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;
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). */
void
assuan_end_confidential (assuan_context_t ctx)
{
assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0);
}
/* Set the system callbacks. */
void
assuan_ctx_set_system_hooks (assuan_context_t ctx,
assuan_system_hooks_t system_hooks)
{
TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_system_hooks", ctx,
"system_hooks=%p (version %i)", system_hooks,
system_hooks->version);
_assuan_system_hooks_copy (&ctx->system, system_hooks);
}
/* 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_ucred
fails. */
pid_t
assuan_get_pid (assuan_context_t ctx)
{
TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pid", ctx,
"pid=%i", ctx ? ctx->pid : -1);
return (ctx && ctx->pid) ? ctx->pid : ASSUAN_INVALID_PID;
}
/* 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/conversion.c b/src/conversion.c
index 88a7fd0..a86e5a9 100644
--- a/src/conversion.c
+++ b/src/conversion.c
@@ -1,113 +1,113 @@
/* conversion.c - String conversion helper functions.
- Copyright (C) 2000 Werner Koch (dd9jn)
- Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009 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, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
#if HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include "assuan-defs.h"
#include "debug.h"
/* Convert the number NR to a hexadecimal string. Returns the tail
pointer. */
static char *
_assuan_bytetohex (int nr, char *str)
{
static char hexdigits[] = "0123456789abcdef";
int i;
#define NROFHEXDIGITS 2
for (i = 0; i < NROFHEXDIGITS; i++)
{
int digit = (nr >> (i << 2)) & 0xf;
*(str++) = hexdigits[digit];
}
return str;
}
/* Encode the C formatted string SRC and return the malloc'ed result. */
char *
_assuan_encode_c_string (assuan_context_t ctx, const char *src)
{
const unsigned char *istr;
char *res;
char *ostr;
-
+
ostr = _assuan_malloc (ctx, 4 * strlen (src) + 1);
if (! *ostr)
return NULL;
res = ostr;
for (istr = (const unsigned char *) src; *istr; istr++)
{
int c = 0;
switch (*istr)
{
case '\r':
c = 'r';
break;
case '\n':
c = 'n';
break;
case '\f':
c = 'f';
break;
case '\v':
c = 'v';
break;
case '\b':
c = 'b';
break;
default:
if ((isascii (*istr) && isprint (*istr)) || (*istr >= 0x80))
*(ostr++) = *istr;
else
{
*(ostr++) = '\\';
*(ostr++) = 'x';
ostr = _assuan_bytetohex (*istr, ostr);
}
}
if (c)
{
*(ostr++) = '\\';
*(ostr++) = c;
}
}
*(ostr) = '\0';
return res;
}
diff --git a/src/debug.h b/src/debug.h
index 5ce0f07..78bbc23 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -1,276 +1,276 @@
/* debug.h - interface to debugging functions
- Copyright (C) 2002, 2004, 2005, 2007 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, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ * Copyright (C) 2002, 2004, 2005, 2007 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
#ifndef DEBUG_H
#define DEBUG_H
#include
#ifdef HAVE_STDINT_H
#include
#endif
#ifdef HAVE_INTTYPES_H
#include
#endif
#include "assuan-defs.h"
/* Indirect stringification, requires __STDC__ to work. */
#define STRINGIFY(v) #v
#define XSTRINGIFY(v) STRINGIFY(v)
/* Remove path components from filenames (i.e. __FILE__) for cleaner
logs. */
static GPG_ERR_INLINE const char *_assuan_debug_srcname (const char *file)
ASSUAN_GCC_A_PURE;
static GPG_ERR_INLINE const char *
_assuan_debug_srcname (const char *file)
{
const char *s = strrchr (file, '/');
return s ? s + 1 : file;
}
/* Called early to initialize the logging. */
void _assuan_debug_subsystem_init (void);
/* Log the formatted string FORMAT at debug level LEVEL or higher. */
void _assuan_debug (assuan_context_t ctx, unsigned int cat,
const char *format, ...);
/* Start a new debug line in *LINE, logged at level LEVEL or higher,
and starting with the formatted string FORMAT. */
void _assuan_debug_begin (assuan_context_t ctx,
void **helper, unsigned int cat,
const char *format, ...);
/* Add the formatted string FORMAT to the debug line *LINE. */
void _assuan_debug_add (assuan_context_t ctx,
void **helper, const char *format, ...);
/* Finish construction of *LINE and send it to the debug output
stream. */
void _assuan_debug_end (assuan_context_t ctx,
void **helper, unsigned int cat);
void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat,
const char *const fmt,
const char *const func, const char *const tagname,
void *tag, const char *const buffer, size_t len);
/* Trace support. */
#define _TRACE(ctx, lvl, name, tag) \
assuan_context_t _assuan_trace_context = ctx; \
int _assuan_trace_level = lvl; \
const char *const _assuan_trace_func = name; \
const char *const _assuan_trace_tagname = STRINGIFY (tag); \
void *_assuan_trace_tag = (void *) (uintptr_t) tag
#define TRACE_BEG(ctx,lvl, name, tag) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag)
#define TRACE_BEG0(ctx, lvl, name, tag, fmt) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag)
#define TRACE_BEG1(ctx, lvl, name, tag, fmt, arg1) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1)
#define TRACE_BEG2(ctx, lvl, name, tag, fmt, arg1, arg2) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2)
#define TRACE_BEG3(ctx, lvl, name, tag, fmt, arg1, arg2, arg3) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3)
#define TRACE_BEG4(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4)
#define TRACE_BEG6(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4,arg5,arg6) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4, arg5, arg6)
#define TRACE_BEG8(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \
arg5, arg6, arg7, arg8) \
_TRACE (ctx, lvl, name, tag); \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): enter: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4, \
arg5, arg6, arg7, arg8)
#define TRACE(ctx, lvl, name, tag) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag)
#define TRACE0(ctx, lvl, name, tag, fmt) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag)
#define TRACE1(ctx, lvl, name, tag, fmt, arg1) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1)
#define TRACE2(ctx, lvl, name, tag, fmt, arg1, arg2) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \
arg2)
#define TRACE3(ctx, lvl, name, tag, fmt, arg1, arg2, arg3) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \
arg2, arg3)
#define TRACE4(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \
arg2, arg3, arg4)
#define TRACE6(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
_assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \
name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \
arg2, arg3, arg4, arg5, arg6)
#define TRACE_ERR(err) \
err == 0 ? (TRACE_SUC ()) : \
(_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): error: %s <%s>\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, gpg_strerror (err), \
ctx?gpg_strsource (ctx->err_source):""), \
_assuan_error (ctx, err))
/* The cast to void suppresses GCC warnings. */
#define TRACE_SYSRES(res) \
res >= 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) : \
(_assuan_debug (_assuan_trace_context, _assuan_trace_level, "%s (%s=%p): error: %s\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, strerror (errno)), (res))
#define TRACE_SYSERR(res) \
res == 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) : \
(_assuan_debug (_assuan_trace_context, _assuan_trace_level, "%s (%s=%p): error: %s\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, strerror (res)), (res))
#define TRACE_SUC() \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): leave\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag), 0
#define TRACE_SUC0(fmt) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): leave: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag), 0
#define TRACE_SUC1(fmt, arg1) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): leave: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1), 0
#define TRACE_SUC2(fmt, arg1, arg2) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): leave: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2), 0
#define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): leave: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4, arg5), 0
#define TRACE_LOG(fmt) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag)
#define TRACE_LOG1(fmt, arg1) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1)
#define TRACE_LOG2(fmt, arg1, arg2) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2)
#define TRACE_LOG3(fmt, arg1, arg2, arg3) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3)
#define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4)
#define TRACE_LOG5(fmt, arg1, arg2, arg3, arg4, arg5) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4, arg5)
#define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
_assuan_debug (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: " fmt "\n", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, arg1, arg2, arg3, arg4, arg5, \
arg6)
#define TRACE_LOGBUF(buf, len) \
_assuan_debug_buffer (_assuan_trace_context, _assuan_trace_level, \
"%s (%s=%p): check: %s", \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag, buf, len)
#define TRACE_SEQ(hlp,fmt) \
_assuan_debug_begin (_assuan_trace_context, &(hlp), \
"%s (%s=%p): check: " fmt, \
_assuan_trace_func, _assuan_trace_tagname, \
_assuan_trace_tag)
#define TRACE_ADD0(hlp,fmt) \
_assuan_debug_add (_assuan_trace_context, &(hlp), fmt)
#define TRACE_ADD1(hlp,fmt,a) \
_assuan_debug_add (_assuan_trace_context, &(hlp), fmt, (a))
#define TRACE_ADD2(hlp,fmt,a,b) \
_assuan_debug_add (_assuan_trace_context, &(hlp), fmt, (a), (b))
#define TRACE_ADD3(hlp,fmt,a,b,c) \
_assuan_debug_add (_assuan_trace_context, &(hlp), fmt, (a), (b), (c))
#define TRACE_END(hlp,fmt) \
_assuan_debug_add (_assuan_trace_context, &(hlp), fmt); \
_assuan_debug_end (_assuan_trace_context, &(hlp), _assuan_trace_level)
#define TRACE_ENABLED(hlp) (!!(hlp))
#endif /* DEBUG_H */
diff --git a/src/funopen.c b/src/funopen.c
index e6d77e3..466d9aa 100644
--- a/src/funopen.c
+++ b/src/funopen.c
@@ -1,62 +1,63 @@
/* funopen.c - Replacement for funopen.
* Copyright (C) 2003, 2005 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
/* Replacement for the *BSD function:
FILE *funopen (void *cookie,
int (*readfn)(void *, char *, int),
int (*writefn)(void *, const char *, int),
fpos_t (*seekfn)(void *, fpos_t, int),
int (*closefn)(void *));
The functions to provide my either be NULL if not required or
similar to the unistd function with the exception of using the
cookie instead of the file descriptor.
*/
#ifdef HAVE_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)
{
cookie_io_functions_t io;
io.read = readfn;
io.write = writefn;
io.seek = seekfn;
io.close = closefn;
return fopencookie (cookie,
readfn ? ( writefn ? "rw" : "r" )
: ( writefn ? "w" : ""), io);
}
#else
#error No known way to implement funopen.
#endif
diff --git a/src/gpgcedev.c b/src/gpgcedev.c
index bff4655..c841ec2 100644
--- a/src/gpgcedev.c
+++ b/src/gpgcedev.c
@@ -1,1640 +1,1640 @@
/* gpgcedrv.c - WindowsCE device driver to implement pipe and syslog.
- Copyright (C) 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 3 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 .
+ * Copyright (C) 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 3 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 .
+ * SPDX-License-Identifier: LGPL-3.0+
*/
-
#include
#include
#include
#include
#include
#include
/* FIXME Cancel not handled. */
#define DBGFILENAME "\\gpgcedev.dbg"
#define LOGFILENAME L"\\gpgcedev.log"
#define GPGCEDEV_KEY_NAME L"Drivers\\GnuPG_Device"
#define GPGCEDEV_KEY_NAME2 L"Drivers\\GnuPG_Log"
/* Missing IOCTLs in the current mingw32ce. */
#ifndef IOCTL_PSL_NOTIFY
# define FILE_DEVICE_PSL 259
# define IOCTL_PSL_NOTIFY \
CTL_CODE (259, 255, METHOD_NEITHER, FILE_ANY_ACCESS)
#endif /*IOCTL_PSL_NOTIFY*/
/* The IOCTL to return the rendezvous id of the handle.
The required outbuf parameter is the address of a variable to store
the rendezvous ID, which is a LONG value. */
#define GPGCEDEV_IOCTL_GET_RVID \
CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
-/* The IOCTL used to create the pipe.
+/* The IOCTL used to create the pipe.
The caller sends this IOCTL to the read or the write handle. The
required inbuf parameter is address of a variable holding the
rendezvous id of the pipe's other end. There is one possible
problem with the code: If a pipe is kept in non-rendezvous state
until after the rendezvous ids overflow, it is possible that the
wrong end will be used. However this is not a realistic scenario. */
#define GPGCEDEV_IOCTL_MAKE_PIPE \
CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
/* The IOCTL used to unblock a blocking thread.
The caller sends this IOCTL to the read or the write handle. No
parameter is required. The effect is that a reader or writer
blocked on the same handle is unblocked (and will return
ERROR_BUSY). Note that the operation can be repeated, if so
desired. The state of the pipe itself will not be affected in any
way. */
#define GPGCEDEV_IOCTL_UNBLOCK \
CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
/* The IOCTL to assign a rendezvous id to a process.
The required inbuf parameters are the rendezvous ID to assign and
the process ID of the process receiving the RVID. The handle on
which this is called is not really used at all! */
#define GPGCEDEV_IOCTL_ASSIGN_RVID \
CTL_CODE (FILE_DEVICE_STREAMS, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
/* An object to describe a pipe. */
struct pipeimpl_s
{
CRITICAL_SECTION critsect; /* Lock for all members. */
int refcnt;
- char *buffer;
+ char *buffer;
size_t buffer_size;
size_t buffer_len; /* The valid length of the bufer. */
size_t buffer_pos; /* The actual read position. */
#define PIPE_FLAG_NO_READER 1
#define PIPE_FLAG_NO_WRITER 2
#define PIPE_FLAG_UNBLOCK_READER 4
#define PIPE_FLAG_UNBLOCK_WRITER 8
#define PIPE_FLAG_HALT_MONITOR 16
int flags;
HANDLE space_available; /* Set if space is available. */
- HANDLE data_available; /* Set if data is available. */
+ HANDLE data_available; /* Set if data is available. */
/* For the monitor thread started by ASSIGN_RVID. */
HANDLE monitor_proc;
int monitor_access;
LONG monitor_rvid;
};
typedef struct pipeimpl_s *pipeimpl_t;
/* An object to describe a logging context. We can't write directly
to the log stream because we want to do line buffering and thus we
need to store data until we see LF. */
struct logimpl_s;
typedef struct logimpl_s *logimpl_t;
struct logimpl_s
{
unsigned long logid; /* An identifier for a log source. */
unsigned long dsec; /* Tenth of a second since system start. */
char *line; /* Malloced line buffer. */
size_t linesize; /* Allocated size of LINE. */
size_t linelen; /* Used length of the line. */
int truncated; /* Indicates a truncated log line. */
};
/* An object to store information pertaining to an open-context. */
struct opnctx_s;
typedef struct opnctx_s *opnctx_t;
struct opnctx_s
{
int inuse; /* True if this object has valid data. */
int is_log; /* True if this describes a log device. */
LONG rvid; /* The unique rendezvous identifier. */
DWORD access_code;/* Value from OpenFile. */
DWORD share_mode; /* Value from OpenFile. */
/* The state shared by all pipe users. Only used if IS_LOG is false. */
pipeimpl_t pipeimpl;
/* The state used to implement a log stream. Only used if IS_LOG is true. */
logimpl_t logimpl;
};
/* A malloced table of open-context and the number of allocated slots. */
static opnctx_t opnctx_table;
static size_t opnctx_table_size;
/* The macros make sure that 0 is never a valid openctx_arg. */
#define OPNCTX_TO_IDX(ctx_arg) (((ctx_arg) - opnctx_table) + 1)
#define OPNCTX_FROM_IDX(idx) (&opnctx_table[(idx) - 1])
#define OPNCTX_VALID_IDX_P(idx) ((idx) > 0 && (idx) <= opnctx_table_size)
typedef struct monitor_s *monitor_t;
struct monitor_s
{
int inuse; /* True if this object has valid data. */
pipeimpl_t pipeimpl;
};
static monitor_t monitor_table;
static size_t monitor_table_size;
/* A criticial section object used to protect the OPNCTX_TABLE and
MONITOR_TABLE. */
static CRITICAL_SECTION opnctx_table_cs;
/* A global object to control the logging. */
struct {
CRITICAL_SECTION lock; /* Lock for this structure. */
HANDLE filehd; /* Handle of the log output file. */
int references; /* Number of objects references this one. */
} logcontrol;
/* We don't need a device context for the pipe thus we use the address
of the critical section object for it. */
#define PIPECTX_VALUE ((DWORD)(&opnctx_table_cs))
/* The device context for the log device is the address of our
control structure. */
#define LOGCTX_VALUE ((DWORD)(&logcontrol))
/* True if we have enabled debugging. */
static int enable_debug;
/* True if logging has been enabled. */
static int enable_logging;
static void
log_debug (const char *fmt, ...)
{
if (enable_debug)
{
va_list arg_ptr;
FILE *fp;
-
+
fp = fopen (DBGFILENAME, "a+");
if (!fp)
return;
va_start (arg_ptr, fmt);
vfprintf (fp, fmt, arg_ptr);
va_end (arg_ptr);
fclose (fp);
}
}
/* Return a new rendezvous id. We will never return an RVID of 0. */
static LONG
create_rendezvous_id (void)
{
static LONG rendezvous_id;
LONG rvid;
while (!(rvid = InterlockedIncrement (&rendezvous_id)))
;
return rvid;
}
/* Return a new log id. These log ids are used to identify log lines
send to the same device; ie. for each CreateFile("GPG2:") a new log
id is assigned. We will ever return a log id of 0. */
static LONG
create_log_id (void)
{
static LONG log_id;
LONG lid;
while (!(lid = InterlockedIncrement (&log_id)))
;
return lid;
}
pipeimpl_t
pipeimpl_new (void)
{
pipeimpl_t pimpl;
pimpl = malloc (sizeof (*pimpl));
if (!pimpl)
return NULL;
InitializeCriticalSection (&pimpl->critsect);
pimpl->refcnt = 1;
pimpl->buffer_size = 512;
pimpl->buffer = malloc (pimpl->buffer_size);
if (!pimpl->buffer)
{
DeleteCriticalSection (&pimpl->critsect);
free (pimpl);
return NULL;
}
pimpl->buffer_len = 0;
pimpl->buffer_pos = 0;
pimpl->flags = 0;
pimpl->space_available = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!pimpl->space_available)
{
free (pimpl->buffer);
DeleteCriticalSection (&pimpl->critsect);
free (pimpl);
return NULL;
}
pimpl->data_available = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!pimpl->data_available)
{
CloseHandle (pimpl->space_available);
free (pimpl->buffer);
DeleteCriticalSection (&pimpl->critsect);
free (pimpl);
return NULL;
}
pimpl->monitor_proc = INVALID_HANDLE_VALUE;
pimpl->monitor_access = 0;
pimpl->monitor_rvid = 0;
return pimpl;
}
/* PIMPL must be locked. It is unlocked at exit. */
void
pipeimpl_unref (pipeimpl_t pimpl)
{
int release = 0;
if (!pimpl)
return;
log_debug ("pipeimpl_unref (%p): dereference\n", pimpl);
if (--pimpl->refcnt == 0)
release = 1;
LeaveCriticalSection (&pimpl->critsect);
if (! release)
return;
log_debug ("pipeimpl_unref (%p): release\n", pimpl);
DeleteCriticalSection (&pimpl->critsect);
if (pimpl->buffer)
{
free (pimpl->buffer);
pimpl->buffer = NULL;
pimpl->buffer_size = 0;
}
if (pimpl->space_available != INVALID_HANDLE_VALUE)
{
CloseHandle (pimpl->space_available);
pimpl->space_available = INVALID_HANDLE_VALUE;
}
if (pimpl->data_available != INVALID_HANDLE_VALUE)
{
CloseHandle (pimpl->data_available);
pimpl->data_available = INVALID_HANDLE_VALUE;
}
}
/* Allocate a new log structure. */
logimpl_t
logimpl_new (void)
{
logimpl_t limpl;
limpl = calloc (1, sizeof *limpl);
if (!limpl)
return NULL;
limpl->logid = create_log_id ();
limpl->linesize = 256;
limpl->line = malloc (limpl->linesize);
if (!limpl->line)
{
free (limpl);
return NULL;
}
return limpl;
}
/* There is no need to lock LIMPL, thus is a dummy function. */
void
logimpl_unref (logimpl_t limpl)
{
(void)limpl;
}
/* Flush a pending log line. */
static void
logimpl_flush (logimpl_t limpl)
{
if (!limpl->linelen || !enable_logging)
return;
EnterCriticalSection (&logcontrol.lock);
if (logcontrol.filehd == INVALID_HANDLE_VALUE)
logcontrol.filehd = CreateFile (LOGFILENAME, GENERIC_WRITE,
FILE_SHARE_READ,
NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (!logcontrol.filehd)
log_debug ("can't open log file: rc=%d\n", (int)GetLastError ());
else
{
char buf[50];
DWORD nwritten;
- snprintf (buf, sizeof buf,
+ snprintf (buf, sizeof buf,
"%06lu/%lu//", limpl->dsec % 1000000, limpl->logid);
if (!WriteFile (logcontrol.filehd, buf, strlen (buf), &nwritten, NULL))
log_debug ("error writing log file: rc=%d\n", (int)GetLastError ());
else if (!WriteFile (logcontrol.filehd,
limpl->line, limpl->linelen, &nwritten, NULL))
log_debug ("error writing log file: rc=%d\n", (int)GetLastError ());
snprintf (buf, sizeof buf, "%s\n", limpl->truncated? "[...]":"");
if (!WriteFile (logcontrol.filehd, buf, strlen (buf), &nwritten, NULL))
log_debug ("error writing log file: rc=%d\n", (int)GetLastError ());
}
LeaveCriticalSection (&logcontrol.lock);
limpl->linelen = 0;
limpl->truncated = 0;
}
/* Return a new opnctx handle and mark it as used. Returns NULL and
sets LastError on memory failure etc. opnctx_table_cs must be
locked on entry and is locked on exit. Note that the returned
pointer is only valid as long as opnctx_table_cs stays locked, as
it is not stable under table reallocation. */
static opnctx_t
allocate_opnctx (int is_log)
{
opnctx_t opnctx = NULL;
int idx;
for (idx = 0; idx < opnctx_table_size; idx++)
if (! opnctx_table[idx].inuse)
break;
if (idx == opnctx_table_size)
{
/* We need to increase the size of the table. The approach we
take is straightforward to minimize the risk of bugs. */
opnctx_t newtbl;
size_t newsize = opnctx_table_size + 64;
newtbl = calloc (newsize, sizeof *newtbl);
if (!newtbl)
goto leave;
memcpy (newtbl, opnctx_table, opnctx_table_size * sizeof (*newtbl));
free (opnctx_table);
opnctx_table = newtbl;
idx = opnctx_table_size;
opnctx_table_size = newsize;
}
opnctx = &opnctx_table[idx];
opnctx->inuse = 1;
opnctx->is_log = is_log;
opnctx->rvid = 0;
opnctx->access_code = 0;
opnctx->share_mode = 0;
opnctx->pipeimpl = 0;
opnctx->logimpl = 0;
leave:
return opnctx;
}
/* Verify context CTX, returns NULL if not valid and the pointer to
the context if valid. opnctx_table_cs must be locked on entry and
is locked on exit. Note that the returned pointer is only valid as
long as opnctx_table_cs remains locked. */
opnctx_t
verify_opnctx (DWORD ctx_arg)
{
opnctx_t ctx;
if (! OPNCTX_VALID_IDX_P (ctx_arg))
{
SetLastError (ERROR_INVALID_HANDLE);
return NULL;
}
ctx = OPNCTX_FROM_IDX (ctx_arg);
if (! ctx->inuse)
{
SetLastError (ERROR_INVALID_HANDLE);
return NULL;
}
return ctx;
}
/* Return a new monitor handle and mark it as used. Returns NULL and
sets LastError on memory failure etc. opnctx_table_cs must be
locked on entry and is locked on exit. Note that the returned
pointer is only valid as long as opnctx_table_cs stays locked, as
it is not stable under table reallocation. */
static monitor_t
allocate_monitor (void)
{
monitor_t monitor = NULL;
int idx;
for (idx = 0; idx < monitor_table_size; idx++)
if (! monitor_table[idx].inuse)
break;
if (idx == monitor_table_size)
{
/* We need to increase the size of the table. The approach we
take is straightforward to minimize the risk of bugs. */
monitor_t newtbl;
size_t newsize = monitor_table_size + 16;
newtbl = calloc (newsize, sizeof *newtbl);
if (!newtbl)
goto leave;
memcpy (newtbl, monitor_table, monitor_table_size * sizeof (*newtbl));
free (monitor_table);
monitor_table = newtbl;
idx = monitor_table_size;
monitor_table_size = newsize;
}
monitor = &monitor_table[idx];
monitor->inuse = 1;
monitor->pipeimpl = 0;
leave:
return monitor;
}
static pipeimpl_t
assert_pipeimpl (opnctx_t ctx)
{
DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
if (ctx->is_log)
{
log_debug (" assert_pipeimpl (ctx=%i): "
"error: not valid for a log device\n", ctx_arg);
return NULL;
}
if (! ctx->pipeimpl)
{
ctx->pipeimpl = pipeimpl_new ();
if (! ctx->pipeimpl)
{
log_debug (" assert_pipeimpl (ctx=%i): error: can't create pipe\n",
ctx_arg);
return NULL;
}
log_debug (" assert_pipeimpl (ctx=%i): created pipe 0x%p\n",
ctx_arg, ctx->pipeimpl);
}
return ctx->pipeimpl;
}
static logimpl_t
assert_logimpl (opnctx_t ctx)
{
DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
if (!ctx->is_log)
{
log_debug (" assert_logimpl (ctx=%i): "
"error: not valid for a pipe device\n", ctx_arg);
return NULL;
}
if (!ctx->logimpl)
{
ctx->logimpl = logimpl_new ();
if (!ctx->logimpl)
{
log_debug (" assert_logimpl (ctx=%i): error: can't create log\n",
ctx_arg);
return NULL;
}
log_debug (" assert_logimpl (ctx=%i): created log 0x%p\n",
ctx_arg, ctx->logimpl);
}
return ctx->logimpl;
}
/* Verify access CODE for context CTX_ARG, returning a reference to
the locked pipe or the locked log implementation. opnctx_table_cs
must be unlocked on entry and is unlocked on exit. */
int
access_opnctx (DWORD ctx_arg, DWORD code, pipeimpl_t *r_pipe, logimpl_t *r_log)
{
opnctx_t ctx;
*r_pipe = NULL;
*r_log = NULL;
EnterCriticalSection (&opnctx_table_cs);
ctx = verify_opnctx (ctx_arg);
if (! ctx)
{
/* Error is set by verify_opnctx. */
LeaveCriticalSection (&opnctx_table_cs);
return -1;
}
if (! (ctx->access_code & code))
{
SetLastError (ERROR_INVALID_ACCESS);
LeaveCriticalSection (&opnctx_table_cs);
return -1;
}
if (ctx->is_log)
{
logimpl_t limpl;
limpl = assert_logimpl (ctx);
if (!limpl)
{
LeaveCriticalSection (&opnctx_table_cs);
return -1;
}
*r_log = limpl;
}
else
{
pipeimpl_t pimpl;
pimpl = assert_pipeimpl (ctx);
if (! pimpl)
{
LeaveCriticalSection (&opnctx_table_cs);
return -1;
}
EnterCriticalSection (&pimpl->critsect);
pimpl->refcnt++;
*r_pipe = pimpl;
}
LeaveCriticalSection (&opnctx_table_cs);
return 0;
}
static char *
wchar_to_utf8 (const wchar_t *string)
{
int n;
size_t length = wcslen (string);
char *result;
n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
if (n < 0 || (n+1) <= 0)
abort ();
result = malloc (n+1);
if (!result)
abort ();
n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
if (n < 0)
abort ();
-
+
result[n] = 0;
return result;
}
/* Initialize the device and return a device specific context. */
DWORD
GPG_Init (LPCTSTR active_key, DWORD bus_context)
{
static int firsttimedone;
HKEY handle;
wchar_t buffer[25];
DWORD buflen;
DWORD result;
(void)bus_context;
EnterCriticalSection (&logcontrol.lock);
if (!firsttimedone)
{
firsttimedone++;
if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME,
0, KEY_READ, &handle))
{
buflen = sizeof buffer;
if (!RegQueryValueEx (handle, L"debugDriver", 0, NULL,
(PBYTE)buffer, &buflen)
&& wcstol (buffer, NULL, 10) > 0)
enable_debug = 1;
RegCloseKey (handle);
}
if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2,
0, KEY_READ, &handle))
{
buflen = sizeof buffer;
if (!RegQueryValueEx (handle, L"enableLog", 0, NULL,
(PBYTE)buffer, &buflen)
&& wcstol (buffer, NULL, 10) > 0)
enable_logging = 1;
RegCloseKey (handle);
}
}
LeaveCriticalSection (&logcontrol.lock);
if (enable_debug)
{
char *tmpbuf;
tmpbuf = wchar_to_utf8 (active_key);
log_debug ("GPG_Init (%s)\n", tmpbuf);
free (tmpbuf);
}
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, active_key, 0, KEY_READ, &handle))
{
- log_debug ("GPG_Init: error reading registry: rc=%d\n",
+ log_debug ("GPG_Init: error reading registry: rc=%d\n",
(int)GetLastError ());
return 0;
}
buflen = sizeof buffer;
if (RegQueryValueEx (handle, L"Name", 0, NULL, (PBYTE)buffer, &buflen))
{
- log_debug ("GPG_Init: error reading registry value 'Name': rc=%d\n",
+ log_debug ("GPG_Init: error reading registry value 'Name': rc=%d\n",
(int)GetLastError ());
result = 0;
}
else if (!wcscmp (buffer, L"GPG1:"))
{
/* This is the pipe device: We don't need any global data.
However, we need to return something. */
log_debug ("GPG_Init: created pipe device (devctx=%p)\n", PIPECTX_VALUE);
result = PIPECTX_VALUE;
}
else if (!wcscmp (buffer, L"GPG2:"))
{
/* This is the log device. Clear the object and return something. */
logcontrol.filehd = INVALID_HANDLE_VALUE;
log_debug ("GPG_Init: created log device (devctx=%p)\n", 0);
result = LOGCTX_VALUE;
}
else
{
if (enable_debug)
{
char *tmpbuf;
tmpbuf = wchar_to_utf8 (buffer);
log_debug ("GPG_Init: device '%s' is not supported\n", tmpbuf);
free (tmpbuf);
}
SetLastError (ERROR_DEV_NOT_EXIST);
result = 0;
}
RegCloseKey (handle);
return result;
}
/* Deinitialize this device driver. */
BOOL
GPG_Deinit (DWORD devctx)
{
log_debug ("GPG_Deinit (devctx=0x%p)\n", (void*)devctx);
if (devctx == PIPECTX_VALUE)
{
/* No need to release resources. */
}
else if (devctx == LOGCTX_VALUE)
{
EnterCriticalSection (&logcontrol.lock);
if (logcontrol.filehd != INVALID_HANDLE_VALUE)
{
CloseHandle (logcontrol.filehd);
logcontrol.filehd = INVALID_HANDLE_VALUE;
}
LeaveCriticalSection (&logcontrol.lock);
}
else
{
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE; /* Error. */
}
-
+
return TRUE; /* Success. */
}
/* Create a new open context. This function is called due to a
CreateFile from the application. */
DWORD
GPG_Open (DWORD devctx, DWORD access_code, DWORD share_mode)
{
opnctx_t opnctx;
DWORD ctx_arg = 0;
int is_log;
log_debug ("GPG_Open (devctx=%p)\n", (void*)devctx);
if (devctx == PIPECTX_VALUE)
is_log = 0;
else if (devctx == LOGCTX_VALUE)
is_log = 1;
else
{
log_debug ("GPG_Open (devctx=%p): error: wrong devctx (expected 0x%p)\n",
(void*) devctx);
SetLastError (ERROR_INVALID_PARAMETER);
return 0; /* Error. */
}
EnterCriticalSection (&opnctx_table_cs);
opnctx = allocate_opnctx (is_log);
if (!opnctx)
{
log_debug ("GPG_Open (devctx=%p): error: could not allocate context\n",
(void*) devctx);
goto leave;
}
opnctx->access_code = access_code;
opnctx->share_mode = share_mode;
ctx_arg = OPNCTX_TO_IDX (opnctx);
log_debug ("GPG_Open (devctx=%p, is_log=%d): success: created context %i\n",
(void*) devctx, is_log, ctx_arg);
if (is_log)
{
EnterCriticalSection (&logcontrol.lock);
logcontrol.references++;
LeaveCriticalSection (&logcontrol.lock);
}
leave:
LeaveCriticalSection (&opnctx_table_cs);
return ctx_arg;
}
BOOL
GPG_Close (DWORD opnctx_arg)
{
opnctx_t opnctx;
BOOL result = FALSE;
log_debug ("GPG_Close (ctx=%i)\n", opnctx_arg);
EnterCriticalSection (&opnctx_table_cs);
opnctx = verify_opnctx (opnctx_arg);
if (!opnctx)
{
log_debug ("GPG_Close (ctx=%i): could not find context\n", opnctx_arg);
goto leave;
}
if (opnctx->pipeimpl)
{
pipeimpl_t pimpl = opnctx->pipeimpl;
EnterCriticalSection (&pimpl->critsect);
/* This needs to be adjusted if there can be multiple
reader/writers. */
if (opnctx->access_code & GENERIC_READ)
{
pimpl->flags |= PIPE_FLAG_NO_READER;
SetEvent (pimpl->space_available);
}
else if (opnctx->access_code & GENERIC_WRITE)
{
pimpl->flags |= PIPE_FLAG_NO_WRITER;
SetEvent (pimpl->data_available);
}
pipeimpl_unref (pimpl);
opnctx->pipeimpl = 0;
}
if (opnctx->logimpl)
{
logimpl_t limpl = opnctx->logimpl;
logimpl_flush (limpl);
logimpl_unref (limpl);
free (limpl->line);
free (limpl);
opnctx->logimpl = 0;
EnterCriticalSection (&logcontrol.lock);
logcontrol.references--;
if (!logcontrol.references && logcontrol.filehd)
{
CloseHandle (logcontrol.filehd);
logcontrol.filehd = INVALID_HANDLE_VALUE;
}
LeaveCriticalSection (&logcontrol.lock);
}
opnctx->access_code = 0;
opnctx->share_mode = 0;
opnctx->rvid = 0;
opnctx->inuse = 0;
result = TRUE;
log_debug ("GPG_Close (ctx=%i): success\n", opnctx_arg);
leave:
LeaveCriticalSection (&opnctx_table_cs);
return result;
}
DWORD
GPG_Read (DWORD opnctx_arg, void *buffer, DWORD count)
{
pipeimpl_t pimpl;
logimpl_t limpl;
const char *src;
char *dst;
int result = -1;
log_debug ("GPG_Read (ctx=%i, buffer=0x%p, count=%d)\n",
opnctx_arg, buffer, count);
if (access_opnctx (opnctx_arg, GENERIC_READ, &pimpl, &limpl))
{
log_debug ("GPG_Read (ctx=%i): error: could not access context\n",
opnctx_arg);
return -1;
}
if (limpl)
{
/* Reading from a log stream does not make sense. Return EOF. */
result = 0;
goto leave;
}
retry:
if (pimpl->buffer_pos == pimpl->buffer_len)
{
HANDLE data_available = pimpl->data_available;
/* Check for end of file. */
if (pimpl->flags & PIPE_FLAG_NO_WRITER)
{
log_debug ("GPG_Read (ctx=%i): success: EOF\n", opnctx_arg);
result = 0;
goto leave;
}
/* Check for request to unblock once. */
if (pimpl->flags & PIPE_FLAG_UNBLOCK_READER)
{
log_debug ("GPG_Read (ctx=%i): success: EBUSY (due to unblock)\n",
opnctx_arg);
pimpl->flags &= ~PIPE_FLAG_UNBLOCK_READER;
SetLastError (ERROR_BUSY);
result = -1;
goto leave;
}
LeaveCriticalSection (&pimpl->critsect);
log_debug ("GPG_Read (ctx=%i): waiting: data_available\n", opnctx_arg);
WaitForSingleObject (data_available, INFINITE);
log_debug ("GPG_Read (ctx=%i): resuming: data_available\n", opnctx_arg);
EnterCriticalSection (&pimpl->critsect);
goto retry;
}
-
+
dst = buffer;
src = pimpl->buffer + pimpl->buffer_pos;
while (count > 0 && pimpl->buffer_pos < pimpl->buffer_len)
{
*dst++ = *src++;
count--;
pimpl->buffer_pos++;
}
result = (dst - (char*)buffer);
if (pimpl->buffer_pos == pimpl->buffer_len)
pimpl->buffer_pos = pimpl->buffer_len = 0;
-
+
/* Now there should be some space available. Signal the write end.
Even if COUNT was passed as NULL and no space is available,
signaling must be done. */
if (!SetEvent (pimpl->space_available))
log_debug ("GPG_Read (ctx=%i): warning: SetEvent(space_available) "
"failed: rc=%d\n", opnctx_arg, (int)GetLastError ());
log_debug ("GPG_Read (ctx=%i): success: result=%d\n", opnctx_arg, result);
leave:
pipeimpl_unref (pimpl);
logimpl_unref (limpl);
return result;
}
DWORD
GPG_Write (DWORD opnctx_arg, const void *buffer, DWORD count)
{
pipeimpl_t pimpl;
logimpl_t limpl;
int result = -1;
const char *src;
char *dst;
size_t nwritten = 0;
log_debug ("GPG_Write (ctx=%i, buffer=0x%p, count=%d)\n", opnctx_arg,
buffer, count);
if (access_opnctx (opnctx_arg, GENERIC_WRITE, &pimpl, &limpl))
{
log_debug ("GPG_Write (ctx=%i): error: could not access context\n",
opnctx_arg);
return -1;
}
if (!count)
{
log_debug ("GPG_Write (ctx=%i): success\n", opnctx_arg);
result = 0;
goto leave;
}
retry:
if (limpl)
{
/* Store it in our buffer up to a LF and print complete lines. */
result = count;
if (!limpl->linelen)
limpl->dsec = GetTickCount () / 100;
dst = limpl->line + limpl->linelen;
for (src = buffer; count; count--, src++)
{
if (*src == '\n')
{
logimpl_flush (limpl);
dst = limpl->line + limpl->linelen;
}
else if (limpl->linelen >= limpl->linesize)
limpl->truncated = 1;
else
{
*dst++ = *src;
limpl->linelen++;
}
}
}
else /* pimpl */
{
/* Check for broken pipe. */
if (pimpl->flags & PIPE_FLAG_NO_READER)
{
log_debug ("GPG_Write (ctx=%i): error: broken pipe\n", opnctx_arg);
SetLastError (ERROR_BROKEN_PIPE);
goto leave;
}
-
+
/* Check for request to unblock once. */
if (pimpl->flags & PIPE_FLAG_UNBLOCK_WRITER)
{
log_debug ("GPG_Write (ctx=%i): success: EBUSY (due to unblock)\n",
opnctx_arg);
pimpl->flags &= ~PIPE_FLAG_UNBLOCK_WRITER;
SetLastError (ERROR_BUSY);
result = -1;
goto leave;
}
-
+
/* Write to our buffer. */
if (pimpl->buffer_len == pimpl->buffer_size)
{
/* Buffer is full. */
HANDLE space_available = pimpl->space_available;
LeaveCriticalSection (&pimpl->critsect);
log_debug ("GPG_Write (ctx=%i): waiting: space_available\n",
opnctx_arg);
WaitForSingleObject (space_available, INFINITE);
log_debug ("GPG_Write (ctx=%i): resuming: space_available\n",
opnctx_arg);
EnterCriticalSection (&pimpl->critsect);
goto retry;
}
-
+
src = buffer;
dst = pimpl->buffer + pimpl->buffer_len;
while (count > 0 && pimpl->buffer_len < pimpl->buffer_size)
{
*dst++ = *src++;
count--;
pimpl->buffer_len++;
nwritten++;
}
result = nwritten;
-
+
if (!SetEvent (pimpl->data_available))
log_debug ("GPG_Write (ctx=%i): warning: SetEvent(data_available) "
"failed: rc=%d\n", opnctx_arg, (int)GetLastError ());
}
-
+
log_debug ("GPG_Write (ctx=%i): success: result=%d\n", opnctx_arg, result);
leave:
pipeimpl_unref (pimpl);
logimpl_unref (limpl);
return result;
}
DWORD
GPG_Seek (DWORD opnctx_arg, long amount, WORD type)
{
SetLastError (ERROR_SEEK_ON_DEVICE);
return -1; /* Error. */
}
/* opnctx_table_s is locked on entering and on exit. */
static BOOL
make_pipe (opnctx_t ctx, LONG rvid)
{
DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
opnctx_t peerctx = NULL;
int idx;
pipeimpl_t pimpl;
log_debug (" make_pipe (ctx=%i, rvid=%08lx)\n", ctx_arg, rvid);
if (ctx->pipeimpl)
{
log_debug (" make_pipe (ctx=%i): error: already assigned\n", ctx_arg);
SetLastError (ERROR_ALREADY_ASSIGNED);
return FALSE;
}
/* GnuPG and other programs don't use the safe ASSIGN_RVID call
because they guarantee that the context exists during the whole
time the child process runs. GPGME is more asynchronous and
relies on ASSIGN_RVID monitors. So, first check for open
contexts, then check for monitors. */
for (idx = 0; idx < opnctx_table_size; idx++)
if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid)
{
peerctx = &opnctx_table[idx];
break;
}
if (peerctx)
{
/* This is the GnuPG etc case, where the context is still open.
It may also cover the GPGME case if GPGME is still using its
own end of the pipe at the time of this call. */
if (peerctx == ctx)
{
log_debug (" make_pipe (ctx=%i): error: target and source identical\n",
ctx_arg);
SetLastError (ERROR_INVALID_TARGET_HANDLE);
return FALSE;
}
if ((ctx->access_code & GENERIC_READ))
{
/* Check that the peer is a write end. */
if (!(peerctx->access_code & GENERIC_WRITE))
{
log_debug (" make_pipe (ctx=%i): error: peer is not writer\n",
ctx_arg);
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
}
else if ((ctx->access_code & GENERIC_WRITE))
{
/* Check that the peer is a read end. */
if (!(peerctx->access_code & GENERIC_READ))
{
log_debug (" make_pipe (ctx=%i): error: peer is not reader\n",
ctx_arg);
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
}
else
{
log_debug (" make_pipe (ctx=%i): error: invalid access\n", ctx_arg);
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
-
+
/* Make sure the peer has a pipe implementation to be shared. If
not yet, create one. */
pimpl = assert_pipeimpl (peerctx);
if (! pimpl)
return FALSE;
}
else
{
/* This is the case where ASSIGN_RVID was called to create a
monitor, and the pipe is already closed at the parent side.
For example GPGME verify detached plain text, where GPG calls
MAKE_PIPE very late. */
-
+
for (idx = 0; idx < monitor_table_size; idx++)
if (monitor_table[idx].inuse
&& monitor_table[idx].pipeimpl->monitor_rvid == rvid)
{
pimpl = monitor_table[idx].pipeimpl;
break;
}
if (idx == monitor_table_size)
{
log_debug (" make_pipe (ctx=%i): error: not found\n", ctx_arg);
SetLastError (ERROR_NOT_FOUND);
return FALSE;
}
if (ctx->access_code & GENERIC_READ)
{
/* Check that the peer is a write end. */
if (!(pimpl->monitor_access & GENERIC_READ))
{
log_debug (" make_pipe (ctx=%i): error: monitor is not reader\n",
ctx_arg);
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
}
else if ((ctx->access_code & GENERIC_WRITE))
{
/* Check that the peer is a read end. */
if (!(pimpl->monitor_access & GENERIC_WRITE))
{
log_debug (" make_pipe (ctx=%i): error: monitor is not writer\n",
ctx_arg);
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
}
else
{
log_debug (" make_pipe (ctx=%i): error: invalid access\n", ctx_arg);
SetLastError (ERROR_INVALID_ACCESS);
return FALSE;
}
}
EnterCriticalSection (&pimpl->critsect);
pimpl->refcnt++;
if (pimpl->monitor_proc != INVALID_HANDLE_VALUE)
{
/* If there is a monitor to the pipe, then it's now about time
to ask it to go away. */
log_debug (" make_pipe (ctx=%i): waking up monitor for pipe 0x%p\n",
ctx_arg, pimpl);
pimpl->flags |= PIPE_FLAG_HALT_MONITOR;
if (pimpl->monitor_access & GENERIC_READ)
SetEvent (pimpl->data_available);
else
SetEvent (pimpl->space_available);
}
LeaveCriticalSection (&pimpl->critsect);
ctx->pipeimpl = pimpl;
if (peerctx)
{
log_debug (" make_pipe (ctx=%i): success: combined with peer ctx=%i "
"(pipe 0x%p)\n", ctx_arg, OPNCTX_TO_IDX (peerctx), pimpl);
}
else
{
log_debug (" make_pipe (ctx=%i): success: combined with "
"pipe 0x%p\n", ctx_arg, OPNCTX_TO_IDX (peerctx), pimpl);
}
return TRUE;
}
/* opnctx_table_s is locked on entering and on exit. */
static BOOL
unblock_call (opnctx_t ctx)
{
/* If there is no pipe object, no thread can be blocked. */
if (!ctx->pipeimpl)
return TRUE;
EnterCriticalSection (&ctx->pipeimpl->critsect);
if (ctx->access_code & GENERIC_READ)
{
ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_READER;
SetEvent (ctx->pipeimpl->data_available);
}
else if (ctx->access_code & GENERIC_WRITE)
{
ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_WRITER;
SetEvent (ctx->pipeimpl->space_available);
}
LeaveCriticalSection (&ctx->pipeimpl->critsect);
return TRUE;
}
-static DWORD CALLBACK
+static DWORD CALLBACK
monitor_main (void *arg)
{
pipeimpl_t pimpl = (pipeimpl_t) arg;
HANDLE handles[2];
int idx;
log_debug ("starting monitor (pimpl=0x%p)\n", pimpl);
-
+
EnterCriticalSection (&pimpl->critsect);
/* Putting proc first in the array is convenient, as this is a hard
break-out condition (and thus takes precedence in WFMO). The
reader/writer event is a soft condition, which also requires a
flag to be set. */
handles[0] = pimpl->monitor_proc;
if (pimpl->monitor_access & GENERIC_READ)
handles[1] = pimpl->data_available;
else
handles[1] = pimpl->space_available;
retry:
/* First check if the peer has not gone away. If it has, we are done. */
if (pimpl->flags & PIPE_FLAG_HALT_MONITOR)
{
log_debug ("monitor (pimpl=0x%p): done: monitored process taking over\n",
pimpl);
- }
+ }
else
{
DWORD res;
LeaveCriticalSection (&pimpl->critsect);
log_debug ("monitor (pimpl=0x%p): waiting\n", pimpl);
res = WaitForMultipleObjects (2, handles, FALSE, INFINITE);
log_debug ("monitor (pimpl=0x%p): resuming\n", pimpl);
EnterCriticalSection (&pimpl->critsect);
if (res == WAIT_FAILED)
{
log_debug ("monitor (pimpl=0x%p): WFMO failed: %i\n",
pimpl, GetLastError ());
}
else if (res == WAIT_OBJECT_0)
{
log_debug ("monitor (pimpl=0x%p): done: monitored process died\n",
pimpl);
- }
+ }
else if (res == WAIT_OBJECT_0 + 1)
goto retry;
else
{
log_debug ("monitor (pimpl=0x%p): unexpected result of WFMO: %i\n",
pimpl, res);
}
}
log_debug ("ending monitor (pimpl=0x%p)\n", pimpl);
/* Remove the monitor from the monitor table. */
LeaveCriticalSection (&pimpl->critsect);
EnterCriticalSection (&opnctx_table_cs);
for (idx = 0; idx < monitor_table_size; idx++)
if (monitor_table[idx].inuse
&& monitor_table[idx].pipeimpl == pimpl)
{
monitor_table[idx].pipeimpl = NULL;
monitor_table[idx].inuse = 0;
break;
}
if (idx == monitor_table_size)
log_debug ("can not find monitor in table (pimpl=0x%p)\n", pimpl);
LeaveCriticalSection (&opnctx_table_cs);
EnterCriticalSection (&pimpl->critsect);
/* Now do the rest of the cleanup. */
CloseHandle (pimpl->monitor_proc);
pimpl->monitor_proc = INVALID_HANDLE_VALUE;
pimpl->monitor_access = 0;
pimpl->monitor_rvid = 0;
pimpl->flags &= ~PIPE_FLAG_HALT_MONITOR;
pipeimpl_unref (pimpl);
return 0;
}
/* opnctx_table_s is locked on entering and on exit. */
static BOOL
assign_rvid (opnctx_t ctx, DWORD rvid, DWORD pid)
{
DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
int idx;
opnctx_t peerctx;
HANDLE monitor_hnd;
HANDLE proc;
pipeimpl_t pimpl;
monitor_t monitor;
log_debug (" assign_rvid (ctx=%i, rvid=%08lx, pid=%08lx)\n",
ctx_arg, rvid, pid);
for (idx = 0; idx < opnctx_table_size; idx++)
if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid)
{
peerctx = &opnctx_table[idx];
break;
}
if (! peerctx)
{
log_debug (" assign_rvid (ctx=%i): error: not found\n", ctx_arg);
SetLastError (ERROR_NOT_FOUND);
return FALSE;
}
-
+
if (peerctx->pipeimpl
&& peerctx->pipeimpl->monitor_proc != INVALID_HANDLE_VALUE)
{
log_debug (" assign_rvid (ctx=%i): error: rvid already assigned\n",
ctx_arg);
SetLastError (ERROR_ALREADY_ASSIGNED);
return FALSE;
}
proc = OpenProcess (0, FALSE, pid);
if (proc == NULL)
{
log_debug (" assign_rvid (ctx=%i): error: process not found\n",
ctx_arg);
return FALSE;
}
/* Acquire a reference to the pipe. We don't want accesss to be
checked. */
pimpl = assert_pipeimpl (peerctx);
if (! pimpl)
{
CloseHandle (proc);
return FALSE;
}
monitor = allocate_monitor ();
if (!monitor)
{
log_debug (" assign_rvid (ctx=%i): error: could not allocate monitor\n",
ctx_arg);
CloseHandle (proc);
return FALSE;
}
monitor->pipeimpl = pimpl;
EnterCriticalSection (&pimpl->critsect);
pimpl->refcnt++;
/* The monitor shadows the peer, so it takes its access. Our access
is the opposite of that of the peer. */
pimpl->monitor_proc = proc;
if (peerctx->access_code == GENERIC_READ)
pimpl->monitor_access = GENERIC_WRITE;
else
pimpl->monitor_access = GENERIC_READ;
pimpl->monitor_rvid = rvid;
monitor_hnd = CreateThread (NULL, 0, monitor_main, pimpl, 0, NULL);
if (monitor_hnd == INVALID_HANDLE_VALUE)
{
pimpl->monitor_access = 0;
pimpl->monitor_proc = INVALID_HANDLE_VALUE;
LeaveCriticalSection (&pimpl->critsect);
monitor->pipeimpl = NULL;
monitor->inuse = 0;
CloseHandle (proc);
log_debug (" assign_rvid (ctx=%i): error: can not create monitor\n",
ctx_arg);
return FALSE;
}
CloseHandle (monitor_hnd);
/* Consume the pimpl reference. */
LeaveCriticalSection (&pimpl->critsect);
return TRUE;
}
BOOL
GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen,
void *outbuf, DWORD outbuflen, DWORD *actualoutlen)
{
opnctx_t opnctx;
BOOL result = FALSE;
LONG rvid;
LONG pid;
log_debug ("GPG_IOControl (ctx=%i, %08x)\n", opnctx_arg, code);
EnterCriticalSection (&opnctx_table_cs);
opnctx = verify_opnctx (opnctx_arg);
if (!opnctx)
{
- log_debug ("GPG_IOControl (ctx=%i): error: could not access context\n",
+ log_debug ("GPG_IOControl (ctx=%i): error: could not access context\n",
opnctx_arg);
goto leave;
}
if (opnctx->is_log)
{
log_debug ("GPG_IOControl (ctx=%i): error: invalid code %u"
" for log device\n", opnctx_arg, (unsigned int)code);
SetLastError (ERROR_INVALID_PARAMETER);
goto leave;
}
switch (code)
{
case GPGCEDEV_IOCTL_GET_RVID:
log_debug ("GPG_IOControl (ctx=%i): code: GET_RVID\n", opnctx_arg);
if (inbuf || inbuflen || !outbuf || outbuflen < sizeof (LONG))
{
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
+ log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
opnctx_arg);
SetLastError (ERROR_INVALID_PARAMETER);
goto leave;
}
- if (! opnctx->rvid)
+ if (! opnctx->rvid)
opnctx->rvid = create_rendezvous_id ();
log_debug ("GPG_IOControl (ctx=%i): returning rvid: %08lx\n",
opnctx_arg, opnctx->rvid);
memcpy (outbuf, &opnctx->rvid, sizeof (LONG));
if (actualoutlen)
*actualoutlen = sizeof (LONG);
result = TRUE;
break;
case GPGCEDEV_IOCTL_MAKE_PIPE:
log_debug ("GPG_IOControl (ctx=%i): code: MAKE_PIPE\n", opnctx_arg);
- if (!inbuf || inbuflen < sizeof (LONG)
+ if (!inbuf || inbuflen < sizeof (LONG)
|| outbuf || outbuflen || actualoutlen)
{
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
+ log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
opnctx_arg);
SetLastError (ERROR_INVALID_PARAMETER);
goto leave;
}
memcpy (&rvid, inbuf, sizeof (LONG));
- log_debug ("GPG_IOControl (ctx=%i): make pipe for rvid: %08lx\n",
+ log_debug ("GPG_IOControl (ctx=%i): make pipe for rvid: %08lx\n",
opnctx_arg, rvid);
if (make_pipe (opnctx, rvid))
result = TRUE;
break;
case GPGCEDEV_IOCTL_UNBLOCK:
log_debug ("GPG_IOControl (ctx=%i): code: UNBLOCK\n", opnctx_arg);
if (inbuf || inbuflen || outbuf || outbuflen || actualoutlen)
{
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
+ log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
opnctx_arg);
SetLastError (ERROR_INVALID_PARAMETER);
goto leave;
}
-
+
if (unblock_call (opnctx))
result = TRUE;
break;
case GPGCEDEV_IOCTL_ASSIGN_RVID:
log_debug ("GPG_IOControl (ctx=%i): code: ASSIGN_RVID\n", opnctx_arg);
if (!inbuf || inbuflen < 2 * sizeof (DWORD)
|| outbuf || outbuflen || actualoutlen)
{
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
+ log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
opnctx_arg);
SetLastError (ERROR_INVALID_PARAMETER);
goto leave;
}
memcpy (&rvid, inbuf, sizeof (DWORD));
memcpy (&pid, ((char *) inbuf) + sizeof (DWORD), sizeof (DWORD));
- log_debug ("GPG_IOControl (ctx=%i): assign rvid %08lx to pid %08lx\n",
+ log_debug ("GPG_IOControl (ctx=%i): assign rvid %08lx to pid %08lx\n",
opnctx_arg, rvid, pid);
if (assign_rvid (opnctx, rvid, pid))
result = TRUE;
break;
case IOCTL_PSL_NOTIFY:
/* This notification is received if the application's main
thread exits and the application has other threads running
and the application has open handles for this device. What
we do is to unblock them all simialr to an explicit unblock
call. */
log_debug ("GPG_IOControl (ctx=%i): code: NOTIFY\n", opnctx_arg);
if (unblock_call (opnctx))
result = TRUE;
break;
default:
log_debug ("GPG_IOControl (ctx=%i): code: (unknown)\n", opnctx_arg);
SetLastError (ERROR_INVALID_PARAMETER);
break;
}
log_debug ("GPG_IOControl (ctx=%i): success: result=%d\n", opnctx_arg,
result);
leave:
LeaveCriticalSection (&opnctx_table_cs);
return result;
}
void
GPG_PowerUp (DWORD devctx)
{
log_debug ("GPG_PowerUp (devctx=%i)\n", devctx);
}
void
GPG_PowerDown (DWORD devctx)
{
log_debug ("GPG_PowerDown (devctx=%i)\n", devctx);
}
/* Entry point called by the DLL loader. */
int WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
(void)reserved;
switch (reason)
{
case DLL_PROCESS_ATTACH:
InitializeCriticalSection (&opnctx_table_cs);
InitializeCriticalSection (&logcontrol.lock);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
DeleteCriticalSection (&opnctx_table_cs);
break;
default:
break;
}
-
+
return TRUE;
}
diff --git a/src/gpgcedev.def b/src/gpgcedev.def
index 387e3a6..bc52d3a 100644
--- a/src/gpgcedev.def
+++ b/src/gpgcedev.def
@@ -1,33 +1,34 @@
; gpgcedev.def - List of symbols to export for gpgcedev.
; Copyright (C) 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 3 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 .
+; SPDX-License-Identifier: LGPL-3.0+
EXPORTS
GPG_Init
GPG_Deinit
GPG_Open
GPG_Close
GPG_Read
GPG_Write
GPG_Seek
GPG_IOControl
GPG_PowerUp
GPG_PowerDown
; END
diff --git a/src/gpgcemgr.c b/src/gpgcemgr.c
index 9dafbc0..5b4f56e 100644
--- a/src/gpgcemgr.c
+++ b/src/gpgcemgr.c
@@ -1,607 +1,608 @@
/* gpgcempr.c - Manager for GPG CE devices
- Copyright (C) 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 3 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 .
+ * Copyright (C) 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 3 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 .
+ * SPDX-License-Identifier: LGPL-3.0+
*/
#define _WIN32_WCE 0x0500
#include
#include
#define PGM "gpgcemgr"
#define GPGCEDEV_KEY_NAME L"Drivers\\GnuPG_Device"
#define GPGCEDEV_KEY_NAME2 L"Drivers\\GnuPG_Log"
#define GPGCEDEV_DLL_NAME L"gpgcedev.dll"
#define GPGCEDEV_PREFIX L"GPG"
static char *
wchar_to_utf8 (const wchar_t *string)
{
int n;
size_t length = wcslen (string);
char *result;
n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
if (n < 0 || (n+1) <= 0)
abort ();
result = malloc (n+1);
if (!result)
abort ();
n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
if (n < 0)
abort ();
-
+
result[n] = 0;
return result;
}
static wchar_t *
utf8_to_wchar (const char *string)
{
int n;
size_t nbytes;
wchar_t *result;
if (!string)
abort ();
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
if (n < 0)
abort ();
nbytes = (size_t)(n+1) * sizeof(*result);
- if (nbytes / sizeof(*result) != (n+1))
+ if (nbytes / sizeof(*result) != (n+1))
abort ();
result = malloc (nbytes);
if (!result)
abort ();
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
if (n < 0)
abort ();
return result;
}
static int
install (void)
{
HKEY handle;
DWORD disp, dw;
int rc;
-
+
if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME, 0, NULL, 0,
KEY_WRITE, NULL, &handle, &disp)))
{
fprintf (stderr, PGM": error creating registry key 1: rc=%d\n", rc);
return 1;
}
- RegSetValueEx (handle, L"dll", 0, REG_SZ,
+ RegSetValueEx (handle, L"dll", 0, REG_SZ,
(void*)GPGCEDEV_DLL_NAME, sizeof (GPGCEDEV_DLL_NAME));
RegSetValueEx (handle, L"prefix", 0, REG_SZ,
(void*)GPGCEDEV_PREFIX, sizeof (GPGCEDEV_PREFIX));
dw = 1;
RegSetValueEx (handle, L"Index", 0, REG_DWORD, (void*)&dw, sizeof dw);
-
+
RegCloseKey (handle);
fprintf (stderr, PGM": registry key 1 created\n");
if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2, 0, NULL, 0,
KEY_WRITE, NULL, &handle, &disp)))
{
fprintf (stderr, PGM": error creating registry key 2: rc=%d\n", rc);
return 1;
}
- RegSetValueEx (handle, L"dll", 0, REG_SZ,
+ RegSetValueEx (handle, L"dll", 0, REG_SZ,
(void*)GPGCEDEV_DLL_NAME, sizeof (GPGCEDEV_DLL_NAME));
RegSetValueEx (handle, L"prefix", 0, REG_SZ,
(void*)GPGCEDEV_PREFIX, sizeof (GPGCEDEV_PREFIX));
dw = 2;
RegSetValueEx (handle, L"Index", 0, REG_DWORD, (void*)&dw, sizeof dw);
-
+
RegCloseKey (handle);
fprintf (stderr, PGM": registry key 2 created\n");
return 0;
}
static int
deinstall (wchar_t *name)
{
int result = 0;
HANDLE shd;
DEVMGR_DEVICE_INFORMATION dinfo;
memset (&dinfo, 0, sizeof dinfo);
dinfo.dwSize = sizeof dinfo;
shd = FindFirstDevice (DeviceSearchByLegacyName, name, &dinfo);
if (shd == INVALID_HANDLE_VALUE)
{
if (GetLastError () == 18)
fprintf (stderr, PGM": device not found\n");
else
{
- fprintf (stderr, PGM": FindFirstDevice failed: rc=%d\n",
+ fprintf (stderr, PGM": FindFirstDevice failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
}
else
{
fprintf (stderr, PGM": ActivateDevice handle is %p\n", dinfo.hDevice);
if (dinfo.hDevice && dinfo.hDevice != INVALID_HANDLE_VALUE)
{
if (!DeactivateDevice (dinfo.hDevice))
{
fprintf (stderr, PGM": DeactivateDevice failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
else
fprintf (stderr, PGM": DeactivateDevice succeeded\n");
}
FindClose (shd);
}
return result;
}
static int
enable_debug (int yes)
{
HKEY handle;
DWORD disp;
int rc;
-
+
if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME, 0, NULL, 0,
KEY_WRITE, NULL, &handle, &disp)))
{
fprintf (stderr, PGM": error creating debug registry key: rc=%d\n", rc);
return 1;
}
-
- RegSetValueEx (handle, L"debugDriver", 0, REG_SZ,
+
+ RegSetValueEx (handle, L"debugDriver", 0, REG_SZ,
(void*)(yes? L"1":L"0"), sizeof L"0");
RegCloseKey (handle);
return 0;
}
static int
enable_log (int yes)
{
HKEY handle;
DWORD disp;
int rc;
-
+
if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2, 0, NULL, 0,
KEY_WRITE, NULL, &handle, &disp)))
{
fprintf (stderr, PGM": error creating debug registry key: rc=%d\n", rc);
return 1;
}
-
- RegSetValueEx (handle, L"enableLog", 0, REG_SZ,
+
+ RegSetValueEx (handle, L"enableLog", 0, REG_SZ,
(void*)(yes? L"1":L"0"), sizeof L"0");
RegCloseKey (handle);
return 0;
}
/* Kudos to Scott Seligman for his work
on the reverse engineering. */
struct htc_sensor_s
{
SHORT tilt_x; // From -1000 to 1000 (about), 0 is flat
SHORT tilt_y; // From -1000 to 1000 (about), 0 is flat
SHORT tilt_z; // From -1000 to 1000 (about)
DWORD angle_x; // 0 .. 359
DWORD angle_y; // From 0 to 359
DWORD orientation; // 0.. 5?
DWORD unknown; // Handle?
};
typedef struct htc_sensor_s *htc_sensor_t;
static HANDLE (WINAPI *HTCSensorOpen) (DWORD);
static void (WINAPI *HTCSensorClose) (HANDLE);
static DWORD (WINAPI *HTCSensorGetDataOutput) (HANDLE, htc_sensor_t);
static int
load_sensor_api (void)
{
static HMODULE dll_hd;
if (dll_hd)
return 0;
dll_hd = LoadLibrary (L"HTCSensorSDK.dll");
if (!dll_hd)
{
fprintf (stderr, PGM": error loading sensor DLL: rc=%d\n",
(int)GetLastError ());
return 1;
}
HTCSensorOpen = (void*)GetProcAddress (dll_hd, L"HTCSensorOpen");
if (HTCSensorOpen)
HTCSensorClose = (void*)GetProcAddress (dll_hd, L"HTCSensorClose");
if (HTCSensorClose)
HTCSensorGetDataOutput = (void*)
GetProcAddress (dll_hd, L"HTCSensorGetDataOutput");
if (!HTCSensorGetDataOutput)
{
fprintf (stderr, PGM": error loading function from sensor DLL: rc=%d\n",
(int)GetLastError ());
CloseHandle (dll_hd);
return 1;
}
return 0;
}
-static int
+static int
gravity (void)
{
int rc;
HANDLE sensor;
struct htc_sensor_s lastdata;
struct htc_sensor_s data;
rc = load_sensor_api ();
if (rc)
return rc;
sensor = HTCSensorOpen (1 /* tilt sensor */);
if (!sensor || sensor == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": error opening gravity sensor: rc=%d\n",
(int)GetLastError ());
HTCSensorClose (sensor);
return 1;
}
memset (&lastdata, 0, sizeof lastdata);
while (HTCSensorGetDataOutput (sensor, &data))
{
if (lastdata.tilt_x/10 != data.tilt_x/10
|| lastdata.tilt_y/10 != data.tilt_y/10
|| lastdata.tilt_z/10 != data.tilt_z/10
|| lastdata.angle_x/5 != data.angle_x/5
|| lastdata.angle_y/5 != data.angle_y/5
|| lastdata.orientation != data.orientation)
{
lastdata = data;
printf ("tilt: x=%-5d y=%-5d z=%-5d "
"angle: x=%-3d y=%-3d "
"ori: %d\n",
(int)data.tilt_x, (int)data.tilt_y, (int)data.tilt_z,
(int)data.angle_x, (int)data.angle_y,
(int)data.orientation);
}
Sleep (200);
}
fprintf (stderr, PGM": reading sensor data failed: rc=%d\n",
(int)GetLastError ());
HTCSensorClose (sensor);
return 0;
}
/* No GPD1 device on the HTC Touch Pro 2. */
# if 0
static int
gps_raw (void)
{
HANDLE hd;
char buffer[1000];
unsigned long nread;
int count;
hd = CreateFile (L"GPD1:", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hd == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": can't open `GPD1': rc=%d\n",
(int)GetLastError ());
return 1;
}
fprintf (stderr, PGM": GPS device successfully opened\n");
for (count=0; count < 100; count++)
{
if (!ReadFile (hd, buffer, sizeof buffer-1, &nread, NULL))
{
fprintf (stderr, PGM": error reading `GPD1': rc=%d\n",
(int)GetLastError ());
CloseHandle (hd);
return 1;
}
buffer[nread-1] = 0;
fputs (buffer, stdout);
}
CloseHandle (hd);
return 0;
}
#endif
/* Untested samples for CE6. */
#if 0
static int
gps (void)
{
HANDLE hd;
GPS_POSITION pos;
hd = GPSOpenDevice (NULL, NULL, NULL, 0);
if (hd == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": GPSOpenDevice failed: rc=%d\n",
(int)GetLastError ());
return 1;
}
fprintf (stderr, PGM": GPS device successfully opened\n");
if (GPSGetPosition (hd, &pos, 2000, 0))
{
fprintf (stderr, PGM": GPSGetPosition failed: rc=%d\n",
(int)GetLastError ());
GPSCloseDevice (hd);
return 1;
}
GPSCloseDevice (hd);
return 0;
}
#endif
static void
set_show_registry (const wchar_t *key, const wchar_t *name, const char *value)
{
HKEY handle;
DWORD disp, nbytes, n1, type;
int rc;
-
+
if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, key, 0, NULL, 0,
KEY_WRITE, NULL, &handle, &disp)))
{
fprintf (stderr, PGM": error creating registry key: rc=%d\n", rc);
return;
}
if (value && !stricmp (value, "none"))
{
if ((rc=RegDeleteValue (handle, name)))
fprintf (stderr, PGM": error deleting registry value: rc=%d\n", rc);
}
else if (value)
{
wchar_t *tmp = utf8_to_wchar (value);
- if ((rc=RegSetValueEx (handle, name, 0, REG_SZ,
+ if ((rc=RegSetValueEx (handle, name, 0, REG_SZ,
(void*)tmp, wcslen (tmp)*sizeof(wchar_t))))
fprintf (stderr, PGM": error setting registry value: rc=%d\n", rc);
free (tmp);
}
else
{
nbytes = 2;
if ((rc=RegQueryValueEx (handle, name, 0, NULL, NULL, &nbytes)))
{
if (rc == ERROR_FILE_NOT_FOUND)
- fprintf (stderr, PGM": registry value not set\n");
+ fprintf (stderr, PGM": registry value not set\n");
else
- fprintf (stderr, PGM": error reading registry value: rc=%d\n", rc);
+ fprintf (stderr, PGM": error reading registry value: rc=%d\n", rc);
}
else
{
char *result = malloc ((n1=nbytes+2));
if (!result)
- fprintf (stderr, PGM": malloc failed: rc=%d\n",
+ fprintf (stderr, PGM": malloc failed: rc=%d\n",
(int)GetLastError ());
else if ((rc=RegQueryValueEx (handle, name, 0, &type,
(void*)result, &n1)))
{
fprintf (stderr, PGM": error reading registry value (2): "
"rc=%d\n", rc);
free (result);
}
else
{
result[nbytes] = 0; /* Make sure it is a string. */
- result[nbytes+1] = 0;
+ result[nbytes+1] = 0;
if (type == REG_SZ)
{
wchar_t *tmp = (void*)result;
result = wchar_to_utf8 (tmp);
free (tmp);
printf ("%s\n", result);
}
else
fprintf (stderr, PGM": registry value is not a string\n");
free (result);
}
}
}
-
+
RegCloseKey (handle);
}
int
main (int argc, char **argv)
{
int result = 0;
if (argc > 1 && !strcmp (argv[1], "--register"))
result = install ();
else if (argc > 1 && !strcmp (argv[1], "--deactivate"))
{
if (deinstall (L"GPG1:"))
result = 1;
if (deinstall (L"GPG2:"))
result = 1;
}
else if (argc > 1 && !strcmp (argv[1], "--activate"))
{
HANDLE hd;
/* This is mainly for testing. The activation is usually done
right before the device is opened. */
if (ActivateDevice (GPGCEDEV_KEY_NAME, 0) == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": ActivateDevice 1 failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
else if (ActivateDevice (GPGCEDEV_KEY_NAME2, 0) == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": ActivateDevice 2 failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
else
{
fprintf (stderr, PGM": devices activated\n");
hd = CreateFile (L"GPG1:", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hd == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": opening `GPG1:' failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
else
{
fprintf (stderr, PGM": device `GPG1:' seems to work\n");
CloseHandle (hd);
}
hd = CreateFile (L"GPG2:", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hd == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": opening `GPG2:' failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
else
{
fprintf (stderr, PGM": device `GPG2:' seems to work\n");
CloseHandle (hd);
}
-
+
}
}
else if (argc > 1 && !strcmp (argv[1], "--gravity"))
result = gravity ();
/* else if (argc > 1 && !strcmp (argv[1], "--gps")) */
/* result = gps (); */
else if (argc > 1 && !strcmp (argv[1], "--log"))
{
HANDLE hd;
hd = CreateFile (L"GPG2:", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hd == INVALID_HANDLE_VALUE)
{
fprintf (stderr, PGM": opening `GPG2:' failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
else
{
char marktwain[] = "I have never let my schooling interfere"
" with my education.\n";
DWORD nwritten;
int i;
- for (i=0; i < 3; i++)
+ for (i=0; i < 3; i++)
{
if (!WriteFile (hd, marktwain, strlen (marktwain),
&nwritten, NULL))
{
fprintf (stderr, PGM": writing `GPG2:' failed: rc=%d\n",
(int)GetLastError ());
result = 1;
}
Sleep (200);
}
CloseHandle (hd);
}
}
else if (argc > 1 && !strcmp (argv[1], "--enable-debug"))
result = enable_debug (1);
else if (argc > 1 && !strcmp (argv[1], "--disable-debug"))
result = enable_debug (0);
else if (argc > 1 && !strcmp (argv[1], "--enable-log"))
result = enable_log (1);
else if (argc > 1 && !strcmp (argv[1], "--disable-log"))
result = enable_log (0);
else if (argc > 1 && !strcmp (argv[1], "--gpgme-log"))
- set_show_registry (L"Software\\GNU\\gpgme", L"debug",
- argc > 2? argv[2] : NULL);
+ set_show_registry (L"Software\\GNU\\gpgme", L"debug",
+ argc > 2? argv[2] : NULL);
else if (argc > 1 && !strcmp (argv[1], "--gnupg-log"))
- set_show_registry (L"Software\\GNU\\GnuPG", L"DefaultLogFile",
+ set_show_registry (L"Software\\GNU\\GnuPG", L"DefaultLogFile",
argc > 2? argv[2] : NULL);
else
{
fprintf (stderr,
"usage: " PGM " COMMAND\n"
"Commands are:\n"
" --register Register the GPGCEDEV device\n"
" --deactivate Deactivate the GPGCEDEV device\n"
" --activate Activate the GPGCEDEV devive\n"
" --enable-debug Enable debugging of GPGCEDEV device\n"
" --disable-debug Disable debugging of GPGCEDEV device\n"
" --gravity Show output of the gravity sensor\n"
" --enable-log Enable logging via \"GPG2:\"\n"
" --disable-log Disable logging via \"GPG2:\"\n"
" --log Write a test string to \"GPG2:\"\n"
" --gpgme-log [ARG] Show or set GPGME log output\n"
" --gnupg-log [ARG] Show or set GnuPG default log file\n"
" (No ARG shows, \"none\" disables)\n"
);
result = 1;
}
fflush (stdout);
fflush (stderr);
Sleep (1000);
return result;
}
diff --git a/src/isascii.c b/src/isascii.c
index 77ed970..3160390 100644
--- a/src/isascii.c
+++ b/src/isascii.c
@@ -1,28 +1,29 @@
/* isascii.c - Replacement for isascii.
* Copyright (C) 2002, 2005 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
int
isascii (int c)
{
return (((c) & ~0x7f) == 0);
}
diff --git a/src/libassuan-config.in b/src/libassuan-config.in
index dd25a4c..04177f0 100644
--- a/src/libassuan-config.in
+++ b/src/libassuan-config.in
@@ -1,133 +1,134 @@
#!/bin/sh
# Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# SPDX-License-Identifier: FSFULLR
# Configure libgpg-error.
gpg_error_cflags="@GPG_ERROR_CFLAGS@"
gpg_error_libs="@GPG_ERROR_LIBS@"
PGM=libassuan-config
lib="@LIBASSUAN_CONFIG_LIB@"
extralibs="@LIBASSUAN_CONFIG_EXTRA_LIBS@ $gpg_error_libs"
cflags="@LIBASSUAN_CONFIG_CFLAGS@ $gpg_error_cflags"
api_version="@LIBASSUAN_CONFIG_API_VERSION@"
my_host="@LIBASSUAN_CONFIG_HOST@"
prefix=@prefix@
exec_prefix=@exec_prefix@
includes=""
libdirs=""
exec_prefix_set=no
echo_libs=no
echo_cflags=no
echo_prefix=no
echo_exec_prefix=no
echo_host=no
usage()
{
cat <&2
fi
while test $# -gt 0; do
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case $1 in
--prefix=*)
# Dummy
;;
--prefix)
echo_prefix=yes
;;
--exec-prefix=*)
# Dummy
;;
--exec-prefix)
echo_exec_prefix=yes
;;
--version)
echo "@VERSION@"
exit 0
;;
--api-version)
echo_api_version=yes
;;
--cflags)
echo_cflags=yes
;;
--libs)
echo_libs=yes
;;
--host)
echo_host=yes
;;
*)
usage 1 1>&2
;;
esac
shift
done
if test "$echo_prefix" = "yes"; then
echo $prefix
fi
if test "$echo_exec_prefix" = "yes"; then
echo $exec_prefix
fi
if test "$echo_api_version" = "yes"; then
echo $api_version
fi
if test "$echo_host" = "yes"; then
echo "$my_host"
fi
if test "$echo_cflags" = "yes"; then
if test "@includedir@" != "/usr/include" ; then
includes="-I@includedir@"
for i in $cflags ; do
if test "$i" = "-I@includedir@" ; then
includes=""
fi
done
fi
echo $includes $cflags
fi
if test "$echo_libs" = "yes"; then
if test "@libdir@" != "/usr/lib" ; then
libdirs="-L@libdir@"
for i in $lib $extralibs ; do
if test "$i" = "-L@libdir@" ; then
libdirs=""
fi
done
fi
echo $libdirs $lib $extralibs
fi
diff --git a/src/libassuan.def b/src/libassuan.def
index c320151..7e32a3d 100644
--- a/src/libassuan.def
+++ b/src/libassuan.def
@@ -1,120 +1,120 @@
; assuan.def - List of symbols to export.
; Copyright (C) 2005, 2009 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, write to the Free Software
-; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+; License along with this program; if not, see .
+; SPDX-License-Identifier: LGPL-2.1+
EXPORTS
assuan_accept @1
assuan_begin_confidential @2
assuan_close_input_fd @3
assuan_close_output_fd @4
assuan_command_parse_fd @5
assuan_ctx_set_system_hooks @6
assuan_end_confidential @7
assuan_get_active_fds @8
assuan_get_assuan_log_prefix @9
assuan_get_command_name @10
assuan_get_data_fp @11
assuan_get_flag @12
assuan_get_gpg_err_source @13
assuan_get_input_fd @14
assuan_get_log_cb @15
assuan_get_malloc_hooks @16
assuan_get_output_fd @17
assuan_get_peercred @18
assuan_get_pid @19
assuan_get_pointer @20
assuan_init_pipe_server @21
assuan_init_socket_server @22
assuan_inquire @23
assuan_inquire_ext @24
assuan_new @25
assuan_new_ext @26
assuan_pending_line @27
assuan_pipe_connect @28
assuan_process @29
assuan_process_done @30
assuan_process_next @31
assuan_read_line @32
assuan_receivefd @33
assuan_register_bye_notify @34
assuan_register_cancel_notify @35
assuan_register_command @36
assuan_register_input_notify @37
assuan_register_option_handler @38
assuan_register_output_notify @39
assuan_register_post_cmd_notify @40
assuan_register_reset_notify @41
assuan_release @42
assuan_send_data @43
assuan_sendfd @44
assuan_set_assuan_log_prefix @45
assuan_set_assuan_log_stream @46
assuan_set_error @47
assuan_set_flag @48
assuan_set_gpg_err_source @49
assuan_set_hello_line @50
assuan_set_io_monitor @51
assuan_set_log_cb @52
assuan_set_log_stream @53
assuan_set_malloc_hooks @54
assuan_set_okay_line @55
assuan_set_pointer @56
assuan_set_system_hooks @57
assuan_sock_bind @58
assuan_sock_check_nonce @59
assuan_sock_close @60
assuan_sock_connect @61
assuan_sock_deinit @62
assuan_sock_get_nonce @63
assuan_sock_init @64
assuan_sock_new @65
assuan_socket_connect @66
assuan_transact @67
assuan_write_line @68
assuan_write_status @69
__assuan_close @70
__assuan_pipe @71
__assuan_socketpair @72
__assuan_spawn @73
__assuan_usleep @74
assuan_fdopen @75
assuan_client_read_response @76
assuan_client_parse_response @77
assuan_set_sock_nonce @78
_assuan_w32ce_create_pipe @79
assuan_free @80
_assuan_w32ce_prepare_pipe @81
_assuan_w32ce_finish_pipe @82
__assuan_socket @83
__assuan_connect @84
assuan_register_pre_cmd_notify @85
assuan_socket_connect_fd @86
__assuan_read @87
__assuan_write @88
__assuan_recvmsg @89
__assuan_sendmsg @90
__assuan_waitpid @91
assuan_check_version @92
assuan_sock_set_sockaddr_un @93
assuan_sock_set_flag @94
assuan_sock_get_flag @95
assuan_sock_connect_byname @96
; END
diff --git a/src/libassuan.m4 b/src/libassuan.m4
index 4b196a5..fe45b06 100644
--- a/src/libassuan.m4
+++ b/src/libassuan.m4
@@ -1,150 +1,151 @@
dnl Autoconf macros for libassuan
dnl Copyright (C) 2002, 2003, 2011 Free Software Foundation, Inc.
dnl
dnl This file is free software; as a special exception the author gives
dnl unlimited permission to copy and/or distribute it, with or without
dnl modifications, as long as this notice is preserved.
dnl
dnl This file is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+dnl SPDX-License-Identifier: FSFULLR
dnl
dnl Common code used for libassuan detection [internal]
dnl Returns ok set to yes or no.
dnl
AC_DEFUN([_AM_PATH_LIBASSUAN_COMMON],
[ AC_REQUIRE([AC_CANONICAL_HOST])
AC_ARG_WITH(libassuan-prefix,
AC_HELP_STRING([--with-libassuan-prefix=PFX],
[prefix where LIBASSUAN is installed (optional)]),
libassuan_config_prefix="$withval", libassuan_config_prefix="")
if test x$libassuan_config_prefix != x ; then
libassuan_config_args="$libassuan_config_args --prefix=$libassuan_config_prefix"
if test x${LIBASSUAN_CONFIG+set} != xset ; then
LIBASSUAN_CONFIG=$libassuan_config_prefix/bin/libassuan-config
fi
fi
AC_PATH_TOOL(LIBASSUAN_CONFIG, libassuan-config, no)
tmp=ifelse([$1], ,1:0.9.2,$1)
if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
req_libassuan_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
min_libassuan_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
else
req_libassuan_api=0
min_libassuan_version="$tmp"
fi
AC_MSG_CHECKING(for LIBASSUAN - version >= $min_libassuan_version)
ok=no
if test "$LIBASSUAN_CONFIG" != "no" \
&& test -f "$LIBASSUAN_CONFIG" ; then
req_major=`echo $min_libassuan_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
req_minor=`echo $min_libassuan_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
req_micro=`echo $min_libassuan_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
libassuan_config_version=`$LIBASSUAN_CONFIG --version`
major=`echo $libassuan_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
minor=`echo $libassuan_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
micro=`echo $libassuan_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
if test "$major" -gt "$req_major"; then
ok=yes
- else
+ else
if test "$major" -eq "$req_major"; then
if test "$minor" -gt "$req_minor"; then
ok=yes
else
if test "$minor" -eq "$req_minor"; then
if test "$micro" -ge "$req_micro"; then
ok=yes
fi
fi
fi
fi
fi
fi
if test $ok = yes; then
AC_MSG_RESULT([yes ($libassuan_config_version)])
else
AC_MSG_RESULT(no)
fi
if test $ok = yes; then
if test "$req_libassuan_api" -gt 0 ; then
tmp=`$LIBASSUAN_CONFIG --api-version 2>/dev/null || echo 0`
if test "$tmp" -gt 0 ; then
AC_MSG_CHECKING([LIBASSUAN API version])
if test "$req_libassuan_api" -eq "$tmp" ; then
AC_MSG_RESULT(okay)
else
ok=no
AC_MSG_RESULT([does not match. want=$req_libassuan_api got=$tmp.])
fi
fi
fi
fi
if test $ok = yes; then
if test x"$host" != x ; then
libassuan_config_host=`$LIBASSUAN_CONFIG --host 2>/dev/null || echo none`
if test x"$libassuan_config_host" != xnone ; then
if test x"$libassuan_config_host" != x"$host" ; then
AC_MSG_WARN([[
***
*** The config script $LIBASSUAN_CONFIG was
*** built for $libassuan_config_host and thus may not match the
*** used host $host.
*** You may want to use the configure option --with-libassuan-prefix
*** to specify a matching config script.
***]])
fi
fi
fi
fi
])
dnl AM_CHECK_LIBASSUAN([MINIMUM-VERSION,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
dnl Test whether libassuan has at least MINIMUM-VERSION. This is
dnl used to test for features only available in newer versions.
dnl
AC_DEFUN([AM_CHECK_LIBASSUAN],
[ _AM_PATH_LIBASSUAN_COMMON($1)
if test $ok = yes; then
ifelse([$2], , :, [$2])
else
ifelse([$3], , :, [$3])
fi
])
dnl AM_PATH_LIBASSUAN([MINIMUM-VERSION,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
dnl Test for libassuan and define LIBASSUAN_CFLAGS and LIBASSUAN_LIBS
dnl
AC_DEFUN([AM_PATH_LIBASSUAN],
[ _AM_PATH_LIBASSUAN_COMMON($1)
if test $ok = yes; then
LIBASSUAN_CFLAGS=`$LIBASSUAN_CONFIG $libassuan_config_args --cflags`
LIBASSUAN_LIBS=`$LIBASSUAN_CONFIG $libassuan_config_args --libs`
ifelse([$2], , :, [$2])
else
LIBASSUAN_CFLAGS=""
LIBASSUAN_LIBS=""
ifelse([$3], , :, [$3])
fi
AC_SUBST(LIBASSUAN_CFLAGS)
AC_SUBST(LIBASSUAN_LIBS)
])
diff --git a/src/libassuan.vers b/src/libassuan.vers
index 37c0131..a178127 100644
--- a/src/libassuan.vers
+++ b/src/libassuan.vers
@@ -1,125 +1,126 @@
# libassuan.vers - List of symbols to export.
# Copyright (C) 2009 g10 Code GmbH
#
# This file is part of LIBASSUAN.
#
# LIBASSUAN 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.
#
# LIBASSUAN 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 .
+# SPDX-License-Identifier: LGPL-2.1+
#-----------------------------------------------------------
# Please remember to add new functions also to libassuan.def
#-----------------------------------------------------------
LIBASSUAN_1.0 {
global:
assuan_accept;
assuan_begin_confidential;
assuan_client_read_response;
assuan_client_parse_response;
assuan_close_input_fd;
assuan_close_output_fd;
assuan_command_parse_fd;
assuan_ctx_set_system_hooks;
assuan_end_confidential;
assuan_fdopen;
assuan_get_active_fds;
assuan_get_assuan_log_prefix;
assuan_get_command_name;
assuan_get_data_fp;
assuan_get_flag;
assuan_get_gpg_err_source;
assuan_get_input_fd;
assuan_get_log_cb;
assuan_get_malloc_hooks;
assuan_get_output_fd;
assuan_get_peercred;
assuan_get_pid;
assuan_get_pointer;
assuan_init_pipe_server;
assuan_init_socket_server;
assuan_inquire;
assuan_inquire_ext;
assuan_new;
assuan_new;
assuan_new_ext;
assuan_pending_line;
assuan_pipe_connect;
assuan_process;
assuan_process_done;
assuan_process_next;
assuan_read_line;
assuan_receivefd;
assuan_register_bye_notify;
assuan_register_cancel_notify;
assuan_register_command;
assuan_register_input_notify;
assuan_register_option_handler;
assuan_register_output_notify;
assuan_register_pre_cmd_notify;
assuan_register_post_cmd_notify;
assuan_register_reset_notify;
assuan_release;
assuan_release;
assuan_send_data;
assuan_sendfd;
assuan_set_assuan_log_prefix;
assuan_set_assuan_log_stream;
assuan_set_error;
assuan_set_flag;
assuan_set_gpg_err_source;
assuan_set_hello_line;
assuan_set_io_monitor;
assuan_set_log_cb;
assuan_set_log_stream;
assuan_set_malloc_hooks;
assuan_set_okay_line;
assuan_set_pointer;
assuan_set_sock_nonce;
assuan_set_system_hooks;
assuan_sock_bind;
assuan_sock_check_nonce;
assuan_sock_close;
assuan_sock_connect;
assuan_sock_deinit;
assuan_sock_get_nonce;
assuan_sock_init;
assuan_sock_new;
assuan_socket_connect;
assuan_transact;
assuan_write_line;
assuan_write_status;
assuan_free;
assuan_socket_connect_fd;
assuan_check_version;
assuan_sock_set_sockaddr_un;
assuan_sock_set_flag;
assuan_sock_get_flag;
assuan_sock_connect_byname;
__assuan_close;
__assuan_pipe;
__assuan_socketpair;
__assuan_spawn;
__assuan_usleep;
__assuan_socket;
__assuan_connect;
__assuan_read;
__assuan_write;
__assuan_recvmsg;
__assuan_sendmsg;
__assuan_waitpid;
local:
*;
};
diff --git a/src/memrchr.c b/src/memrchr.c
index 258216c..adb68d7 100644
--- a/src/memrchr.c
+++ b/src/memrchr.c
@@ -1,39 +1,40 @@
/* memrchr.c - Replacement for memrchr.
* Copyright (C) 2002, 2004, 2005 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
void *
memrchr (const void *block, int c, size_t size)
{
const unsigned char *p = block;
if (size)
{
for (p += size - 1; size; p--, size--)
if (*p == c)
return (void *)p;
}
return NULL;
}
diff --git a/src/mkheader.c b/src/mkheader.c
index 44eb78e..0ee0944 100644
--- a/src/mkheader.c
+++ b/src/mkheader.c
@@ -1,269 +1,270 @@
/* mkheader.c - Create a header file for libassuan.
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * SPDX-License-Identifier: FSFULLR
*/
#include
#include
#include
#include
#define PGM "mkheader"
#define LINESIZE 1024
static const char *host_os;
static char *srcdir;
static const char *hdr_version;
static const char *hdr_version_number;
/* Include the file NAME form the source directory. The included file
is not further expanded. It may have comments indicated by a
double hash mark at the begin of a line. */
static void
include_file (const char *fname, int lnr, const char *name)
{
FILE *fp;
char *incfname;
char line[LINESIZE];
incfname = malloc (strlen (srcdir) + strlen (name) + 1);
if (!incfname)
{
fputs (PGM ": out of core\n", stderr);
exit (1);
}
strcpy (incfname, srcdir);
strcat (incfname, name);
fp = fopen (incfname, "r");
if (!fp)
{
fprintf (stderr, "%s:%d: error including `%s': %s\n",
fname, lnr, incfname, strerror (errno));
exit (1);
}
while (fgets (line, LINESIZE, fp))
{
if (line[0] == '#' && line[1] == '#')
{
if (!strncmp (line+2, "EOF##", 5))
break; /* Forced EOF. */
}
else
fputs (line, stdout);
}
if (ferror (fp))
{
fprintf (stderr, "%s:%d: error reading `%s': %s\n",
fname, lnr, incfname, strerror (errno));
exit (1);
}
fclose (fp);
free (incfname);
}
static int
write_special (const char *fname, int lnr, const char *tag)
{
if (!strcmp (tag, "include:includes"))
{
if (strstr (host_os, "mingw32"))
include_file (fname, lnr, "w32-includes.inc.h");
else
include_file (fname, lnr, "posix-includes.inc.h");
}
else if (!strcmp (tag, "include:sys/types.h"))
{
if (!strcmp (host_os, "mingw32ce"))
fputs ("#ifdef __MINGW32CE__\n"
"# include \n"
"#endif\n", stdout);
else
fputs ("#include \n", stdout);
}
else if (!strcmp (tag, "include:unistd.h"))
{
if (!strcmp (host_os, "mingw32ce"))
fputs ("#ifdef __MINGW32CE__\n"
"# include \n"
"#endif\n", stdout);
else
fputs ("#include \n", stdout);
}
else if (!strcmp (tag, "include:types"))
{
if (strstr (host_os, "mingw32"))
include_file (fname, lnr, "w32-types.inc.h");
else
include_file (fname, lnr, "posix-types.inc.h");
}
else if (!strcmp (tag, "include:fd-t"))
{
if (!strcmp (host_os, "mingw32ce"))
include_file (fname, lnr, "w32ce-fd-t.inc.h");
else if (strstr (host_os, "mingw32"))
include_file (fname, lnr, "w32-fd-t.inc.h");
else
include_file (fname, lnr, "posix-fd-t.inc.h");
}
else if (!strcmp (tag, "include:sock-nonce"))
{
if (strstr (host_os, "mingw32"))
include_file (fname, lnr, "w32-sock-nonce.inc.h");
else
include_file (fname, lnr, "posix-sock-nonce.inc.h");
}
else if (!strcmp (tag, "include:sys-pth-impl"))
{
if (strstr (host_os, "mingw32"))
include_file (fname, lnr, "w32-sys-pth-impl.h");
else
include_file (fname, lnr, "posix-sys-pth-impl.h");
}
else if (!strcmp (tag, "include:w32ce-add"))
{
if (!strcmp (host_os, "mingw32ce"))
include_file (fname, lnr, "w32ce-add.h");
}
else if (!strcmp (tag, "version"))
{
putchar ('\"');
fputs (hdr_version, stdout);
putchar ('\"');
putchar ('\n');
}
else if (!strcmp (tag, "version-number"))
{
fputs (hdr_version_number, stdout);
putchar ('\n');
}
else
return 0; /* Unknown tag. */
return 1; /* Tag processed. */
}
int
main (int argc, char **argv)
{
FILE *fp;
char line[LINESIZE];
int lnr = 0;
const char *fname, *s;
char *p1, *p2;
if (argc)
{
argc--; argv++;
}
if (argc != 4)
{
fputs ("usage: " PGM " host_os template.h version version_number\n",
stderr);
return 1;
}
host_os = argv[0];
fname = argv[1];
hdr_version = argv[2];
hdr_version_number = argv[3];
srcdir = malloc (strlen (fname) + 2 + 1);
if (!srcdir)
{
fputs (PGM ": out of core\n", stderr);
return 1;
}
strcpy (srcdir, fname);
p1 = strrchr (srcdir, '/');
if (p1)
p1[1] = 0;
else
strcpy (srcdir, "./");
fp = fopen (fname, "r");
if (!fp)
{
fprintf (stderr, "%s:%d: can't open file: %s",
fname, lnr, strerror (errno));
return 1;
}
while (fgets (line, LINESIZE, fp))
{
size_t n = strlen (line);
lnr++;
if (!n || line[n-1] != '\n')
{
fprintf (stderr,
"%s:%d: trailing linefeed missing, line too long or "
"embedded Nul character", fname, lnr);
break;
}
line[--n] = 0;
p1 = strchr (line, '@');
p2 = p1? strchr (p1+1, '@') : NULL;
if (!p1 || !p2 || p2-p1 == 1)
{
puts (line);
continue;
}
*p1++ = 0;
*p2++ = 0;
fputs (line, stdout);
if (!strcmp (p1, "configure_input"))
{
s = strrchr (fname, '/');
printf ("Do not edit. Generated from %s by %s for %s.",
s? s+1 : fname, PGM, host_os);
fputs (p2, stdout);
putchar ('\n');
}
else if (!write_special (fname, lnr, p1))
{
putchar ('@');
fputs (p1, stdout);
putchar ('@');
fputs (p2, stdout);
putchar ('\n');
}
}
if (ferror (fp))
{
fprintf (stderr, "%s:%d: error reading file: %s\n",
fname, lnr, strerror (errno));
return 1;
}
fputs ("/*\n"
"Loc" "al Variables:\n"
"buffer-read-only: t\n"
"End:\n"
"*/\n", stdout);
if (ferror (stdout))
{
fprintf (stderr, PGM ": error writing stdout: %s\n", strerror (errno));
return 1;
}
fclose (fp);
return 0;
}
diff --git a/src/posix-fd-t.inc.h b/src/posix-fd-t.inc.h
index 80aa5f0..832c4fa 100644
--- a/src/posix-fd-t.inc.h
+++ b/src/posix-fd-t.inc.h
@@ -1,32 +1,33 @@
## posix-fd-t.inc.h - Include fragment to build assuan.h.
## Copyright (C) 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 .
+## SPDX-License-Identifier: LGPL-2.1+
##
##
## This file is included by the mkheader tool. Lines starting with
## a double hash mark are not copied to the destination file.
typedef int assuan_fd_t;
#define ASSUAN_INVALID_FD (-1)
#define ASSUAN_INVALID_PID ((pid_t) -1)
static GPG_ERR_INLINE assuan_fd_t
assuan_fd_from_posix_fd (int fd)
{
return fd;
}
##EOF##
diff --git a/src/posix-includes.inc.h b/src/posix-includes.inc.h
index c641f86..d95a403 100644
--- a/src/posix-includes.inc.h
+++ b/src/posix-includes.inc.h
@@ -1,23 +1,24 @@
## posix-includes.inc.h - Include fragment to build assuan.h.
## Copyright (C) 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 .
+## SPDX-License-Identifier: LGPL-2.1+
##
##
## This file is included by the mkheader tool. Lines starting with
## a double hash mark are not copied to the destination file.
#include
##EOF##
diff --git a/src/posix-sock-nonce.inc.h b/src/posix-sock-nonce.inc.h
index a62216d..edd5a57 100644
--- a/src/posix-sock-nonce.inc.h
+++ b/src/posix-sock-nonce.inc.h
@@ -1,32 +1,33 @@
## posix-sock-nonce.inc.h - Include fragment to build assuan.h.
## Copyright (C) 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 .
+## SPDX-License-Identifier: LGPL-2.1+
##
##
## This file is included by the mkheader tool. Lines starting with
## a double hash mark are not copied to the destination file.
/* Under Windows Assuan features an emulation of Unix domain sockets
based on a local TCP connections. To implement access permissions
based on file permissions a nonce is used which is expected by the
server as the first bytes received. On POSIX systems this is a
- dummy structure. */
+ dummy structure. */
struct assuan_sock_nonce_s
{
size_t length;
};
typedef struct assuan_sock_nonce_s assuan_sock_nonce_t;
##EOF##
diff --git a/src/posix-sys-pth-impl.h b/src/posix-sys-pth-impl.h
index 77d38f0..6943359 100644
--- a/src/posix-sys-pth-impl.h
+++ b/src/posix-sys-pth-impl.h
@@ -1,88 +1,87 @@
## posix-sys-pth-impl.h - Include fragment to build assuan.h.
## Copyright (C) 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 .
+## SPDX-License-Identifier: LGPL-2.1+
##
##
## This file is included by the mkheader tool. Lines starting with
## a double hash mark are not copied to the destination file.
##
## Warning: This is a fragment of a macro - no empty lines please.
static int _assuan_pth_recvmsg (assuan_context_t ctx, assuan_fd_t fd, \
assuan_msghdr_t msg, int flags) \
{ \
/* Pth does not provide a recvmsg function. We implement it. */ \
int ret; \
int fdmode; \
\
(void) ctx; \
fdmode = pth_fdmode (fd, PTH_FDMODE_POLL); \
if (fdmode == PTH_FDMODE_ERROR) \
{ \
errno = EBADF; \
return -1; \
} \
if (fdmode == PTH_FDMODE_BLOCK) \
{ \
fd_set fds; \
\
FD_ZERO (&fds); \
FD_SET (fd, &fds); \
while ((ret = pth_select (fd + 1, &fds, NULL, NULL, NULL)) < 0 \
&& errno == EINTR) \
; \
if (ret < 0) \
return -1; \
} \
\
while ((ret = recvmsg (fd, msg, flags)) == -1 && errno == EINTR) \
; \
return ret; \
} \
static int _assuan_pth_sendmsg (assuan_context_t ctx, assuan_fd_t fd, \
const assuan_msghdr_t msg, int flags) \
{ \
/* Pth does not provide a sendmsg function. We implement it. */ \
int ret; \
int fdmode; \
\
(void) ctx; \
fdmode = pth_fdmode (fd, PTH_FDMODE_POLL); \
if (fdmode == PTH_FDMODE_ERROR) \
{ \
errno = EBADF; \
return -1; \
} \
if (fdmode == PTH_FDMODE_BLOCK) \
{ \
fd_set fds; \
\
FD_ZERO (&fds); \
FD_SET (fd, &fds); \
while ((ret = pth_select (fd + 1, NULL, &fds, NULL, NULL)) < 0 \
&& errno == EINTR) \
; \
if (ret < 0) \
return -1; \
} \
\
while ((ret = sendmsg (fd, msg, flags)) == -1 && errno == EINTR) \
; \
return ret; \
} \
##EOF## Force end-of file.
-
-
diff --git a/src/posix-types.inc.h b/src/posix-types.inc.h
index c242b48..e3810b3 100644
--- a/src/posix-types.inc.h
+++ b/src/posix-types.inc.h
@@ -1,23 +1,24 @@
## posix-types.inc.h - Include fragment to build assuan.h.
## Copyright (C) 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 .
+## SPDX-License-Identifier: LGPL-2.1+
##
##
## This file is included by the mkheader tool. Lines starting with
## a double hash mark are not copied to the destination file.
typedef struct msghdr *assuan_msghdr_t;
##EOF##
diff --git a/src/putc_unlocked.c b/src/putc_unlocked.c
index 80b3aa1..6adcaec 100644
--- a/src/putc_unlocked.c
+++ b/src/putc_unlocked.c
@@ -1,30 +1,31 @@
/* putc_unlocked.c - Replacement for putc_unlocked.
* Copyright (C) 2002, 2005 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
int
putc_unlocked (int c, FILE *stream)
{
return putc (c, stream);
}
diff --git a/src/server.c b/src/server.c
index 6cc75ae..7c82f02 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1,69 +1,70 @@
/* server.c - Interfaces for all assuan servers.
- 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include "assuan-defs.h"
#include "debug.h"
/* Disconnect and release the context CTX. */
void
_assuan_server_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->pid != ASSUAN_INVALID_PID && ctx->pid)
{
_assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
ctx->pid = ASSUAN_INVALID_PID;
}
_assuan_uds_deinit (ctx);
_assuan_inquire_release (ctx);
}
void
_assuan_server_release (assuan_context_t ctx)
{
_assuan_server_finish (ctx);
_assuan_free (ctx, ctx->hello_line);
ctx->hello_line = NULL;
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = NULL;
_assuan_free (ctx, ctx->cmdtbl);
ctx->cmdtbl = NULL;
}
diff --git a/src/setenv.c b/src/setenv.c
index 9f91124..3410b30 100644
--- a/src/setenv.c
+++ b/src/setenv.c
@@ -1,357 +1,358 @@
/* Copyright (C) 1992,1995-2001,2004 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library 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.
-
- The GNU C Library 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 the GNU C Library; if not,
- see .
+ * This file is part of the GNU C Library.
+ *
+ * The GNU C Library 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.
+ *
+ * The GNU C Library 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 the GNU C Library; if not,
+ * see .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#if HAVE_CONFIG_H
# include
#endif
#ifndef HAVE_W32CE_SYSTEM
#define setenv _assuan_setenv
#define unsetenv _assuan_unsetenv
#define clearenv _assuan_clearenv
#define __builtin_expect(cond,val) (cond)
#include
#if !_LIBC
# if !defined errno && !defined HAVE_ERRNO_DECL
extern int errno;
# endif
# define __set_errno(ev) ((errno) = (ev))
#endif
#if _LIBC || HAVE_STDLIB_H
# include
#endif
#if _LIBC || HAVE_STRING_H
# include
#endif
#if _LIBC || HAVE_UNISTD_H
# include
#endif
#if !_LIBC
# define __environ environ
# ifndef HAVE_ENVIRON_DECL
extern char **environ;
# endif
#endif
#if _LIBC
/* This lock protects against simultaneous modifications of `environ'. */
# include
__libc_lock_define_initialized (static, envlock)
# define LOCK __libc_lock_lock (envlock)
# define UNLOCK __libc_lock_unlock (envlock)
#else
# define LOCK
# define UNLOCK
#endif
/* In the GNU C library we must keep the namespace clean. */
#ifdef _LIBC
# define setenv __setenv
# define unsetenv __unsetenv
# define clearenv __clearenv
# define tfind __tfind
# define tsearch __tsearch
#endif
/* In the GNU C library implementation we try to be more clever and
allow arbitrarily many changes of the environment given that the used
values are from a small set. Outside glibc this will eat up all
memory after a while. */
#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
&& defined __GNUC__)
# define USE_TSEARCH 1
# include
/* This is a pointer to the root of the search tree with the known
values. */
static void *known_values;
# define KNOWN_VALUE(Str) \
({ \
void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \
value != NULL ? *(char **) value : NULL; \
})
# define STORE_VALUE(Str) \
tsearch (Str, &known_values, (__compar_fn_t) strcmp)
#else
# undef USE_TSEARCH
# define KNOWN_VALUE(Str) NULL
# define STORE_VALUE(Str) do { } while (0)
#endif
/* If this variable is not a null pointer we allocated the current
environment. */
static char **last_environ;
/* This function is used by `setenv' and `putenv'. The difference between
the two functions is that for the former must create a new string which
is then placed in the environment, while the argument of `putenv'
must be used directly. This is all complicated by the fact that we try
to reuse values once generated for a `setenv' call since we can never
free the strings. */
static int
__add_to_environ (const char *name, const char *value, const char *combined,
int replace)
{
register char **ep;
register size_t size;
const size_t namelen = strlen (name);
const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
LOCK;
/* We have to get the pointer now that we have the lock and not earlier
since another thread might have created a new environment. */
ep = __environ;
size = 0;
if (ep != NULL)
{
for (; *ep != NULL; ++ep)
if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
break;
else
++size;
}
if (ep == NULL || __builtin_expect (*ep == NULL, 1))
{
char **new_environ;
/* We allocated this space; we can extend it. */
new_environ = (char **) realloc (last_environ,
(size + 2) * sizeof (char *));
if (new_environ == NULL)
{
UNLOCK;
return -1;
}
/* If the whole entry is given add it. */
if (combined != NULL)
/* We must not add the string to the search tree since it belongs
to the user. */
new_environ[size] = (char *) combined;
else
{
/* See whether the value is already known. */
#ifdef USE_TSEARCH
# ifdef __GNUC__
char new_value[namelen + 1 + vallen];
# else
char *new_value = (char *) alloca (namelen + 1 + vallen);
# endif
# ifdef _LIBC
__mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
value, vallen);
# else
memcpy (new_value, name, namelen);
new_value[namelen] = '=';
memcpy (&new_value[namelen + 1], value, vallen);
# endif
new_environ[size] = KNOWN_VALUE (new_value);
if (__builtin_expect (new_environ[size] == NULL, 1))
#endif
{
new_environ[size] = (char *) malloc (namelen + 1 + vallen);
if (__builtin_expect (new_environ[size] == NULL, 0))
{
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
#ifdef USE_TSEARCH
memcpy (new_environ[size], new_value, namelen + 1 + vallen);
#else
memcpy (new_environ[size], name, namelen);
new_environ[size][namelen] = '=';
memcpy (&new_environ[size][namelen + 1], value, vallen);
#endif
/* And save the value now. We cannot do this when we remove
the string since then we cannot decide whether it is a
user string or not. */
STORE_VALUE (new_environ[size]);
}
}
if (__environ != last_environ)
memcpy ((char *) new_environ, (char *) __environ,
size * sizeof (char *));
new_environ[size + 1] = NULL;
last_environ = __environ = new_environ;
}
else if (replace)
{
char *np;
/* Use the user string if given. */
if (combined != NULL)
np = (char *) combined;
else
{
#ifdef USE_TSEARCH
# ifdef __GNUC__
char new_value[namelen + 1 + vallen];
# else
char *new_value = (char *) alloca (namelen + 1 + vallen);
# endif
# ifdef _LIBC
__mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
value, vallen);
# else
memcpy (new_value, name, namelen);
new_value[namelen] = '=';
memcpy (&new_value[namelen + 1], value, vallen);
# endif
np = KNOWN_VALUE (new_value);
if (__builtin_expect (np == NULL, 1))
#endif
{
np = malloc (namelen + 1 + vallen);
if (__builtin_expect (np == NULL, 0))
{
UNLOCK;
return -1;
}
#ifdef USE_TSEARCH
memcpy (np, new_value, namelen + 1 + vallen);
#else
memcpy (np, name, namelen);
np[namelen] = '=';
memcpy (&np[namelen + 1], value, vallen);
#endif
/* And remember the value. */
STORE_VALUE (np);
}
}
*ep = np;
}
UNLOCK;
return 0;
}
int
setenv (const char *name, const char *value, int replace)
{
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
__set_errno (EINVAL);
return -1;
}
return __add_to_environ (name, value, NULL, replace);
}
int
unsetenv (const char *name)
{
size_t len;
char **ep;
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
__set_errno (EINVAL);
return -1;
}
len = strlen (name);
LOCK;
ep = __environ;
while (*ep != NULL)
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
{
/* Found it. Remove this pointer by moving later ones back. */
char **dp = ep;
do
dp[0] = dp[1];
while (*dp++);
/* Continue the loop in case NAME appears again. */
}
else
++ep;
UNLOCK;
return 0;
}
/* The `clearenv' was planned to be added to POSIX.1 but probably
never made it. Nevertheless the POSIX.9 standard (POSIX bindings
for Fortran 77) requires this function. */
int
clearenv (void)
{
LOCK;
if (__environ == last_environ && __environ != NULL)
{
/* We allocated this environment so we can free it. */
free (__environ);
last_environ = NULL;
}
/* Clear the environment pointer removes the whole environment. */
__environ = NULL;
UNLOCK;
return 0;
}
#ifdef _LIBC
libc_freeres_fn (free_mem)
{
/* Remove all traces. */
clearenv ();
/* Now remove the search tree. */
__tdestroy (known_values, free);
known_values = NULL;
}
# undef setenv
# undef unsetenv
# undef clearenv
weak_alias (__setenv, setenv)
weak_alias (__unsetenv, unsetenv)
weak_alias (__clearenv, clearenv)
#endif
#endif /*!HAVE_W32CE_SYSTEM*/
diff --git a/src/stpcpy.c b/src/stpcpy.c
index 8c489b8..4820c7a 100644
--- a/src/stpcpy.c
+++ b/src/stpcpy.c
@@ -1,54 +1,56 @@
/* Copyright (C) 1992, 1995, 1997, 2002, 2004 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library 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.
-
- The GNU C Library 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 the GNU C Library; if not,
- see . */
+ * This file is part of the GNU C Library.
+ *
+ * The GNU C Library 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.
+ *
+ * The GNU C Library 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 the GNU C Library; if not,
+ * see .
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#undef __stpcpy
#undef stpcpy
#ifndef weak_alias
# define __stpcpy stpcpy
#endif
/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
char *
__stpcpy (dest, src)
char *dest;
const char *src;
{
register char *d = dest;
register const char *s = src;
do
*d++ = *s;
while (*s++ != '\0');
return d - 1;
}
#ifdef libc_hidden_def
libc_hidden_def (__stpcpy)
#endif
#ifdef weak_alias
weak_alias (__stpcpy, stpcpy)
#endif
#ifdef libc_hidden_builtin_def
libc_hidden_builtin_def (stpcpy)
#endif
diff --git a/src/system-posix.c b/src/system-posix.c
index d274994..b7da9e3 100644
--- a/src/system-posix.c
+++ b/src/system-posix.c
@@ -1,450 +1,451 @@
/* system-posix.c - System support functions.
- Copyright (C) 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 .
+ * Copyright (C) 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef HAVE_STDINT_H
# include
#endif
/* Solaris 8 needs sys/types.h before time.h. */
#include
#include
#include
#include
#ifdef HAVE_GETRLIMIT
# include
# include
#endif /*HAVE_GETRLIMIT*/
#if __linux__
# include
#endif /*__linux__ */
#include "assuan-defs.h"
#include "debug.h"
assuan_fd_t
assuan_fdopen (int fd)
{
return dup (fd);
}
/* Sleep for the given number of microseconds. Default
implementation. */
void
__assuan_usleep (assuan_context_t ctx, unsigned int usec)
{
if (! usec)
return;
#ifdef HAVE_NANOSLEEP
{
struct timespec req;
struct timespec rem;
req.tv_sec = usec / 1000000;
req.tv_nsec = (usec % 1000000) * 1000;
while (nanosleep (&req, &rem) < 0 && errno == EINTR)
req = rem;
}
#else
{
struct timeval tv;
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
select (0, NULL, NULL, NULL, &tv);
}
#endif
}
/* Create a pipe with one inheritable end. Easy for Posix. */
int
__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
{
return pipe (fd);
}
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. Easy for Posix. */
int
__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
{
return close (fd);
}
ssize_t
__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
return read (fd, buffer, size);
}
ssize_t
__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
{
return write (fd, buffer, size);
}
int
__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
int ret;
do
ret = recvmsg (fd, msg, flags);
while (ret == -1 && errno == EINTR);
return ret;
}
int
__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
int ret;
do
ret = sendmsg (fd, msg, flags);
while (ret == -1 && errno == EINTR);
return ret;
}
static int
writen (int fd, const char *buffer, size_t length)
{
while (length)
{
int nwritten = write (fd, buffer, length);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
return -1; /* write error */
}
length -= nwritten;
buffer += nwritten;
}
return 0; /* okay */
}
/* Return the maximum number of currently allowed open file
* descriptors. */
static int
get_max_fds (void)
{
int max_fds = -1;
#ifdef HAVE_GETRLIMIT
struct rlimit rl;
/* Under Linux we can figure out the highest used file descriptor by
* reading /proc/PID/fd. This is in the common cases much faster
* than for example doing 4096 close calls where almost all of them
* will fail. We use the same code in GnuPG and measured this: On a
* system with a limit of 4096 files and only 8 files open with the
* highest number being 10, we speedup close_all_fds from 125ms to
* 0.4ms including the readdir.
*
* Another option would be to close the file descriptors as returned
* from reading that directory - however then we need to snapshot
* that list before starting to close them. */
#ifdef __linux__
{
DIR *dir = NULL;
struct dirent *dir_entry;
const char *s;
int x;
dir = opendir ("/proc/self/fd");
if (dir)
{
while ((dir_entry = readdir (dir)))
{
s = dir_entry->d_name;
if ( *s < '0' || *s > '9')
continue;
x = atoi (s);
if (x > max_fds)
max_fds = x;
}
closedir (dir);
}
if (max_fds != -1)
return max_fds + 1;
}
#endif /* __linux__ */
# ifdef RLIMIT_NOFILE
if (!getrlimit (RLIMIT_NOFILE, &rl))
max_fds = rl.rlim_max;
# endif
# ifdef RLIMIT_OFILE
if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl))
max_fds = rl.rlim_max;
# endif
#endif /*HAVE_GETRLIMIT*/
#ifdef _SC_OPEN_MAX
if (max_fds == -1)
{
long int scres = sysconf (_SC_OPEN_MAX);
if (scres >= 0)
max_fds = scres;
}
#endif
#ifdef _POSIX_OPEN_MAX
if (max_fds == -1)
max_fds = _POSIX_OPEN_MAX;
#endif
#ifdef OPEN_MAX
if (max_fds == -1)
max_fds = OPEN_MAX;
#endif
if (max_fds == -1)
max_fds = 256; /* Arbitrary limit. */
/* AIX returns INT32_MAX instead of a proper value. We assume that
this is always an error and use a more reasonable limit. */
#ifdef INT32_MAX
if (max_fds == INT32_MAX)
max_fds = 256;
#endif
return max_fds;
}
int
__assuan_spawn (assuan_context_t ctx, 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 pid;
pid = fork ();
if (pid < 0)
return -1;
if (pid == 0)
{
/* Child process (server side). */
int i;
int n;
char errbuf[512];
int *fdp;
int fdnul;
if (atfork)
atfork (atforkvalue, 0);
fdnul = open ("/dev/null", O_WRONLY);
if (fdnul == -1)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"can't open `/dev/null': %s", strerror (errno));
_exit (4);
}
/* Dup handles to stdin/stdout. */
if (fd_out != STDOUT_FILENO)
{
if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out,
STDOUT_FILENO) == -1)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"dup2 failed in child: %s", strerror (errno));
_exit (4);
}
}
if (fd_in != STDIN_FILENO)
{
if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in,
STDIN_FILENO) == -1)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"dup2 failed in child: %s", strerror (errno));
_exit (4);
}
}
/* Dup stderr to /dev/null unless it is in the list of FDs to be
passed to the child. */
fdp = fd_child_list;
if (fdp)
{
for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
;
}
if (!fdp || *fdp == -1)
{
if (dup2 (fdnul, STDERR_FILENO) == -1)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
"dup2(dev/null, 2) failed: %s", strerror (errno));
_exit (4);
}
}
close (fdnul);
/* Close all files which will not be duped and are not in the
fd_child_list. */
n = get_max_fds ();
for (i = 0; i < n; i++)
{
if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO)
continue;
fdp = fd_child_list;
if (fdp)
{
while (*fdp != -1 && *fdp != i)
fdp++;
}
if (!(fdp && *fdp != -1))
close (i);
}
gpg_err_set_errno (0);
if (! name)
{
/* No name and no args given, thus we don't do an exec
but continue the forked process. */
*argv = "server";
/* FIXME: Cleanup. */
return 0;
}
execv (name, (char *const *) argv);
/* oops - use the pipe to tell the parent about it */
snprintf (errbuf, sizeof(errbuf)-1,
"ERR %d can't exec `%s': %.50s\n",
_assuan_error (ctx, GPG_ERR_ASS_SERVER_START),
name, strerror (errno));
errbuf[sizeof(errbuf)-1] = 0;
writen (1, errbuf, strlen (errbuf));
_exit (4);
}
if (! name)
*argv = "client";
*r_pid = pid;
return 0;
}
/* FIXME: Add some sort of waitpid function that covers GPGME and
gpg-agent's use of assuan. */
pid_t
__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
int *status, int options)
{
/* We can't just release the PID, a waitpid is mandatory. But
NOWAIT in POSIX systems just means the caller already did the
waitpid for this child. */
if (! nowait)
return waitpid (pid, NULL, 0);
return 0;
}
int
__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2])
{
return socketpair (namespace, style, protocol, filedes);
}
int
__assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
{
return socket (namespace, style, protocol);
}
int
__assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
socklen_t length)
{
return connect (sock, addr, length);
}
/* The default system hooks for assuan contexts. */
struct assuan_system_hooks _assuan_system_hooks =
{
ASSUAN_SYSTEM_HOOKS_VERSION,
__assuan_usleep,
__assuan_pipe,
__assuan_close,
__assuan_read,
__assuan_write,
__assuan_recvmsg,
__assuan_sendmsg,
__assuan_spawn,
__assuan_waitpid,
__assuan_socketpair,
__assuan_socket,
__assuan_connect
};
diff --git a/src/system-w32.c b/src/system-w32.c
index 7b95d5c..9547ce0 100644
--- a/src/system-w32.c
+++ b/src/system-w32.c
@@ -1,595 +1,596 @@
/* system-w32.c - System support functions for Windows.
- Copyright (C) 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 .
+ * Copyright (C) 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include "assuan-defs.h"
#include "debug.h"
assuan_fd_t
assuan_fdopen (int fd)
{
assuan_fd_t ifd = (assuan_fd_t) _get_osfhandle (fd);
assuan_fd_t ofd;
if (! DuplicateHandle(GetCurrentProcess(), ifd,
GetCurrentProcess(), &ofd, 0,
TRUE, DUPLICATE_SAME_ACCESS))
{
gpg_err_set_errno (EIO);
return ASSUAN_INVALID_FD;
}
return ofd;
}
/* Sleep for the given number of microseconds. Default
implementation. */
void
__assuan_usleep (assuan_context_t ctx, unsigned int usec)
{
if (!usec)
return;
Sleep (usec / 1000);
}
/* Three simple wrappers, only used because thes function are named in
the def file. */
HANDLE
_assuan_w32ce_prepare_pipe (int *r_rvid, int write_end)
{
(void)r_rvid;
(void)write_end;
return INVALID_HANDLE_VALUE;
}
HANDLE
_assuan_w32ce_finish_pipe (int rvid, int write_end)
{
(void)rvid;
(void)write_end;
return INVALID_HANDLE_VALUE;
}
DWORD
_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
LPSECURITY_ATTRIBUTES sec_attr, DWORD size)
{
return CreatePipe (read_hd, write_hd, sec_attr, size);
}
/* Create a pipe with one inheritable end. Default implementation. */
int
__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
{
HANDLE rh;
HANDLE wh;
HANDLE th;
SECURITY_ATTRIBUTES sec_attr;
memset (&sec_attr, 0, sizeof (sec_attr));
sec_attr.nLength = sizeof (sec_attr);
sec_attr.bInheritHandle = FALSE;
if (!CreatePipe (&rh, &wh, &sec_attr, 0))
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
"CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
gpg_err_set_errno (EIO);
return -1;
}
if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh,
GetCurrentProcess(), &th, 0,
TRUE, DUPLICATE_SAME_ACCESS ))
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
"DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
CloseHandle (rh);
CloseHandle (wh);
gpg_err_set_errno (EIO);
return -1;
}
if (inherit_idx == 0)
{
CloseHandle (rh);
rh = th;
}
else
{
CloseHandle (wh);
wh = th;
}
fd[0] = rh;
fd[1] = wh;
return 0;
}
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. Default implementation. */
int
__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
{
int rc = closesocket (HANDLE2SOCKET(fd));
if (rc)
gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) );
if (rc && WSAGetLastError () == WSAENOTSOCK)
{
rc = CloseHandle (fd);
if (rc)
/* FIXME. */
gpg_err_set_errno (EIO);
}
return rc;
}
/* Return true if HD refers to a socket. */
static int
is_socket (HANDLE hd)
{
/* We need to figure out whether we are working on a socket or on a
handle. A trivial way would be to check for the return code of
recv and see if it is WSAENOTSOCK. However the recv may block
after the server process died and thus the destroy_reader will
hang. Another option is to use getsockopt to test whether it is
a socket. The bug here is that once a socket with a certain
values has been opened, closed and later a CreatePipe returned
the same value (i.e. handle), getsockopt still believes it is a
socket. What we do now is to use a combination of GetFileType
and GetNamedPipeInfo. The specs say that the latter may be used
on anonymous pipes as well. Note that there are claims that
since winsocket version 2 ReadFile may be used on a socket but
only if it is supported by the service provider. Tests on a
stock XP using a local TCP socket show that it does not work. */
DWORD dummyflags, dummyoutsize, dummyinsize, dummyinst;
if (GetFileType (hd) == FILE_TYPE_PIPE
&& !GetNamedPipeInfo (hd, &dummyflags, &dummyoutsize,
&dummyinsize, &dummyinst))
return 1; /* Function failed; thus we assume it is a socket. */
else
return 0; /* Success; this is not a socket. */
}
ssize_t
__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
int res;
int ec = 0;
if (is_socket (fd))
{
int tries = 3;
again:
ec = 0;
res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
if (res == -1)
ec = WSAGetLastError ();
if (ec == WSAEWOULDBLOCK && tries--)
{
/* EAGAIN: Use select to wait for resources and try again.
We do this 3 times and then give up. The higher level
layer then needs to take care of EAGAIN. No need to
specify a timeout - the socket is not expected to be in
blocking mode. */
fd_set fds;
FD_ZERO (&fds);
FD_SET (HANDLE2SOCKET (fd), &fds);
select (0, &fds, NULL, NULL, NULL);
goto again;
}
}
else
{
DWORD nread = 0;
if (!ReadFile (fd, buffer, size, &nread, NULL))
{
res = -1;
ec = GetLastError ();
}
else
res = nread;
}
if (res == -1)
{
switch (ec)
{
case WSAENOTSOCK:
gpg_err_set_errno (EBADF);
break;
case WSAEWOULDBLOCK:
gpg_err_set_errno (EAGAIN);
break;
case WSAECONNRESET: /* Due to the use of recv. */
case ERROR_BROKEN_PIPE:
gpg_err_set_errno (EPIPE);
break;
default:
gpg_err_set_errno (EIO);
break;
}
}
return res;
}
ssize_t
__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
{
int res;
int ec = 0;
if (is_socket (fd))
{
int tries = 3;
again:
ec = 0;
res = send (HANDLE2SOCKET (fd), buffer, size, 0);
if (res == -1)
ec = WSAGetLastError ();
if (ec == WSAEWOULDBLOCK && tries--)
{
/* EAGAIN: Use select to wait for resources and try again.
We do this 3 times and then give up. The higher level
layer then needs to take care of EAGAIN. No need to
specify a timeout - the socket is not expected to be in
blocking mode. */
fd_set fds;
FD_ZERO (&fds);
FD_SET (HANDLE2SOCKET (fd), &fds);
select (0, NULL, &fds, NULL, NULL);
goto again;
}
}
else
{
DWORD nwrite;
if (!WriteFile (fd, buffer, size, &nwrite, NULL))
{
res = -1;
ec = GetLastError ();
}
else
res = (int)nwrite;
}
if (res == -1)
{
switch (ec)
{
case WSAENOTSOCK:
gpg_err_set_errno (EBADF);
break;
case WSAEWOULDBLOCK:
gpg_err_set_errno (EAGAIN);
break;
case ERROR_BROKEN_PIPE:
case ERROR_NO_DATA:
gpg_err_set_errno (EPIPE);
break;
default:
gpg_err_set_errno (EIO);
break;
}
}
return res;
}
int
__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
gpg_err_set_errno (ENOSYS);
return -1;
}
int
__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
gpg_err_set_errno (ENOSYS);
return -1;
}
/* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */
static int
build_w32_commandline (assuan_context_t ctx, const char * const *argv,
char **cmdline)
{
int i, n;
const char *s;
char *buf, *p;
*cmdline = NULL;
n = 0;
for (i=0; (s = argv[i]); i++)
{
n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
for (; *s; s++)
if (*s == '\"')
n++; /* Need to double inner quotes. */
}
n++;
buf = p = _assuan_malloc (ctx, n);
if (! buf)
return -1;
for (i = 0; argv[i]; i++)
{
if (i)
p = stpcpy (p, " ");
if (! *argv[i]) /* Empty string. */
p = stpcpy (p, "\"\"");
else if (strpbrk (argv[i], " \t\n\v\f\""))
{
p = stpcpy (p, "\"");
for (s = argv[i]; *s; s++)
{
*p++ = *s;
if (*s == '\"')
*p++ = *s;
}
*p++ = '\"';
*p = 0;
}
else
p = stpcpy (p, argv[i]);
}
*cmdline= buf;
return 0;
}
int
__assuan_spawn (assuan_context_t ctx, 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)
{
SECURITY_ATTRIBUTES sec_attr;
PROCESS_INFORMATION pi =
{
NULL, /* Returns process handle. */
0, /* Returns primary thread handle. */
0, /* Returns pid. */
0 /* Returns tid. */
};
STARTUPINFO si;
assuan_fd_t fd;
assuan_fd_t *fdp;
char *cmdline;
HANDLE nullfd = INVALID_HANDLE_VALUE;
/* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
variable. However this requires us to write a full environment
handler, because the strings are expected in sorted order. The
suggestion given in the MS Reference Library, to save the old
value, change it, create process and restore it, is not thread
safe. */
/* Build the command line. */
if (build_w32_commandline (ctx, argv, &cmdline))
return -1;
/* Start the process. */
memset (&sec_attr, 0, sizeof sec_attr);
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
memset (&si, 0, sizeof si);
si.cb = sizeof (si);
si.dwFlags = STARTF_USESTDHANDLES;
/* FIXME: Dup to nul if ASSUAN_INVALID_FD. */
si.hStdInput = fd_in;
si.hStdOutput = fd_out;
/* Dup stderr to /dev/null unless it is in the list of FDs to be
passed to the child. */
fd = assuan_fd_from_posix_fd (fileno (stderr));
fdp = fd_child_list;
if (fdp)
{
for (; *fdp != ASSUAN_INVALID_FD && *fdp != fd; fdp++)
;
}
if (!fdp || *fdp == ASSUAN_INVALID_FD)
{
nullfd = CreateFileW (L"nul", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (nullfd == INVALID_HANDLE_VALUE)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"can't open `nul': %s", _assuan_w32_strerror (ctx, -1));
_assuan_free (ctx, cmdline);
gpg_err_set_errno (EIO);
return -1;
}
si.hStdError = nullfd;
}
else
si.hStdError = fd;
/* Note: We inherit all handles flagged as inheritable. This seems
to be a security flaw but there seems to be no way of selecting
handles to inherit. A fix for this would be to use a helper
process like we have in gpgme. */
/* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
/* name, cmdline); */
if (!CreateProcess (name, /* Program to start. */
cmdline, /* Command line arguments. */
&sec_attr, /* Process security attributes. */
&sec_attr, /* Thread security attributes. */
TRUE, /* Inherit handles. */
(CREATE_DEFAULT_ERROR_MODE
| ((flags & 128)? DETACHED_PROCESS : 0)
| GetPriorityClass (GetCurrentProcess ())
| CREATE_SUSPENDED), /* Creation flags. */
NULL, /* Environment. */
NULL, /* Use current drive/directory. */
&si, /* Startup information. */
&pi /* Returns process information. */
))
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
"CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
_assuan_free (ctx, cmdline);
if (nullfd != INVALID_HANDLE_VALUE)
CloseHandle (nullfd);
gpg_err_set_errno (EIO);
return -1;
}
_assuan_free (ctx, cmdline);
if (nullfd != INVALID_HANDLE_VALUE)
CloseHandle (nullfd);
ResumeThread (pi.hThread);
CloseHandle (pi.hThread);
/* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
/* " dwProcessID=%d dwThreadId=%d\n", */
/* pi.hProcess, pi.hThread, */
/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
*r_pid = (pid_t) pi.hProcess;
/* No need to modify peer process, as we don't change the handle
names. However this also means we are not safe, as we inherit
too many handles. Should use approach similar to gpgme and glib
using a helper process. */
return 0;
}
/* FIXME: Add some sort of waitpid function that covers GPGME and
gpg-agent's use of assuan. */
pid_t
__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
int *status, int options)
{
CloseHandle ((HANDLE) pid);
return 0;
}
int
__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2])
{
gpg_err_set_errno (ENOSYS);
return -1;
}
int
__assuan_socket (assuan_context_t ctx, int domain, int type, int proto)
{
int res;
res = socket (domain, type, proto);
if (res == -1)
gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
}
int
__assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
socklen_t length)
{
int res;
res = connect (sock, addr, length);
if (res < 0)
gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
}
/* The default system hooks for assuan contexts. */
struct assuan_system_hooks _assuan_system_hooks =
{
ASSUAN_SYSTEM_HOOKS_VERSION,
__assuan_usleep,
__assuan_pipe,
__assuan_close,
__assuan_read,
__assuan_write,
__assuan_recvmsg,
__assuan_sendmsg,
__assuan_spawn,
__assuan_waitpid,
__assuan_socketpair,
__assuan_socket,
__assuan_connect
};
diff --git a/src/system-w32ce.c b/src/system-w32ce.c
index d3e3357..da5dcf2 100644
--- a/src/system-w32ce.c
+++ b/src/system-w32ce.c
@@ -1,705 +1,706 @@
/* system-w32ce.c - System support functions for WindowsCE.
- Copyright (C) 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 .
+ * Copyright (C) 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
# ifdef HAVE_WINSOCK2_H
# include
# endif
#include
#include
#include
#include "assuan-defs.h"
#include "debug.h"
#define GPGCEDEV_IOCTL_GET_RVID \
CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define GPGCEDEV_IOCTL_MAKE_PIPE \
CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
static wchar_t *
utf8_to_wchar (const char *string)
{
int n;
size_t nbytes;
wchar_t *result;
if (!string)
return NULL;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
if (n < 0)
{
gpg_err_set_errno (EINVAL);
return NULL;
}
nbytes = (size_t)(n+1) * sizeof(*result);
if (nbytes / sizeof(*result) != (n+1))
{
gpg_err_set_errno (ENOMEM);
return NULL;
}
result = malloc (nbytes);
if (!result)
return NULL;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
if (n < 0)
{
free (result);
gpg_err_set_errno (EINVAL);
result = NULL;
}
return result;
}
/* Convenience function. */
static void
free_wchar (wchar_t *string)
{
if (string)
free (string);
}
assuan_fd_t
assuan_fdopen (int fd)
{
return (assuan_fd_t)fd;
}
/* Sleep for the given number of microseconds. Default
implementation. */
void
__assuan_usleep (assuan_context_t ctx, unsigned int usec)
{
if (usec)
Sleep (usec / 1000);
}
/* Prepare a pipe. Returns a handle which is, depending on WRITE_END,
will either act the read or as the write end of the pipe. The
other value returned is a rendezvous id used to complete the pipe
creation with _assuan_w32ce_finish_pipe. The rendezvous id may be
passed to another process and that process may finish the pipe
creation. This creates the interprocess pipe. The rendezvous id
is not a handle but a plain number; there is no release function
and care should be taken not to pass it to a function expecting a
handle. */
HANDLE
_assuan_w32ce_prepare_pipe (int *r_rvid, int write_end)
{
HANDLE hd;
LONG rvid;
ActivateDevice (L"Drivers\\GnuPG_Device", 0);
/* Note: Using "\\$device\\GPG1" should be identical to "GPG1:".
However this returns an invalid parameter error without having
called GPG_Init in the driver. The docs mention something about
RegisterAFXEx but that API is not documented. */
hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hd != INVALID_HANDLE_VALUE)
{
if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_GET_RVID,
NULL, 0, &rvid, sizeof rvid, NULL, NULL))
{
DWORD lastrc = GetLastError ();
CloseHandle (hd);
hd = INVALID_HANDLE_VALUE;
SetLastError (lastrc);
}
else
*r_rvid = rvid;
}
return hd;
}
/* Create a pipe. WRITE_END shall have the opposite value of the one
pssed to _assuan_w32ce_prepare_pipe; see there for more
details. */
HANDLE
_assuan_w32ce_finish_pipe (int rvid, int write_end)
{
HANDLE hd;
if (!rvid)
{
SetLastError (ERROR_INVALID_HANDLE);
return INVALID_HANDLE_VALUE;
}
hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
if (hd != INVALID_HANDLE_VALUE)
{
if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_MAKE_PIPE,
&rvid, sizeof rvid, NULL, 0, NULL, NULL))
{
DWORD lastrc = GetLastError ();
CloseHandle (hd);
hd = INVALID_HANDLE_VALUE;
SetLastError (lastrc);
}
}
return hd;
}
/* WindowsCE does not provide a pipe feature. However we need
something like a pipe to convey data between processes and in some
cases within a process. This replacement is not only used by
libassuan but exported and thus usable by gnupg and gpgme as well. */
DWORD
_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
LPSECURITY_ATTRIBUTES sec_attr, DWORD size)
{
HANDLE hd[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
int rvid;
int rc = 0;
hd[0] = _assuan_w32ce_prepare_pipe (&rvid, 0);
if (hd[0] != INVALID_HANDLE_VALUE)
{
hd[1] = _assuan_w32ce_finish_pipe (rvid, 1);
if (hd[1] != INVALID_HANDLE_VALUE)
rc = 1;
else
{
DWORD lastrc = GetLastError ();
CloseHandle (hd[0]);
hd[0] = INVALID_HANDLE_VALUE;
SetLastError (lastrc);
}
}
*read_hd = hd[0];
*write_hd = hd[1];
return rc;
}
/* Create a pipe with one inheritable end. Default implementation.
If INHERIT_IDX is 0, the read end of the pipe is made inheritable;
with INHERIT_IDX is 1 the write end will be inheritable. The
question now is how we create an inheritable pipe end under windows
CE were handles are process local objects? The trick we employ is
to defer the actual creation to the other end: We create an
incomplete pipe and pass a rendezvous id to the other end
(process). The other end now uses the rendezvous id to lookup the
pipe in our device driver, creates a new handle and uses that one
to finally establish the pipe. */
int
__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
{
HANDLE hd;
int rvid;
hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
if (hd == INVALID_HANDLE_VALUE)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
"CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
gpg_err_set_errno (EIO);
return -1;
}
if (inherit_idx)
{
fd[0] = hd;
fd[1] = (void*)rvid;
}
else
{
fd[0] = (void*)rvid;
fd[1] = hd;
}
return 0;
}
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. Default implementation. */
int
__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
{
int rc = closesocket (HANDLE2SOCKET(fd));
int err = WSAGetLastError ();
/* Note that gpg_err_set_errno on Windows CE overwrites
WSAGetLastError() (via SetLastError()). */
if (rc)
gpg_err_set_errno (_assuan_sock_wsa2errno (err));
if (rc && err == WSAENOTSOCK)
{
rc = CloseHandle (fd);
if (rc)
/* FIXME. */
gpg_err_set_errno (EIO);
}
return rc;
}
ssize_t
__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
/* Due to the peculiarities of the W32 API we can't use read for a
network socket and thus we try to use recv first and fallback to
read if recv detects that it is not a network socket. */
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx,
"fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
#ifdef HAVE_W32CE_SYSTEM
/* This is a bit of a hack to support stdin over ssh. Note that
fread buffers fully while getchar is line buffered. Weird, but
that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are
special handle values that shouldn't occur in the wild. */
if (fd == ASSUAN_STDIN)
{
int i = 0;
int chr;
while (i < size)
{
chr = getchar();
if (chr == EOF)
break;
((char*)buffer)[i++] = (char) chr;
if (chr == '\n')
break;
}
return TRACE_SYSRES (i);
}
#endif
res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
if (res == -1)
{
TRACE_LOG1 ("recv failed: rc=%d", (int)WSAGetLastError ());
switch (WSAGetLastError ())
{
case WSAENOTSOCK:
{
DWORD nread = 0;
res = ReadFile (fd, buffer, size, &nread, NULL);
if (! res)
{
TRACE_LOG1 ("ReadFile failed: rc=%d", (int)GetLastError ());
switch (GetLastError ())
{
case ERROR_BROKEN_PIPE:
gpg_err_set_errno (EPIPE);
break;
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BUSY:
gpg_err_set_errno (EAGAIN);
break;
default:
gpg_err_set_errno (EIO);
}
res = -1;
}
else
res = (int) nread;
}
break;
case WSAEWOULDBLOCK:
gpg_err_set_errno (EAGAIN);
break;
case ERROR_BROKEN_PIPE:
gpg_err_set_errno (EPIPE);
break;
default:
gpg_err_set_errno (EIO);
break;
}
}
return TRACE_SYSRES (res);
}
ssize_t
__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
{
/* Due to the peculiarities of the W32 API we can't use write for a
network socket and thus we try to use send first and fallback to
write if send detects that it is not a network socket. */
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_write", ctx,
"fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
#ifdef HAVE_W32CE_SYSTEM
/* This is a bit of a hack to support stdout over ssh. Note that
fread buffers fully while getchar is line buffered. Weird, but
that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are
special handle values that shouldn't occur in the wild. */
if (fd == ASSUAN_STDOUT)
{
res = fwrite (buffer, 1, size, stdout);
return TRACE_SYSRES (res);
}
#endif
res = send ((int)fd, buffer, size, 0);
if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
{
DWORD nwrite;
TRACE_LOG ("send call failed - trying WriteFile");
res = WriteFile (fd, buffer, size, &nwrite, NULL);
if (! res)
{
TRACE_LOG1 ("WriteFile failed: rc=%d", (int)GetLastError ());
switch (GetLastError ())
{
case ERROR_BROKEN_PIPE:
case ERROR_NO_DATA:
gpg_err_set_errno (EPIPE);
break;
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BUSY:
gpg_err_set_errno (EAGAIN);
break;
default:
gpg_err_set_errno (EIO);
break;
}
res = -1;
}
else
res = (int) nwrite;
}
else if (res == -1)
TRACE_LOG1 ("send call failed: rc=%d", (int)GetLastError ());
return TRACE_SYSRES (res);
}
int
__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
gpg_err_set_errno (ENOSYS);
return -1;
}
int
__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
gpg_err_set_errno (ENOSYS);
return -1;
}
/* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */
static int
build_w32_commandline (assuan_context_t ctx, const char * const *argv,
assuan_fd_t fd0, assuan_fd_t fd1, assuan_fd_t fd2,
int fd2_isnull,
char **cmdline)
{
int i, n;
const char *s;
char *buf, *p;
char fdbuf[3*30];
p = fdbuf;
*p = 0;
if (fd0 != ASSUAN_INVALID_FD)
{
snprintf (p, 25, "-&S0=%d ", (int)fd0);
p += strlen (p);
}
if (fd1 != ASSUAN_INVALID_FD)
{
snprintf (p, 25, "-&S1=%d ", (int)fd1);
p += strlen (p);
}
if (fd2 != ASSUAN_INVALID_FD)
{
if (fd2_isnull)
strcpy (p, "-&S2=null ");
else
snprintf (p, 25, "-&S2=%d ", (int)fd2);
p += strlen (p);
}
*cmdline = NULL;
n = strlen (fdbuf);
for (i=0; (s = argv[i]); i++)
{
if (!i)
continue; /* Ignore argv[0]. */
n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
for (; *s; s++)
if (*s == '\"')
n++; /* Need to double inner quotes. */
}
n++;
buf = p = _assuan_malloc (ctx, n);
if (! buf)
return -1;
p = stpcpy (p, fdbuf);
for (i = 0; argv[i]; i++)
{
if (!i)
continue; /* Ignore argv[0]. */
if (i > 1)
p = stpcpy (p, " ");
if (! *argv[i]) /* Empty string. */
p = stpcpy (p, "\"\"");
else if (strpbrk (argv[i], " \t\n\v\f\""))
{
p = stpcpy (p, "\"");
for (s = argv[i]; *s; s++)
{
*p++ = *s;
if (*s == '\"')
*p++ = *s;
}
*p++ = '\"';
*p = 0;
}
else
p = stpcpy (p, argv[i]);
}
*cmdline = buf;
return 0;
}
int
__assuan_spawn (assuan_context_t ctx, 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)
{
PROCESS_INFORMATION pi =
{
NULL, /* Returns process handle. */
0, /* Returns primary thread handle. */
0, /* Returns pid. */
0 /* Returns tid. */
};
assuan_fd_t fd;
assuan_fd_t *fdp;
assuan_fd_t fd_err;
int fd_err_isnull = 0;
char *cmdline;
/* Dup stderr to /dev/null unless it is in the list of FDs to be
passed to the child. Well we don't actually open nul because
that is not available on Windows, but use our hack for it.
Because an RVID of 0 is an invalid value and HANDLES will never
have this value either, we test for this as well. */
/* FIXME: As long as we can't decide whether a handle is a real
handler or an rendezvous id we can't do anything with the
FD_CHILD_LIST. We can't do much with stderr either, thus we
better don't pass stderr to the child at all. If we would do so
and it is not a rendezvous id the client would run into
problems. */
fd = assuan_fd_from_posix_fd (fileno (stderr));
fdp = fd_child_list;
if (fdp)
{
for (; *fdp != ASSUAN_INVALID_FD && *fdp != 0 && *fdp != fd; fdp++)
;
}
if (!fdp || *fdp == ASSUAN_INVALID_FD)
fd_err_isnull = 1;
fd_err = ASSUAN_INVALID_FD;
if (build_w32_commandline (ctx, argv, fd_in, fd_out, fd_err, fd_err_isnull,
&cmdline))
{
return -1;
}
TRACE2 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"path=`%s' cmdline=`%s'", name, cmdline);
{
wchar_t *wcmdline, *wname;
wcmdline = utf8_to_wchar (cmdline);
_assuan_free (ctx, cmdline);
if (!wcmdline)
return -1;
wname = utf8_to_wchar (name);
if (!wname)
{
free_wchar (wcmdline);
return -1;
}
if (!CreateProcess (wname, /* Program to start. */
wcmdline, /* Command line arguments. */
NULL, /* (not supported) */
NULL, /* (not supported) */
FALSE, /* (not supported) */
(CREATE_SUSPENDED), /* Creation flags. */
NULL, /* (not supported) */
NULL, /* (not supported) */
NULL, /* (not supported) */
&pi /* Returns process information.*/
))
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
free_wchar (wname);
free_wchar (wcmdline);
gpg_err_set_errno (EIO);
return -1;
}
free_wchar (wname);
free_wchar (wcmdline);
}
ResumeThread (pi.hThread);
TRACE4 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
"CreateProcess ready: hProcess=%p hThread=%p"
" dwProcessID=%d dwThreadId=%d\n",
pi.hProcess, pi.hThread, (int) pi.dwProcessId, (int) pi.dwThreadId);
CloseHandle (pi.hThread);
*r_pid = (pid_t) pi.hProcess;
return 0;
}
pid_t
__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
int *status, int options)
{
CloseHandle ((HANDLE) pid);
return 0;
}
int
__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2])
{
gpg_err_set_errno (ENOSYS);
return -1;
}
int
__assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
{
int res;
res = socket (namespace, style, protocol);
if (res == -1)
gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
}
int
__assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
socklen_t length)
{
int res;
res = connect (sock, addr, length);
if (res < 0)
gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
}
/* The default system hooks for assuan contexts. */
struct assuan_system_hooks _assuan_system_hooks =
{
ASSUAN_SYSTEM_HOOKS_VERSION,
__assuan_usleep,
__assuan_pipe,
__assuan_close,
__assuan_read,
__assuan_write,
__assuan_recvmsg,
__assuan_sendmsg,
__assuan_spawn,
__assuan_waitpid,
__assuan_socketpair,
__assuan_socket,
__assuan_connect
};
diff --git a/src/system.c b/src/system.c
index ddb99fb..00b76cb 100644
--- a/src/system.c
+++ b/src/system.c
@@ -1,414 +1,415 @@
/* 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 .
+ * 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef HAVE_SYS_TYPES_H
/* Solaris 8 needs sys/types.h before time.h. */
# include
#endif
#include
#ifdef HAVE_FCNTL_H
#include
#endif
#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);
}
/* Copy the system hooks struct, paying attention to version
differences. SRC is usually from the user, DST MUST be from the
library. */
void
_assuan_system_hooks_copy (assuan_system_hooks_t dst,
assuan_system_hooks_t src)
{
/* Reset the defaults. */
if (dst != &_assuan_system_hooks)
memcpy (dst, &_assuan_system_hooks, sizeof (*dst));
dst->version = ASSUAN_SYSTEM_HOOKS_VERSION;
if (src->version >= 1)
{
dst->usleep = src->usleep;
dst->pipe = src->pipe;
dst->close = src->close;
dst->read = src->read;
dst->write = src->write;
dst->sendmsg = src->sendmsg;
dst->recvmsg = src->recvmsg;
dst->spawn = src->spawn;
dst->waitpid = src->waitpid;
dst->socketpair = src->socketpair;
}
if (src->version >= 2)
{
dst->socket = src->socket;
dst->connect = src->connect;
}
if (src->version > 2)
/* FIXME. Application uses newer version of the library. What to
do? */
;
}
/* 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);
(ctx->system.usleep) (ctx, usec);
}
/* 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 = (ctx->system.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)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
"fd=0x%x", fd);
return (ctx->system.close) (ctx, fd);
}
/* 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)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close_inheritable", ctx,
"fd=0x%x", fd);
#ifdef HAVE_W32CE_SYSTEM
return 0; /* Nothing to do because it is a rendezvous id. */
#else
return (ctx->system.close) (ctx, fd);
#endif
}
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);
res = (ctx->system.read) (ctx, fd, buffer, size);
return TRACE_SYSRES (res);
#else
return (ctx->system.read) (ctx, fd, buffer, size);
#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);
res = (ctx->system.write) (ctx, fd, buffer, size);
return TRACE_SYSRES (res);
#else
return (ctx->system.write) (ctx, fd, buffer, size);
#endif
}
int
_assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_recvmsg", ctx,
"fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
res = (ctx->system.recvmsg) (ctx, fd, msg, flags);
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
return (ctx->system.recvmsg) (ctx, fd, msg, flags);
#endif
}
int
_assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
#if DEBUG_SYSIO
ssize_t 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);
}
}
res = (ctx->system.sendmsg) (ctx, fd, msg, flags);
return TRACE_SYSRES (res);
#else
return (ctx->system.sendmsg) (ctx, fd, msg, flags);
#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, 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 res;
int i;
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 = (ctx->system.spawn) (ctx, r_pid, name, argv, fd_in, fd_out,
fd_child_list, atfork, atforkvalue, flags);
if (name)
{
TRACE_LOG1 ("pid = 0x%x", *r_pid);
}
else
{
TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv);
}
return TRACE_SYSERR (res);
}
/* FIXME: Add some sort of waitpid function that covers GPGME and
gpg-agent's use of assuan. */
pid_t
_assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
int *status, int options)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx,
"pid=%i, action=%i, status=%p, options=%i",
pid, action, status, options);
res = (ctx->system.waitpid) (ctx, pid, action, status, options);
return TRACE_SYSRES (res);
#else
return (ctx->system.waitpid) (ctx, pid, action, status, options);
#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 = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes);
if (res == 0)
TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]);
return TRACE_SYSERR (res);
}
int
_assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
{
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socket", ctx,
"namespace=%i,style=%i,protocol=%i",
namespace, style, protocol);
res = (ctx->system.socket) (ctx, namespace, style, protocol);
return TRACE_SYSRES (res);
}
int
_assuan_connect (assuan_context_t ctx, int 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);
res = (ctx->system.connect) (ctx, sock, addr, length);
return TRACE_SYSRES (res);
}
diff --git a/src/sysutils.c b/src/sysutils.c
index 0eb5d1c..74031cd 100644
--- a/src/sysutils.c
+++ b/src/sysutils.c
@@ -1,138 +1,140 @@
/* sysutils.c - System utilities
- Copyright (C) 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 .
+ * Copyright (C) 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include