Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libfilezilla for openSUSE:Factory 
checked in at 2021-12-12 21:27:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libfilezilla (Old)
 and      /work/SRC/openSUSE:Factory/.libfilezilla.new.2520 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libfilezilla"

Sun Dec 12 21:27:52 2021 rev:43 rq:940085 version:0.35.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/libfilezilla/libfilezilla.changes        
2021-11-06 18:21:27.392994574 +0100
+++ /work/SRC/openSUSE:Factory/.libfilezilla.new.2520/libfilezilla.changes      
2021-12-12 21:28:39.804378999 +0100
@@ -1,0 +2,16 @@
+Sun Dec 12 13:58:20 UTC 2021 - ecsos <ec...@opensuse.org>
+
+- Update to 0.35.0
+  * New features:
+    - *nix: Added fz::forkblock which can be used to safely set 
+      FD_CLOEXEC on descriptors even if the system lacks 
+      SOCK_CLOCKEXEC, MSG_CMSG_CLOEXEC, pipe2 or accept4
+    - macOS: Impersonation support
+    - Added fz::tls_layer::set_unexpected_eof_cb, in some
+      situations it may be desirable that unexpected closure is not
+      reported as a hard errror
+  * Bugfixes and minor changes:
+    - Added various convenience overloads for fz::buffer
+    - Performance improvement for fz::json::to_string
+
+-------------------------------------------------------------------

Old:
----
  libfilezilla-0.34.2.tar.bz2

New:
----
  libfilezilla-0.35.0.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libfilezilla.spec ++++++
--- /var/tmp/diff_new_pack.Uo1ybM/_old  2021-12-12 21:28:40.232379253 +0100
+++ /var/tmp/diff_new_pack.Uo1ybM/_new  2021-12-12 21:28:40.236379255 +0100
@@ -16,11 +16,11 @@
 #
 
 
-%define major          22
+%define major          23
 %define libname                %{name}%{major}
 %define develname      %{name}-devel
 Name:           libfilezilla
-Version:        0.34.2
+Version:        0.35.0
 Release:        0
 Summary:        C++ library for filezilla
 License:        GPL-2.0-or-later

++++++ libfilezilla-0.34.2.tar.bz2 -> libfilezilla-0.35.0.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/NEWS new/libfilezilla-0.35.0/NEWS
--- old/libfilezilla-0.34.2/NEWS        2021-10-26 13:54:12.000000000 +0200
+++ new/libfilezilla-0.35.0/NEWS        2021-12-08 16:09:44.000000000 +0100
@@ -1,3 +1,11 @@
+0.35.0 (2021-12-08)
+
++ *nix: Added fz::forkblock which can be used to safely set FD_CLOEXEC on 
descriptors even if the system lacks SOCK_CLOCKEXEC, MSG_CMSG_CLOEXEC, pipe2 or 
accept4
++ macOS: Impersonation support
++ Added fz::tls_layer::set_unexpected_eof_cb, in some situations it may be 
desirable that unexpected closure is not reported as a hard errror
+- Added various convenience overloads for fz::buffer
+- Performance improvement for fz::json::to_string
+
 0.34.2 (2021-10-26)
 
 + fz::file::open now returns fz::result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/configure 
new/libfilezilla-0.35.0/configure
--- old/libfilezilla-0.34.2/configure   2021-10-26 13:54:27.000000000 +0200
+++ new/libfilezilla-0.35.0/configure   2021-12-08 16:11:25.000000000 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libfilezilla 0.34.2.
+# Generated by GNU Autoconf 2.69 for libfilezilla 0.35.0.
 #
 # Report bugs to <tim.ko...@filezilla-project.org>.
 #
@@ -590,8 +590,8 @@
 # Identity of this package.
 PACKAGE_NAME='libfilezilla'
 PACKAGE_TARNAME='libfilezilla'
-PACKAGE_VERSION='0.34.2'
-PACKAGE_STRING='libfilezilla 0.34.2'
+PACKAGE_VERSION='0.35.0'
+PACKAGE_STRING='libfilezilla 0.35.0'
 PACKAGE_BUGREPORT='tim.ko...@filezilla-project.org'
 PACKAGE_URL='https://lib.filezilla-project.org/'
 
@@ -1451,7 +1451,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libfilezilla 0.34.2 to adapt to many kinds of systems.
+\`configure' configures libfilezilla 0.35.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1522,7 +1522,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libfilezilla 0.34.2:";;
+     short | recursive ) echo "Configuration of libfilezilla 0.35.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1678,7 +1678,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libfilezilla configure 0.34.2
+libfilezilla configure 0.35.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2123,7 +2123,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libfilezilla $as_me 0.34.2, which was
+It was created by libfilezilla $as_me 0.35.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2478,7 +2478,7 @@
 # If any interfaces have been added since the last public release, then 
increment age.
 # If any interfaces have been removed or changed since the last public 
release, then set age to 0.
 # CURRENT:REVISION:AGE
-LIBRARY_VERSION=22:0:0
+LIBRARY_VERSION=23:0:0
 
 
 ac_config_headers="$ac_config_headers config/config.hpp"
@@ -2994,7 +2994,7 @@
 
 # Define the identity of the package.
  PACKAGE='libfilezilla'
- VERSION='0.34.2'
+ VERSION='0.35.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -22459,7 +22459,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libfilezilla $as_me 0.34.2, which was
+This file was extended by libfilezilla $as_me 0.35.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -22526,7 +22526,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libfilezilla config.status 0.34.2
+libfilezilla config.status 0.35.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/configure.ac 
new/libfilezilla-0.35.0/configure.ac
--- old/libfilezilla-0.34.2/configure.ac        2021-10-26 13:54:12.000000000 
+0200
+++ new/libfilezilla-0.35.0/configure.ac        2021-12-08 16:09:44.000000000 
+0100
@@ -1,4 +1,4 @@
-???AC_INIT([libfilezilla],[0.34.2],[tim.ko...@filezilla-project.org],[],[https://lib.filezilla-project.org/])
+???AC_INIT([libfilezilla],[0.35.0],[tim.ko...@filezilla-project.org],[],[https://lib.filezilla-project.org/])
 
 # Update the version information only immediately before a public release of 
your software
 # If the library source code has changed at all since the last update, then 
increment revision (???c:r:a??? becomes ???c:r+1:a???).
@@ -6,7 +6,7 @@
 # If any interfaces have been added since the last public release, then 
increment age.
 # If any interfaces have been removed or changed since the last public 
release, then set age to 0.
 # CURRENT:REVISION:AGE
-LIBRARY_VERSION=22:0:0
+LIBRARY_VERSION=23:0:0
 
 
 AC_CONFIG_HEADERS([config/config.hpp])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/demos/Makefile.am 
new/libfilezilla-0.35.0/demos/Makefile.am
--- old/libfilezilla-0.34.2/demos/Makefile.am   2021-08-31 16:47:29.000000000 
+0200
+++ new/libfilezilla-0.35.0/demos/Makefile.am   2021-12-08 16:09:44.000000000 
+0100
@@ -55,7 +55,7 @@
 
 list_DEPENDENCIES = ../lib/libfilezilla.la
 
-if FZ_UNIX
+if !FZ_WINDOWS
 noinst_PROGRAMS += impersonation
 
 impersonation_SOURCES = impersonation.cpp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/demos/Makefile.in 
new/libfilezilla-0.35.0/demos/Makefile.in
--- old/libfilezilla-0.34.2/demos/Makefile.in   2021-10-26 13:54:26.000000000 
+0200
+++ new/libfilezilla-0.35.0/demos/Makefile.in   2021-12-08 16:11:25.000000000 
+0100
@@ -91,7 +91,7 @@
 host_triplet = @host@
 noinst_PROGRAMS = timer_fizzbuzz$(EXEEXT) process$(EXEEXT) \
        events$(EXEEXT) list$(EXEEXT) $(am__EXEEXT_1)
-@FZ_UNIX_TRUE@am__append_1 = impersonation
+@FZ_WINDOWS_FALSE@am__append_1 = impersonation
 subdir = demos
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_flag.m4 \
@@ -122,7 +122,7 @@
 CONFIG_HEADER = $(top_builddir)/config/config.hpp
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-@FZ_UNIX_TRUE@am__EXEEXT_1 = impersonation$(EXEEXT)
+@FZ_WINDOWS_FALSE@am__EXEEXT_1 = impersonation$(EXEEXT)
 PROGRAMS = $(noinst_PROGRAMS)
 am_events_OBJECTS = events-events.$(OBJEXT)
 events_OBJECTS = $(am_events_OBJECTS)
@@ -135,8 +135,8 @@
        $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
        $(CXXFLAGS) $(events_LDFLAGS) $(LDFLAGS) -o $@
 am__impersonation_SOURCES_DIST = impersonation.cpp
-@FZ_UNIX_TRUE@am_impersonation_OBJECTS =  \
-@FZ_UNIX_TRUE@ impersonation-impersonation.$(OBJEXT)
+@FZ_WINDOWS_FALSE@am_impersonation_OBJECTS =  \
+@FZ_WINDOWS_FALSE@     impersonation-impersonation.$(OBJEXT)
 impersonation_OBJECTS = $(am_impersonation_OBJECTS)
 impersonation_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
        $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
@@ -422,12 +422,13 @@
 list_LDFLAGS = $(AM_LDFLAGS) -no-install
 list_LDADD = ../lib/libfilezilla.la $(libdeps)
 list_DEPENDENCIES = ../lib/libfilezilla.la
-@FZ_UNIX_TRUE@impersonation_SOURCES = impersonation.cpp
-@FZ_UNIX_TRUE@impersonation_CPPFLAGS = $(AM_CPPFLAGS) \
-@FZ_UNIX_TRUE@ -I$(top_srcdir)/lib
-@FZ_UNIX_TRUE@impersonation_LDFLAGS = $(AM_LDFLAGS) -no-install
-@FZ_UNIX_TRUE@impersonation_LDADD = ../lib/libfilezilla.la $(libdeps)
-@FZ_UNIX_TRUE@impersonation_DEPENDENCIES = ../lib/libfilezilla.la
+@FZ_WINDOWS_FALSE@impersonation_SOURCES = impersonation.cpp
+@FZ_WINDOWS_FALSE@impersonation_CPPFLAGS = $(AM_CPPFLAGS) \
+@FZ_WINDOWS_FALSE@     -I$(top_srcdir)/lib
+@FZ_WINDOWS_FALSE@impersonation_LDFLAGS = $(AM_LDFLAGS) -no-install
+@FZ_WINDOWS_FALSE@impersonation_LDADD = ../lib/libfilezilla.la \
+@FZ_WINDOWS_FALSE@     $(libdeps)
+@FZ_WINDOWS_FALSE@impersonation_DEPENDENCIES = ../lib/libfilezilla.la
 dist_noinst_DATA = \
        demo_events.vcxproj \
        demo_list.vcxproj \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/demos/impersonation.cpp 
new/libfilezilla-0.35.0/demos/impersonation.cpp
--- old/libfilezilla-0.34.2/demos/impersonation.cpp     2021-08-31 
16:47:29.000000000 +0200
+++ new/libfilezilla-0.35.0/demos/impersonation.cpp     2021-12-08 
16:09:44.000000000 +0100
@@ -45,7 +45,11 @@
                assert(recv(sockfd, &v, 1, 0) == 1);
 
                std::cerr << "Child: Opening /tmp/test.txt\n";
-               auto f = fz::file("/tmp/test.txt", fz::file::writing, 
fz::file::empty | fz::file::current_user_only);
+               fz::file f;
+               if (!f.open("/tmp/test.txt", fz::file::writing, fz::file::empty 
| fz::file::current_user_only)) {
+                       std::cerr << "Could not open /tmp/test.txt\n";
+                       abort();
+               }
                int fd = f.detach();
                fz::buffer b;
                b.append("okay\n");
@@ -56,7 +60,9 @@
                        if (res < 0) {
                                abort();
                        }
-                       close(fd);
+                       if (fd != 1) {
+                               close(fd);
+                       }
                        fd = -1;
                }
 
@@ -94,6 +100,10 @@
 
        // Drop privileges
        fz::impersonation_token nobody("nobody", 
fz::impersonation_flag::pwless);
+       if (!nobody) {
+               std::cerr << "Parent: Could not get token for \"nobody\"\n";
+               abort();
+       }
        if (!fz::set_process_impersonation(nobody)) {
                std::cerr << "Parent: Could not drop privileges to 
\"nobody\"\n";
                abort();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/buffer.cpp 
new/libfilezilla-0.35.0/lib/buffer.cpp
--- old/libfilezilla-0.34.2/lib/buffer.cpp      2021-09-14 14:31:26.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/buffer.cpp      2021-12-08 16:09:44.000000000 
+0100
@@ -176,11 +176,22 @@
        append(reinterpret_cast<unsigned char const*>(data.data()), 
data.size());
 }
 
+void buffer::append(fz::buffer const& b)
+{
+       append(b.get(), b.size());
+}
+
 void buffer::append(unsigned char v)
 {
        append(&v, 1);
 }
 
+void buffer::append(size_t len, unsigned char c)
+{
+       memset(get(len), c, len);
+       add(len);
+}
+
 void buffer::reserve(size_t capacity)
 {
        if (capacity_ >= capacity) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/encode.cpp 
new/libfilezilla-0.35.0/lib/encode.cpp
--- old/libfilezilla-0.34.2/lib/encode.cpp      2021-07-02 11:04:19.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/encode.cpp      2021-12-08 16:09:44.000000000 
+0100
@@ -1,3 +1,4 @@
+#include "libfilezilla/buffer.hpp"
 #include "libfilezilla/encode.hpp"
 
 namespace fz {
@@ -67,6 +68,13 @@
        return ret;
 }
 
+std::string base64_encode(fz::buffer const& in, base64_type type, bool pad)
+{
+       std::string ret;
+       base64_encode_impl(ret, in.to_view(), type, pad);
+       return ret;
+}
+
 void base64_encode_append(std::string& result, std::string_view const& in, 
base64_type type, bool pad)
 {
        base64_encode_impl(result, in, type, pad);
@@ -172,6 +180,11 @@
        return base64_decode_impl<std::vector<uint8_t>>(in);
 }
 
+std::vector<uint8_t> base64_decode(fz::buffer const& in)
+{
+       return base64_decode_impl<std::vector<uint8_t>>(in.to_view());
+}
+
 std::string base64_decode_s(std::string_view const& in)
 {
        return base64_decode_impl<std::string>(in);
@@ -182,6 +195,11 @@
        return base64_decode_impl<std::string>(in);
 }
 
+std::string base64_decode_s(fz::buffer const& in)
+{
+       return base64_decode_impl<std::string>(in.to_view());
+}
+
 
 namespace {
 template<typename DataContainer>
@@ -275,6 +293,10 @@
        return base32_encode_impl(in, type, pad);
 }
 
+std::string base32_encode(fz::buffer const& in, base32_type type, bool pad)
+{
+       return base32_encode_impl(in.to_view(), type, pad);
+}
 
 namespace {
 template<typename Ret, typename View>
@@ -435,6 +457,11 @@
        return base32_decode_impl<std::vector<uint8_t>>(in, type);
 }
 
+std::vector<uint8_t> base32_decode(fz::buffer const& in, base32_type type)
+{
+       return base32_decode_impl<std::vector<uint8_t>>(in.to_view(), type);
+}
+
 std::string base32_decode_s(std::string_view const& in, base32_type type)
 {
        return base32_decode_impl<std::string>(in, type);
@@ -445,6 +472,11 @@
        return base32_decode_impl<std::string>(in, type);
 }
 
+std::string base32_decode_s(fz::buffer const& in, base32_type type)
+{
+       return base32_decode_impl<std::string>(in.to_view(), type);
+}
+
 
 std::string percent_encode(std::string_view const& s, bool keep_slashes)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/glue/unix.cpp 
new/libfilezilla-0.35.0/lib/glue/unix.cpp
--- old/libfilezilla-0.34.2/lib/glue/unix.cpp   2021-10-19 11:51:29.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/glue/unix.cpp   2021-12-08 16:09:44.000000000 
+0100
@@ -1,5 +1,6 @@
 #include "../libfilezilla/buffer.hpp"
 #include "../libfilezilla/glue/unix.hpp"
+#include "../libfilezilla/process.hpp"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -28,7 +29,7 @@
        return false;
 }
 
-bool create_pipe(int fds[2], bool require_atomic_creation)
+bool create_pipe(int fds[2])
 {
        disable_sigpipe();
 
@@ -46,10 +47,7 @@
        else
 #endif
        {
-               if (require_atomic_creation) {
-                       return false;
-               }
-
+               forkblock b;
                if (pipe(fds) != 0) {
                        return false;
                }
@@ -67,16 +65,28 @@
        std::call_once(flag, [](){ signal(SIGPIPE, SIG_IGN); });
 }
 
-#if FZ_UNIX
 bool create_socketpair(int fds[2])
 {
        disable_sigpipe();
 
-       bool ret = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds) == 0;
+       int flags = SOCK_STREAM;
+#ifdef SOCK_CLOEXEC
+       flags |= SOCK_CLOEXEC;
+#else
+       forkblock b;
+#endif
+       bool ret = socketpair(AF_UNIX, flags, 0, fds) == 0;
        if (!ret) {
                fds[0] = -1;
                fds[1] = -1;
        }
+#ifndef SOCK_CLOEXEC
+       if (ret) {
+           set_cloexec(fds[0]);
+           set_cloexec(fds[1]);
+       }
+#endif
+
        return ret;
 }
 
@@ -87,7 +97,7 @@
                return -1;
        }
        if (socket < 0) {
-               error = EBADFD;
+               error = EBADF;
                return -1;
        }
 
@@ -144,14 +154,18 @@
 {
        fd = -1;
        if (socket < 0) {
-               error = EBADFD;
+               error = EBADF;
                return -1;
        }
 
+       int flags{};
 #ifdef MSG_NOSIGNAL
-       const int flags = MSG_NOSIGNAL|MSG_CMSG_CLOEXEC;
+       flags |= MSG_NOSIGNAL;
+#endif
+#ifdef MSG_CMSG_CLOEXEC
+       flags |= MSG_CMSG_CLOEXEC;
 #else
-       const int flags = MSG_CMSG_CLOEXEC;
+       forkblock b;
 #endif
 
        struct msghdr msg{};
@@ -184,6 +198,9 @@
                struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg);
                if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type 
== SCM_RIGHTS && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
                        memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
+#ifndef MSG_CMSG_CLOEXEC
+                       set_cloexec(fd);
+#endif
                };
        }
        else {
@@ -192,6 +209,5 @@
 
        return res;
 }
-#endif
 
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/impersonation.cpp 
new/libfilezilla-0.35.0/lib/impersonation.cpp
--- old/libfilezilla-0.34.2/lib/impersonation.cpp       2021-10-19 
11:51:29.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/impersonation.cpp       2021-12-08 
16:10:58.000000000 +0100
@@ -1,20 +1,26 @@
 #include "libfilezilla/impersonation.hpp"
 
-#if FZ_UNIX
+#if FZ_UNIX || FZ_MAC
 
 #include "libfilezilla/buffer.hpp"
 
 #include <optional>
 #include <tuple>
 
+#if FZ_UNIX
 #include <crypt.h>
+#include <shadow.h>
+#endif
 #include <grp.h>
 #include <pwd.h>
-#include <shadow.h>
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#if FZ_MAC
+#include <CoreServices/CoreServices.h>
+#endif
+
 namespace fz {
 namespace {
 struct passwd_holder {
@@ -52,7 +58,7 @@
        return ret;
 }
 
-
+#if FZ_UNIX
 struct shadow_holder {
        shadow_holder() = default;
        shadow_holder(shadow_holder const&) = delete;
@@ -87,6 +93,7 @@
 
        return ret;
 }
+#endif
 }
 
 class impersonation_token_impl final
@@ -119,7 +126,14 @@
        int size = 100;
        while (true) {
                ret.resize(size);
-               int res = getgrouplist(username.c_str(), primary, ret.data(), 
&size);
+#if FZ_MAC
+               typedef int glt;
+               static_assert(sizeof(gid_t) == sizeof(glt));
+#else
+               typedef gid_t glt;
+#endif
+
+               int res = getgrouplist(username.c_str(), primary, 
reinterpret_cast<glt*>(ret.data()), &size);
                if (size < 0 || (res < 0 && static_cast<size_t>(size) <= 
ret.size())) {
                        // Something went wrong
                        ret.clear();
@@ -133,26 +147,65 @@
        }
        return ret;
 }
+
+bool check_auth(fz::native_string const& username, fz::native_string const& 
password)
+{
+#if FZ_UNIX
+       auto shadow = get_shadow(username);
+       if (shadow.shadow_) {
+               struct crypt_data data{};
+               char* encrypted = crypt_r(password.c_str(), 
shadow.shadow_->sp_pwdp, &data);
+               if (encrypted && !strcmp(encrypted, shadow.shadow_->sp_pwdp)) {
+                       return true;
+               }
+       }
+#elif FZ_MAC
+       bool ret{};
+
+       CFStringRef cfu = CFStringCreateWithCString(NULL, username.c_str(), 
kCFStringEncodingUTF8);
+       if (cfu) {
+               CSIdentityQueryRef q = 
CSIdentityQueryCreateForName(kCFAllocatorDefault, cfu, 
kCSIdentityQueryStringEquals, kCSIdentityClassUser, 
CSGetDefaultIdentityAuthority());
+               if (q) {
+                       if (CSIdentityQueryExecute(q, 
kCSIdentityQueryGenerateUpdateEvents, NULL)) {
+                               CFArrayRef users = 
CSIdentityQueryCopyResults(q);
+                               if (users) {
+                                       if (CFArrayGetCount(users) == 1) {
+                                               CSIdentityRef user = 
(CSIdentityRef)(CFArrayGetValueAtIndex(users, 0));
+                                               if (user) {
+                                                       CFStringRef pw = 
CFStringCreateWithCString(NULL, password.c_str(), kCFStringEncodingUTF8);
+                                                       if (pw) {
+                                                               ret = 
CSIdentityAuthenticateUsingPassword(user, pw);
+                                                               CFRelease(pw);
+                                                       }
+                                               }
+                                       }
+                                       CFRelease(users);
+                               }
+                       }
+                       CFRelease(q);
+               }
+               CFRelease(cfu);
+       }
+
+       return ret;
+#endif
+       return false;
+}
 }
 
-impersonation_token::impersonation_token(fz::native_string const& username, 
fz::native_string const& passwd)
+impersonation_token::impersonation_token(fz::native_string const& username, 
fz::native_string const& password)
 {
        auto pwd = get_passwd(username);
        if (pwd.pwd_) {
-               auto shadow = get_shadow(username);
-               if (shadow.shadow_) {
-                       struct crypt_data data{};
-                       char* encrypted = crypt_r(passwd.c_str(), 
shadow.shadow_->sp_pwdp, &data);
-                       if (encrypted && !strcmp(encrypted, 
shadow.shadow_->sp_pwdp)) {
-                               impl_ = 
std::make_unique<impersonation_token_impl>();
-                               impl_->name_ = username;
-                               if (pwd.pwd_->pw_dir) {
-                                       impl_->home_ = pwd.pwd_->pw_dir;
-                               }
-                               impl_->uid_ = pwd.pwd_->pw_uid;
-                               impl_->gid_ = pwd.pwd_->pw_gid;
-                               impl_->sup_groups_ = 
get_supplementary(username, pwd.pwd_->pw_gid);
+               if (check_auth(username, password)) {
+                       impl_ = std::make_unique<impersonation_token_impl>();
+                       impl_->name_ = username;
+                       if (pwd.pwd_->pw_dir) {
+                               impl_->home_ = pwd.pwd_->pw_dir;
                        }
+                       impl_->uid_ = pwd.pwd_->pw_uid;
+                       impl_->gid_ = pwd.pwd_->pw_gid;
+                       impl_->sup_groups_ = get_supplementary(username, 
pwd.pwd_->pw_gid);
                }
        }
 }
@@ -284,14 +337,14 @@
 impersonation_token& impersonation_token::operator=(impersonation_token&&) 
noexcept = default;
 
 
-impersonation_token::impersonation_token(fz::native_string const& username, 
fz::native_string const& passwd)
+impersonation_token::impersonation_token(fz::native_string const& username, 
fz::native_string const& password)
 {
        if (username.find_first_of(L"\"/\\[]:;|=,+*?<>") != 
fz::native_string::npos) {
                return;
        }
 
        HANDLE token{INVALID_HANDLE_VALUE};
-       DWORD res = LogonUserW(username.c_str(), nullptr, passwd.c_str(), 
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &token);
+       DWORD res = LogonUserW(username.c_str(), nullptr, password.c_str(), 
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &token);
        if (!res) {
                return;
        }
@@ -385,14 +438,28 @@
 #elif 0
 namespace fz {
 struct impersonation_token_impl{};
+
 impersonation_token::impersonation_token() {}
+impersonation_token::impersonation_token(impersonation_token&&) noexcept {}
+impersonation_token& impersonation_token::operator=(impersonation_token&&) 
noexcept { return *this; }
+
 impersonation_token::impersonation_token(fz::native_string const&, 
fz::native_string const&) {}
-impersonation_token::impersonation_token(fz::native_string const&, 
impersonation_flag) {}
 impersonation_token::~impersonation_token() noexcept {}
 
+bool impersonation_token::operator==(impersonation_token const&) const { 
return true; }
+bool impersonation_token::operator<(impersonation_token const&) const { return 
false; }
+
+fz::native_string impersonation_token::username() const { return {}; }
+fz::native_string impersonation_token::home() const { return {}; }
+std::size_t impersonation_token::hash() const noexcept { return {}; }
+
+#if FZ_UNIX
+impersonation_token::impersonation_token(fz::native_string const&, 
impersonation_flag) {}
 bool set_process_impersonation(impersonation_token const&)
 {
        return false;
 }
+#endif
+
 }
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/json.cpp 
new/libfilezilla-0.35.0/lib/json.cpp
--- old/libfilezilla-0.34.2/lib/json.cpp        2021-09-29 14:07:07.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/json.cpp        2021-12-08 16:09:45.000000000 
+0100
@@ -113,9 +113,8 @@
 }
 
 namespace {
-void json_append_escaped(std::string& out, std::string const& s)
+void json_append_escaped(std::string & out, std::string const& s)
 {
-       out.reserve(s.size());
        for (auto & c : s) {
                switch (c) {
                case '\r':
@@ -147,8 +146,13 @@
 }
 
 std::string json::to_string(bool pretty, size_t depth) const
+{      std::string ret;
+       to_string(ret, pretty, depth);
+       return ret;
+}
+
+void json::to_string(std::string & ret, bool pretty, size_t depth) const
 {
-       std::string ret;
        switch (type_) {
        case json_type::object: {
                ret += '{';
@@ -177,7 +181,7 @@
                        if (pretty) {
                                ret += ' ';
                        }
-                       ret += c.second.to_string(pretty, depth + 1);
+                       c.second.to_string(ret, pretty, depth + 1);
                }
                if (pretty) {
                        ret += '\n';
@@ -208,7 +212,7 @@
                                ret += "null";
                        }
                        else {
-                               ret += c.to_string(pretty, depth + 1);
+                               c.to_string(ret, pretty, depth + 1);
                        }
                }
                if (pretty) {
@@ -219,24 +223,22 @@
                break;
        }
        case json_type::boolean:
-               ret = std::get<3>(value_) ? "true" : "false";
+               ret += std::get<3>(value_) ? "true" : "false";
                break;
        case json_type::number:
-               ret = std::get<0>(value_);
+               ret += std::get<0>(value_);
                break;
        case json_type::null:
-               ret = "null";
+               ret += "null";
                break;
        case json_type::string:
-               ret = '"';
+               ret += '"';
                json_append_escaped(ret, std::get<0>(value_));
                ret += '"';
                break;
        case json_type::none:
                break;
        }
-
-       return ret;
 }
 
 json json::parse(std::string_view const& s, size_t max_depth)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/buffer.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/buffer.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/buffer.hpp 2021-07-28 
15:59:29.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/buffer.hpp 2021-12-08 
16:09:45.000000000 +0100
@@ -4,6 +4,7 @@
 #include "libfilezilla.hpp"
 
 #include <vector>
+#include <type_traits>
 
 /** \file
 * \brief Declares fz::buffer
@@ -65,6 +66,19 @@
        /// Increase size by the passed amount. Call this after having obtained 
a writable buffer with get(size_t write_size)
        void add(size_t added);
 
+       /**
+        * \brief Overload of add for signed types, only adds if value is 
positive.
+        *
+        * Does nothing on values <= 0, useful for directly passing the ssize_t 
result of
+        * the system's recv() or read() functions.
+        */
+       template<typename T, std::enable_if_t<std::is_signed_v<T>, int> = 0>
+       void add(T added) {
+               if (added > 0) {
+                       add(static_cast<size_t>(added));
+               }
+       }
+
        /** \brief Removes consumed bytes from the beginning of the buffer.
         *
         * Undefined if consumed > size()
@@ -85,7 +99,26 @@
        void append(unsigned char const* data, size_t len);
        void append(std::string_view const& str);
        void append(std::vector<uint8_t> const& data);
+       void append(fz::buffer const& b);
        void append(unsigned char v);
+       void append(size_t len, unsigned char c);
+
+       buffer& operator+=(unsigned char v) {
+               append(v);
+               return *this;
+       }
+       buffer& operator+=(std::string_view const& str) {
+               append(str);
+               return *this;
+       }
+       buffer& operator+=(std::vector<uint8_t> const& data) {
+               append(data);
+               return *this;
+       }
+       buffer& operator+=(fz::buffer const& b) {
+               append(b);
+               return *this;
+       }
 
        bool empty() const { return size_ == 0; }
        explicit operator bool() const {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/encode.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/encode.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/encode.hpp 2021-05-04 
10:46:55.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/encode.hpp 2021-12-08 
16:09:45.000000000 +0100
@@ -13,6 +13,7 @@
  */
 
 namespace fz {
+class buffer;
 
 /** \brief Converts a hex digit to decimal int
  *
@@ -112,6 +113,7 @@
 /// \brief Encodes raw input string to base64
 std::string FZ_PUBLIC_SYMBOL base64_encode(std::string_view const& in, 
base64_type type = base64_type::standard, bool pad = true);
 std::string FZ_PUBLIC_SYMBOL base64_encode(std::vector<uint8_t> const& in, 
base64_type type = base64_type::standard, bool pad = true);
+std::string FZ_PUBLIC_SYMBOL base64_encode(fz::buffer const& in, base64_type 
type = base64_type::standard, bool pad = true);
 
 /**
  * \brief base64-encodes input and appends it to result.
@@ -128,8 +130,10 @@
  */
 std::vector<uint8_t> FZ_PUBLIC_SYMBOL base64_decode(std::string_view const& 
in);
 std::vector<uint8_t> FZ_PUBLIC_SYMBOL base64_decode(std::wstring_view const& 
in);
+std::vector<uint8_t> FZ_PUBLIC_SYMBOL base64_decode(fz::buffer const& in);
 std::string FZ_PUBLIC_SYMBOL base64_decode_s(std::string_view const& in);
 std::string FZ_PUBLIC_SYMBOL base64_decode_s(std::wstring_view const& in);
+std::string FZ_PUBLIC_SYMBOL base64_decode_s(fz::buffer const& in);
 
 
 /**
@@ -147,6 +151,7 @@
 /// \brief Encodes raw input string to base32
 std::string FZ_PUBLIC_SYMBOL base32_encode(std::string_view const& in, 
base32_type type = base32_type::standard, bool pad = true);
 std::string FZ_PUBLIC_SYMBOL base32_encode(std::vector<uint8_t> const& in, 
base32_type type = base32_type::standard, bool pad = true);
+std::string FZ_PUBLIC_SYMBOL base32_encode(fz::buffer const& in, base32_type 
type = base32_type::standard, bool pad = true);
 
 /**
  * \brief Decodes base32, ignores whitespace. Returns empty string on invalid 
input.
@@ -155,8 +160,10 @@
  */
 std::vector<uint8_t> FZ_PUBLIC_SYMBOL base32_decode(std::string_view const& 
in, base32_type type = base32_type::standard);
 std::vector<uint8_t> FZ_PUBLIC_SYMBOL base32_decode(std::wstring_view const& 
in, base32_type type = base32_type::standard);
+std::vector<uint8_t> FZ_PUBLIC_SYMBOL base32_decode(fz::buffer const& in, 
base32_type type = base32_type::standard);
 std::string FZ_PUBLIC_SYMBOL base32_decode_s(std::string_view const& in, 
base32_type type = base32_type::standard);
 std::string FZ_PUBLIC_SYMBOL base32_decode_s(std::wstring_view const& in, 
base32_type type = base32_type::standard);
+std::string FZ_PUBLIC_SYMBOL base32_decode_s(fz::buffer const& in, base32_type 
type = base32_type::standard);
 
 /**
  * \brief Percent-encodes string.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/glue/unix.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/glue/unix.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/glue/unix.hpp      2021-08-31 
16:47:29.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/glue/unix.hpp      2021-12-08 
16:09:45.000000000 +0100
@@ -11,7 +11,11 @@
 
 namespace fz {
 
-/// Sets FD_CLOEXEC on file descriptor
+/**
+ * \brief Sets FD_CLOEXEC on file descriptor
+ *
+ * If you use this function, you probably also want to use \ref fz::forkblock
+ */
 bool FZ_PUBLIC_SYMBOL set_cloexec(int fd);
 
 /**
@@ -22,7 +26,7 @@
  *
  * On failure sets fds to -1.
  */
-bool FZ_PUBLIC_SYMBOL create_pipe(int fds[2], bool require_atomic_creation = 
false);
+bool FZ_PUBLIC_SYMBOL create_pipe(int fds[2]);
 
 /** \brief Disables SIGPIPE
  *
@@ -30,7 +34,6 @@
  */
 void FZ_PUBLIC_SYMBOL disable_sigpipe();
 
-#if FZ_UNIX
 /// Creates a connected pair of unix domain sockets of SOCK_STREAM type
 bool FZ_PUBLIC_SYMBOL create_socketpair(int fds[2]);
 
@@ -61,8 +64,6 @@
  * fd is set to -1.
  */
 int FZ_PUBLIC_SYMBOL read_fd(int socket, fz::buffer & buf, int &fd, int & 
error);
-#endif
-
 }
 
 #else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libfilezilla-0.34.2/lib/libfilezilla/impersonation.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/impersonation.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/impersonation.hpp  2021-09-29 
14:07:07.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/impersonation.hpp  2021-12-08 
16:09:59.000000000 +0100
@@ -7,14 +7,12 @@
 
 #include "string.hpp"
 
-#if FZ_UNIX || FZ_WINDOWS
-
 #include <memory>
 #include <functional>
 
 namespace fz {
 
-#if FZ_UNIX
+#if !FZ_WINDOWS
 enum class impersonation_flag
 {
        pwless /// Impersonate as any user without checking credentials
@@ -42,7 +40,7 @@
        /// Creates an impersonation token, verifying credentials in the 
proceess
        explicit impersonation_token(fz::native_string const& username, 
fz::native_string const& password);
 
-#if FZ_UNIX
+#if !FZ_WINDOWS
        /// Doesn't verify credentials
        explicit impersonation_token(fz::native_string const& username, 
impersonation_flag flag);
 #endif
@@ -70,7 +68,7 @@
        std::unique_ptr<impersonation_token_impl> impl_;
 };
 
-#if FZ_UNIX
+#if !FZ_WINDOWS
 /// Applies to the entire current process, calls setuid/setgid
 bool FZ_PUBLIC_SYMBOL set_process_impersonation(impersonation_token const& 
token);
 #endif
@@ -90,6 +88,5 @@
 };
 
 }
-#endif
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/json.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/json.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/json.hpp   2021-08-31 
16:47:29.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/json.hpp   2021-12-08 
16:09:45.000000000 +0100
@@ -128,13 +128,22 @@
 
        explicit operator bool() const { return type_ != json_type::none; }
 
-       /** \brief Serializes JSONS structure
+       /** \brief Serializes JSON structure
         *
         * Children of objects with none type are ignored.
         * Children of arrays with none type are serialized as null.
         */
        std::string to_string(bool pretty = false, size_t depth = 0) const;
 
+       /** \brief Serializes JSON structure
+        *
+        * Children of objects with none type are ignored.
+        * Children of arrays with none type are serialized as null.
+        *
+        * Does not clear output string
+        */
+       void to_string(std::string & ret, bool pretty = false, size_t depth = 
0) const;
+
        /** \brief Parses JSON structure from input.
         *
         * Returns none if there is any null-byte in the input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libfilezilla-0.34.2/lib/libfilezilla/local_filesys.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/local_filesys.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/local_filesys.hpp  2021-10-26 
13:54:12.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/local_filesys.hpp  2021-12-08 
16:10:13.000000000 +0100
@@ -86,7 +86,7 @@
         * Takes ownership of the HANDLE.
         */
        result begin_find_files(HANDLE dir, bool dirs_only = false, bool 
query_symlink_targets = true);
-#elif FZ_UNIX
+#else
        /**
         * \brief Begin enumerating a directory represented by a file 
descriptor.
         *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/optional.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/optional.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/optional.hpp       2020-10-13 
14:16:49.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/optional.hpp       2021-12-08 
16:09:45.000000000 +0100
@@ -19,11 +19,11 @@
 class sparse_optional final
 {
 public:
-       sparse_optional();
+       sparse_optional() noexcept = default;
        explicit sparse_optional(T const& v);
 
        /// Takes ownership of pointer.
-       explicit sparse_optional(T * v);
+       explicit sparse_optional(T * v) noexcept;
 
        sparse_optional(sparse_optional<T> const& v);
        sparse_optional(sparse_optional<T> && v) noexcept;
@@ -46,16 +46,9 @@
        sparse_optional<T>& operator=(sparse_optional<T> const& v);
        sparse_optional<T>& operator=(sparse_optional<T> && v) noexcept;
 private:
-       T* v_;
+       T* v_{};
 };
 
-
-template<typename T>
-sparse_optional<T>::sparse_optional()
-       : v_()
-{
-}
-
 template<typename T>
 sparse_optional<T>::sparse_optional(T const& v)
        : v_(new T(v))
@@ -63,7 +56,7 @@
 }
 
 template<typename T>
-sparse_optional<T>::sparse_optional(T * v)
+sparse_optional<T>::sparse_optional(T * v) noexcept
        : v_(v)
 {
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/process.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/process.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/process.hpp        2021-09-29 
14:07:07.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/process.hpp        2021-12-08 
16:09:45.000000000 +0100
@@ -118,6 +118,27 @@
  */
 bool FZ_PUBLIC_SYMBOL spawn_detached_process(std::vector<native_string> const& 
cmd_with_args);
 
+#if !FZ_WINDOWS
+/** \brief Temporarily suppress fork() if CLOEXEC cannot be set atomically at 
creation
+ *
+ * fz::process::spawn() will wait until there is no forkblock.
+ *
+ * In case of a wild fork() in third-party code, pthread_atfork handlers will 
enforce a wait.
+ * This may deadlock. Behavior is undefined if fork is called from a signal 
handler.
+ *
+ * If you fork while the current thread holds a forklock, the child will 
immediately exit.
+ */
+class FZ_PUBLIC_SYMBOL forkblock final
+{
+public:
+       forkblock();
+       ~forkblock();
+
+       forkblock(forkblock const&) = delete;
+       forkblock& operator=(forkblock const&) = delete;
+};
+#endif
+
 }
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/libfilezilla/tls_layer.hpp 
new/libfilezilla-0.35.0/lib/libfilezilla/tls_layer.hpp
--- old/libfilezilla-0.34.2/lib/libfilezilla/tls_layer.hpp      2021-09-14 
14:31:26.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/libfilezilla/tls_layer.hpp      2021-12-08 
16:09:45.000000000 +0100
@@ -211,6 +211,22 @@
         */
        int new_session_ticket();
 
+       /** \brief Sets a callback to control whether unexpected eof is seen as 
error
+        *
+        * With TLS, an EOF on the socket prior to receiving a closure alert 
normally is an error.
+        * In many cases this is harmless though, e.g. if the connection is 
idle.
+        *
+        * If this callback is set, premature termination is no longer seen as 
error if the
+        * callback returns false.
+        *
+        * Callback must not call any tls_layer function.
+        *
+        * Only controls the layer's own logging. Functions such as read will 
still return
+        * ECONNABORTED.
+        */
+       void set_unexpected_eof_cb(std::function<bool()> const& cb);
+       void set_unexpected_eof_cb(std::function<bool()> && cb);
+
        virtual socket_state get_state() const override;
 
        virtual int connect(native_string const& host, unsigned int port, 
address_type family = address_type::unknown) override;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/local_filesys.cpp 
new/libfilezilla-0.35.0/lib/local_filesys.cpp
--- old/libfilezilla-0.34.2/lib/local_filesys.cpp       2021-10-26 
13:54:12.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/local_filesys.cpp       2021-11-02 
15:59:45.000000000 +0100
@@ -438,7 +438,7 @@
        buffer_.resize(64 * 1024);
        return {result::ok};
 }
-#elif FZ_UNIX
+#else
 result local_filesys::begin_find_files(int fd, bool dirs_only, bool 
query_symlink_targets)
 {
        end_find_files();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/process.cpp 
new/libfilezilla-0.35.0/lib/process.cpp
--- old/libfilezilla-0.34.2/lib/process.cpp     2021-10-11 10:03:36.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/process.cpp     2021-12-08 16:09:45.000000000 
+0100
@@ -263,6 +263,7 @@
 #else
 
 #include "libfilezilla/glue/unix.hpp"
+#include "libfilezilla/mutex.hpp"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -271,6 +272,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <atomic>
 #include <memory>
 #include <vector>
 
@@ -308,12 +310,12 @@
        pipe(pipe const&) = delete;
        pipe& operator=(pipe const&) = delete;
 
-       bool create(bool require_atomic_creation = false)
+       bool create()
        {
                reset();
 
                int fds[2];
-               if (!create_pipe(fds, require_atomic_creation)) {
+               if (!create_pipe(fds)) {
                        return false;
                }
 
@@ -359,6 +361,9 @@
        }
        *v = nullptr;
 }
+
+std::atomic<unsigned int> forkblocks_{};
+mutex forkblock_mtx_;
 }
 
 class process::impl
@@ -395,6 +400,7 @@
                std::unique_ptr<char *[]> argV;
                get_argv(cmd, begin, end, argList, argV);
 
+               scoped_lock l(forkblock_mtx_);
                pid_t pid = fork();
                if (pid < 0) {
                        return false;
@@ -429,15 +435,11 @@
                                }
                        }
 
-#if FZ_UNIX
                        if (it && *it) {
                                if (!set_process_impersonation(*it)) {
                                        _exit(1);
                                }
                        }
-#else
-                       (void)it;
-#endif
 
                        // Execute process
                        execv(cmd.c_str(), argV.get()); // noreturn on success
@@ -777,12 +779,14 @@
        pid_t const parent = getppid();
        pid_t const ppgid = getpgid(parent);
 
+       scoped_lock l(forkblock_mtx_);
+
        // We're using a pipe created with O_CLOEXEC to signal failure from 
execv.
-       // Note that this flags must be set atomically, setting FD_CLOEXEC 
after creation
-       // leads to a deadlock if a different thread calls exec in-between.
-       // Unfortunately even in early 2020, macOS does not have pipe2.
+       // Fortunately the forkblock avoids a deadlock if the cloexec flag 
isn't set
+       // atomically and another threa execs in-between, as even in 2022, macOS
+       // doesn't have pipe2.
        pipe errpipe;
-       errpipe.create(true);
+       errpipe.create();
 
        pid_t pid = fork();
        if (!pid) {
@@ -838,4 +842,52 @@
        }
 #endif
 }
+
+#if !FZ_WINDOWS
+forkblock::forkblock()
+{
+       forkblock_mtx_.lock();
+       ++forkblocks_;
+}
+
+forkblock::~forkblock()
+{
+       --forkblocks_;
+       forkblock_mtx_.unlock();
+}
+
+namespace {
+bool forked_child_{};
+void atfork_lock_forkblock()
+{
+       // Unsafe if fork is called from a signal handler
+       if (!forked_child_) {
+               forkblock_mtx_.lock();
+       }
+}
+
+void atfork_unlock_forkblock()
+{
+       // Unsafe if fork is called from a signal handler
+       if (!forked_child_) {
+               forkblock_mtx_.unlock();
+       }
+}
+
+void atfork_check_forkblocks()
+{
+       // Last line of defense.
+       if (forkblocks_) {
+               _exit(1);
+       }
+       forked_child_ = true;
+}
+
+
+int const atfork_registered = []() {
+       return pthread_atfork(&atfork_lock_forkblock, &atfork_unlock_forkblock, 
&atfork_check_forkblocks);
+}();
+}
+#endif
+
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/socket.cpp 
new/libfilezilla-0.35.0/lib/socket.cpp
--- old/libfilezilla-0.34.2/lib/socket.cpp      2021-09-14 14:31:27.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/socket.cpp      2021-12-08 16:09:45.000000000 
+0100
@@ -14,6 +14,7 @@
 
 #ifndef FZ_WINDOWS
   #include "libfilezilla/glue/unix.hpp"
+  #include "libfilezilla/process.hpp"
 
   #define mutex mutex_override // Sadly on some platforms system headers 
include conflicting names
   #include <sys/types.h>
@@ -582,6 +583,9 @@
                if (fd == -1 && errno == EINVAL)
 #endif
                {
+#if !defined(FZ_WINDOWS)
+                       forkblock b;
+#endif
                        fd = ::socket(addr.ai_family, addr.ai_socktype, 
addr.ai_protocol);
 
 #if !defined(FZ_WINDOWS)
@@ -1587,6 +1591,9 @@
                if (fd == -1 && errno == ENOSYS)
 #endif
                {
+#if !defined(FZ_WINDOWS)
+                       forkblock b;
+#endif
                        fd = ::accept(fd_, nullptr, nullptr);
 #if !defined(FZ_WINDOWS)
                        set_cloexec(fd);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/tls_layer.cpp 
new/libfilezilla-0.35.0/lib/tls_layer.cpp
--- old/libfilezilla-0.34.2/lib/tls_layer.cpp   2021-09-14 14:31:27.000000000 
+0200
+++ new/libfilezilla-0.35.0/lib/tls_layer.cpp   2021-12-08 16:09:45.000000000 
+0100
@@ -208,4 +208,19 @@
 {
        return impl_ ? impl_->new_session_ticket() : false;
 }
+
+void tls_layer::set_unexpected_eof_cb(std::function<bool()> const& cb)
+{
+       if (impl_) {
+               std::function<bool()> f = cb;
+               impl_->set_unexpected_eof_cb(std::move(f));
+       }
+}
+
+void tls_layer::set_unexpected_eof_cb(std::function<bool()> && cb)
+{
+       if (impl_) {
+               impl_->set_unexpected_eof_cb(std::move(cb));
+       }
+}
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/tls_layer_impl.cpp 
new/libfilezilla-0.35.0/lib/tls_layer_impl.cpp
--- old/libfilezilla-0.34.2/lib/tls_layer_impl.cpp      2021-10-26 
13:54:12.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/tls_layer_impl.cpp      2021-12-08 
16:09:45.000000000 +0100
@@ -1182,19 +1182,21 @@
 {
        logger_.log(logmsg::debug_debug, L"tls_layer_impl::failure(%d)", code);
        if (code) {
-               log_error(code, function);
-               if (socket_eof_) {
-                       if (code == GNUTLS_E_UNEXPECTED_PACKET_LENGTH
-#ifdef GNUTLS_E_PREMATURE_TERMINATION
-                               || code == GNUTLS_E_PREMATURE_TERMINATION
-#endif
-                               )
-                       {
-                               if (state_ != socket_state::shut_down || 
!shutdown_silence_read_errors_) {
-                                       logger_.log(logmsg::status, server_ ? 
fztranslate("Client did not properly shut down TLS connection") : 
fztranslate("Server did not properly shut down TLS connection"));
-                               }
+               bool suppress{};
+               auto level = logmsg::error;
+               if (socket_eof_ && code == (GNUTLS_E_UNEXPECTED_PACKET_LENGTH 
|| code == GNUTLS_E_PREMATURE_TERMINATION)) {
+                       suppress = state_ == socket_state::shut_down && 
shutdown_silence_read_errors_;
+                       if (!suppress && state_ == socket_state::connected && 
unexpected_eof_cb_) {
+                               suppress = !unexpected_eof_cb_();
+                       }
+                       if (suppress) {
+                               level = logmsg::debug_warning;
                        }
                }
+               log_error(code, function, level);
+               if (!suppress && socket_eof_ && (code == 
GNUTLS_E_UNEXPECTED_PACKET_LENGTH || code == GNUTLS_E_PREMATURE_TERMINATION)) {
+                       logger_.log(logmsg::status, server_ ? 
fztranslate("Client did not properly shut down TLS connection") : 
fztranslate("Server did not properly shut down TLS connection"));
+               }
        }
 
        auto const oldState = state_;
@@ -1281,8 +1283,10 @@
 
 void tls_layer_impl::set_verification_result(bool trusted)
 {
+       logger_.log(logmsg::debug_verbose, L"set_verification_result(%s)", 
trusted ? "true"sv : "false"sv);
+
        if (state_ != socket_state::connecting && !handshake_successful_) {
-               logger_.log(logmsg::debug_warning, L"TrustCurrentCert called at 
wrong time.");
+               logger_.log(logmsg::debug_warning, L"set_verification_result 
called at wrong time.");
                return;
        }
 
@@ -1822,6 +1826,7 @@
                                }
                                systemTrust = true;
                        }
+                       logger_.log(logmsg::debug_verbose, L"System trust store 
decision: %s", systemTrust ? "true"sv : "false"sv);
                }
                else {
                        std::get<1>(lease).unlock();
@@ -1886,8 +1891,6 @@
                        }
                }
 
-               logger_.log(logmsg::status, fztranslate("Verifying 
certificate..."));
-
                std::vector<x509_certificate> certificates;
                certificates.reserve(certs.certs_size);
                for (unsigned int i = 0; i < certs.certs_size; ++i) {
@@ -1954,6 +1957,7 @@
                        hostnameMismatch
                );
 
+               logger_.log(logmsg::debug_verbose, L"Sending 
certificate_verification_event");
                
verification_handler_->send_event<certificate_verification_event>(&tls_layer_, 
std::move(session_info));
 
                return EAGAIN;
@@ -2597,4 +2601,9 @@
        return socket_error_ ? socket_error_ : ECONNABORTED;
 }
 
+void tls_layer_impl::set_unexpected_eof_cb(std::function<bool()> && cb)
+{
+       unexpected_eof_cb_ = std::move(cb);
+}
+
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libfilezilla-0.34.2/lib/tls_layer_impl.hpp 
new/libfilezilla-0.35.0/lib/tls_layer_impl.hpp
--- old/libfilezilla-0.34.2/lib/tls_layer_impl.hpp      2021-09-14 
14:31:27.000000000 +0200
+++ new/libfilezilla-0.35.0/lib/tls_layer_impl.hpp      2021-12-08 
16:09:45.000000000 +0100
@@ -99,6 +99,8 @@
        void set_min_tls_ver(tls_ver ver);
        void set_max_tls_ver(tls_ver ver);
 
+       void set_unexpected_eof_cb(std::function<bool()> && cb);
+
 private:
        bool init();
        void deinit();
@@ -145,6 +147,8 @@
 
        logger_interface & logger_;
 
+       std::function<bool()> unexpected_eof_cb_;
+
        gnutls_session_t session_{};
 
        std::vector<uint8_t> ticket_key_;

Reply via email to