Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package sphinx for openSUSE:Factory checked 
in at 2022-01-29 20:59:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/sphinx (Old)
 and      /work/SRC/openSUSE:Factory/.sphinx.new.1898 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "sphinx"

Sat Jan 29 20:59:29 2022 rev:6 rq:949725 version:2.2.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/sphinx/sphinx.changes    2020-07-27 
17:49:26.335524991 +0200
+++ /work/SRC/openSUSE:Factory/.sphinx.new.1898/sphinx.changes  2022-01-29 
21:00:04.147486015 +0100
@@ -1,0 +2,12 @@
+Thu Jan 27 20:00:41 UTC 2022 - Bruno Friedmann <br...@ioda-net.ch>
+
+- Added CVE-2020-29050.patch for fixing CVE-2020-29050 boo#1195227
+  Source debian and manticoresearch
+- Packaging:
+  + Renew with spec-cleaner -m
+  + Update copyright year
+  + Cleanup older suse version %if construct
+  + Use libmariadb-devel instead mysql-devel
+  + Use %autopatch
+
+-------------------------------------------------------------------

New:
----
  CVE-2020-29050.patch

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

Other differences:
------------------
++++++ sphinx.spec ++++++
--- /var/tmp/diff_new_pack.Dcu4u5/_old  2022-01-29 21:00:04.671482492 +0100
+++ /var/tmp/diff_new_pack.Dcu4u5/_new  2022-01-29 21:00:04.675482466 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package sphinx
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -23,13 +23,6 @@
 %global soname 0_0_1
 # For being able to build for SLE_11
 %{!?_tmpfilesdir:%global _tmpfilesdir %{_prefix}/lib/tmpfiles.d}
-%if 0%{?suse_version} > 1210
-%define has_systemd 1
-BuildRequires:  systemd-rpm-macros
-%{?systemd_ordering}
-%else
-Requires(pre):  %insserv_prereq
-%endif
 Name:           sphinx
 Version:        2.2.11
 Release:        0
@@ -43,11 +36,14 @@
 Patch0:         obs.patch
 Patch2:         sphinx-default_listen.patch
 Patch3:         reproducible.patch
+#CVE-2020-29050 
https://salsa.debian.org/debian/sphinxsearch/-/blob/4d6fe40644130308604845db43d3588e715ec85d/debian/patches/06-CVE-2020-29050.patch
+Patch4:         CVE-2020-29050.patch
 # for fix-ups
 BuildRequires:  dos2unix
 BuildRequires:  gcc-c++
-BuildRequires:  mysql-devel
+BuildRequires:  libmariadb-devel
 BuildRequires:  pkgconfig
+BuildRequires:  systemd-rpm-macros
 BuildRequires:  pkgconfig(expat)
 BuildRequires:  pkgconfig(libecpg) >= 9.6
 BuildRequires:  pkgconfig(libecpg_compat) >= 9.6
@@ -57,16 +53,8 @@
 Requires(pre):  %{_bindir}/getent
 Requires(pre):  %{_sbindir}/useradd
 Provides:       %{daemon}
-%if 0%{?suse_version}
+%{?systemd_ordering}
 Requires(post): %fillup_prereq
-#Requires(pre):  permissions >= 2014.11
-%else
-Requires(post): /sbin/chkconfig
-Requires(postun): /sbin/service
-Requires(preun): /sbin/chkconfig
-Requires(preun): /sbin/service
-%endif
-#
 
 %description
 Sphinx is a standalone search engine providing size-efficient and
@@ -100,15 +88,13 @@
 Pure C searchd client API library
 Sphinx search engine, http://sphinxsearch.com/
 
+
 # Comment
 # we don't package api language java,ruby,php,python
 # upstream don't recommend their usage.
-
 %prep
 %setup -q -n "%{name}-%{version}-release"
-%patch0 -p1
-%patch2 -p1
-%patch3 -p1
+%autopatch -p1
 
 find -type d -name CVS -exec rm -Rf {} +
 
@@ -179,76 +165,34 @@
 }
 EOF
 
-%if 0%{?has_systemd}
 # Create /usr/tempfiles.d/sphinx
 mkdir -p %{buildroot}%{_tmpfilesdir}
 cat > %{buildroot}%{_tmpfilesdir}/%{name}.conf << EOF
 d /run/%{name} 755 sphinx root -
 EOF
-%endif
 
 # systemd vs SysVinit
 mkdir -p %{buildroot}%{_sbindir}
-%if 0%{?has_systemd}
-  install -D -m 644 %{SOURCE1} %{buildroot}%{_unitdir}/%{daemon}.service
-  ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{daemon}
-%else
-#SysVinit
-  install -D %{SOURCE2} %{buildroot}%{_sysconfdir}/init.d/%{daemon}
- %if 0%{?suse_version}
-  ln -sf %{_sysconfdir}/init.d/%{daemon} %{buildroot}%{_sbindir}/rc%{daemon}
- %endif
-%endif
+install -D -m 644 %{SOURCE1} %{buildroot}%{_unitdir}/%{daemon}.service
+ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{daemon}
 
 %pre
 getent group %{sphinx_group} >/dev/null || groupadd -r %{sphinx_group}
 getent passwd %{sphinx_user} >/dev/null || \
 useradd -r -g %{sphinx_group} -d %{sphinx_home} -s /bin/sh \
 -c "Sphinx Searchd daemon" %{sphinx_user}
-%if 0%{?has_systemd}
 %service_add_pre %{daemon}.service
-%endif
 
 %post
-%if 0%{?has_systemd}
 %service_add_post %{daemon}.service
 %{_bindir}/systemd-tmpfiles --create %{_tmpfilesdir}/%{name}.conf || true
-%else
- %if 0%{?suse_version}
-%{fillup_and_insserv -n "%{daemon}"}
- %else
-   /sbin/chkconfig --add %{daemon}
- %endif
-%endif
 
 %preun
-%if 0%{?has_systemd}
 %service_del_preun %{daemon}.service
 %{_bindir}/systemd-tmpfiles --remove %{_tmpfilesdir}/%{name}.conf || true
-%else
- %if 0%{?suse_version}
-%stop_on_removal %{daemon}
- %else
-   if [ $1 = 0 ] ; then
-     service %{daemon} stop >/dev/null 2>&1
-     /sbin/chkconfig --del %{daemon}
-   fi
- %endif
-%endif
 
 %postun
-%if 0%{?has_systemd}
 %service_del_postun %{daemon}.service
-%else
- %if 0%{?suse_version}
-%restart_on_update %{daemon}
-%insserv_cleanup
- %else
-  if [ "$1" -ge "1" ] ; then
-    service %{daemon} restart >/dev/null 2>&1
-  fi
- %endif
-%endif
 
 %post -n libsphinxclient-%{soname} -p /sbin/ldconfig
 %postun -n libsphinxclient-%{soname} -p /sbin/ldconfig
@@ -262,13 +206,9 @@
 %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf
 %config %{_sysconfdir}/%{name}/%{name}.conf.dist
 %config %{_sysconfdir}/%{name}/%{name}-min.conf.dist
-%if 0%{?has_systemd}
 %{_unitdir}/%{daemon}.service
 %{_tmpfilesdir}/%{name}.conf
 %ghost /run/%{name}
-%else
-%{_sysconfdir}/init.d/%{daemon}
-%endif
 %{_sbindir}/rc%{daemon}
 %config %{_sysconfdir}/logrotate.d/%{name}
 %attr(755,root,root) %{_bindir}/spelldump
@@ -284,17 +224,11 @@
 %doc %attr(644, root, man) %{_mandir}/man1/searchd.1*
 %doc %attr(644, root, man) %{_mandir}/man1/spelldump.1*
 %dir %attr(0750, root, %{sphinx_group}) %{_localstatedir}/log/%{name}
-#Doesn't work on SLE_11 :-(
-%if 0%{?suse_version} > 1230
 %ghost %attr(0640, %{sphinx_user}, root) 
%{_localstatedir}/log/%{name}/%{daemon}.log
 %ghost %attr(0640, %{sphinx_user}, root) 
%{_localstatedir}/log/%{name}/query.log
-%endif
 %dir %attr(0755, %{sphinx_user}, %{sphinx_group}) %{_localstatedir}/lib/%{name}
 %dir %attr(0755, %{sphinx_user}, %{sphinx_group}) 
%{_localstatedir}/lib/%{name}/data
 %dir %attr(0755, %{sphinx_user}, %{sphinx_group}) 
%{_localstatedir}/lib/%{name}/data/index
-%dir %attr(0750, root, root) %{_localstatedir}/log/%{name}
-%attr(0640, %{sphinx_user}, root) %{_localstatedir}/log/%{name}/%{daemon}.log
-%attr(0640, %{sphinx_user}, root) %{_localstatedir}/log/%{name}/query.log
 
 %files -n libsphinxclient-%{soname}
 %license COPYING

++++++ CVE-2020-29050.patch ++++++
>From 17245f7dd75d47c7365797b3d5feba8976367c6e Mon Sep 17 00:00:00 2001
From: klirichek <ale...@manticoresearch.com>
Date: Tue, 2 Jul 2019 19:06:09 +0700
Subject: [PATCH] Fix random file reading by scattered snippets

Issue was that load_files_scattered option just concatenated prefix with
given name and then opened the file. So, if you provide something like
'/etc/password' as file, or '../../../etc/passwd' even with non-zero
prefix, it will unfortunately work. After this commit such behavior
possible ONLY if user explicitly set `snippets_file_prefix` to empty
string or '/'; another cases will not cause uncontroled reading.
That fixes #866.

[basilgello: Back-port to 2.2.11:
 - Refactor sphNormalizePath to use only available classes.
 - Do not use 'g_sSnippetsFilePrefix' in src/sphinxexcerpt.h,
   use 'tOptions.m_sFilePrefix' instead, as for 2.2.11, all
   two instances are assigned to 'g_sSnippetsFilePrefix'.
 - Adjust context. ]

The following test passes, adapted from commit
66b5761ad258c60b1866a8e1333f86e74f48035 at
https://github.com/manticoresoftware/manticoresearch :

====
/*
 cd test &&
 g++ -o test test.cpp -I../src -I../config -I/usr/include/postgresql \
        -I/usr/include/mariadb -DHAVE_CONFIG_H -L../src -lsphinx -pthread \
        -lm -ldl -lstemmer -lmariadb -lpq -lexpat -lz
*/

void ASSERT_STREQ(const char *src, const char *dst)
{
        auto normalized = sphNormalizePath(src);
        if (!strcmp(dst, normalized.scstr())) {
                auto _src = src;
                auto _dst = dst;

                if (src == nullptr) _src = "nullptr";
                if (dst == nullptr) _dst = "nullptr";

                std::cout << "OK  : '" << _src << "' = '" << _dst <<
                        "'" << std::endl;
        } else {
                auto _src = src;
                auto _dst = dst;

                if (src == nullptr) _src = "nullptr";
                if (dst == nullptr) _dst = "nullptr";

                std::cout << "FAIL: '" << _src << "' != '" << _dst << "' ( = '" 
<<
                        normalized.scstr() << "')" << std::endl;
        }
}

int main()
{
        ASSERT_STREQ ( "/", "/" );
        ASSERT_STREQ ( "/..//bbb", "/bbb" );
        ASSERT_STREQ ( "/quite/long/path/../../../etc/passwd", "/etc/passwd" );
        ASSERT_STREQ ( "/aaa/bbb/ccc/ddd/../../../../../../../", "/" );

        ASSERT_STREQ ( "",  "" );
        ASSERT_STREQ ( nullptr, "" );
        ASSERT_STREQ ( "aaa/", "aaa" );
        ASSERT_STREQ ( "aaa/.", "aaa" );
        ASSERT_STREQ ( "aaa/././././////././", "aaa" );
        ASSERT_STREQ ( "aaa/////", "aaa" );
        ASSERT_STREQ ( "aaa/bbb/ccc", "aaa/bbb/ccc" );
        ASSERT_STREQ ( "aaa/bbb/ccc/ddd/..", "aaa/bbb/ccc" );
        ASSERT_STREQ ( "aaa/bbb/ccc/ddd/../../..", "aaa" );
        ASSERT_STREQ ( "aaa/bbb/ccc/ddd/../../../xxx", "aaa/xxx" );
        ASSERT_STREQ ( "aaa/bbb/ccc/ddd/../../../..", "" );
        ASSERT_STREQ ( "aaa/bbb/ccc/ddd/../../../../", "" );
        ASSERT_STREQ ( "aaa/bbb/ccc/ddd/../../../../../../../", "../../.." );
        ASSERT_STREQ ( "..//bbb", "../bbb" );
        return 0;
}
====

Fixes CVE-2020-29050.

Signed-off-by: Vasyl Gello <vasek.ge...@gmail.com>
---
 doc/sphinx.html        | 19 ++++++++++-
 doc/sphinx.txt         | 19 ++++++++++-
 sphinx.conf.in         |  4 +--
 src/searchd.cpp        |  8 ++++-
 src/sphinx.cpp         | 71 ++++++++++++++++++++++++++++++++++++++++++
 src/sphinxexcerpt.cpp  | 14 +++++++++
 src/sphinxexcerpt.h    |  3 ++
 src/sphinxstd.h        |  3 ++
 test/test_130/test.xml |  7 +++--
 9 files changed, 140 insertions(+), 8 deletions(-)

diff --git a/doc/sphinx.html b/doc/sphinx.html
index b56e445..8ad44dd 100644
--- a/doc/sphinx.html
+++ b/doc/sphinx.html
@@ -11652,7 +11652,7 @@ binlog_max_log_size = 16M
 <div class="sect2" title="12.4.28.&nbsp;snippets_file_prefix"><div 
class="titlepage"><div><div><h3 class="title"><a 
name="conf-snippets-file-prefix"></a>12.4.28.&nbsp;snippets_file_prefix</h3></div></div></div>
 <p>
 A prefix to prepend to the local file names when generating snippets.
-Optional, default is empty.
+Optional, default is current working folder.
 Introduced in version 2.1.1-beta.
 </p><p>
 This prefix can be used in distributed snippets generation along with
@@ -11663,6 +11663,19 @@ is set to "server1" and the request refers to 
"file23", <code class="filename">s
 will attempt to open "server1file23" (all of that without quotes). So if you
 need it to be a path, you have to mention the trailing slash.
 </p><p>
+After constructing final file path, daemon unwinds all relative dirs and
+compares final result with the value of ``snippet_file_prefix``. If result
+is not begin with the prefix, such file will be rejected with error message.
+
+So, if you set it to '/mnt/data' and somebody calls snippet generation with 
file
+'../../../etc/passwd', as the source, it will get error message
+`File '/mnt/data/../../../etc/passwd' escapes '/mnt/data/' scope`
+instead of content of the file.
+
+Also, with non-set parameter and reading '/etc/passwd' it will actually read
+/daemon/working/folder/etc/passwd since default for param is exactly daemon's
+working folder.
+</p><p>
 Note also that this is a local option, it does not affect the agents anyhow.
 So you can safely set a prefix on a master server. The requests routed to the
 agents will not be affected by the master's setting. They will however be 
affected
@@ -11673,6 +11686,10 @@ This might be useful, for instance, when the document 
storage locations
 </p><h4><a name="idp33320288"></a>Example:</h4><pre class="programlisting">
 snippets_file_prefix = /mnt/common/server1/
 </pre></div>
+<p><span class="bold"><strong>WARNING:</strong></span>
+If you still want to access files from the FS root, you have to explicitly set
+'snippets_file_prefix' to empty value (by 'snippets_file_prefix=' line), or to
+root (by 'snippets_file_prefix=/').
 <div class="sect2" title="12.4.29.&nbsp;collation_server"><div 
class="titlepage"><div><div><h3 class="title"><a 
name="conf-collation-server"></a>12.4.29.&nbsp;collation_server</h3></div></div></div>
 <p>
 Default server collation.
diff --git a/doc/sphinx.txt b/doc/sphinx.txt
index ed994f9..f750f4e 100644
--- a/doc/sphinx.txt
+++ b/doc/sphinx.txt
@@ -12832,7 +12832,7 @@ Example:
 -----------------------------
 
 A prefix to prepend to the local file names when generating snippets.
-Optional, default is empty. Introduced in version 2.1.1-beta.
+Optional, default is current working folder. Introduced in version 2.1.1-beta.
 
 This prefix can be used in distributed snippets generation along with
 load_files or load_files_scattered options.
@@ -12842,6 +12842,19 @@ to "server1" and the request refers to "file23", 
searchd will attempt to
 open "server1file23" (all of that without quotes). So if you need it to be
 a path, you have to mention the trailing slash.
 
+After constructing final file path, daemon unwinds all relative dirs and
+compares final result with the value of ``snippet_file_prefix``. If result
+is not begin with the prefix, such file will be rejected with error message.
+
+So, if you set it to '/mnt/data' and somebody calls snippet generation with 
file
+'../../../etc/passwd', as the source, it will get error message
+`File '/mnt/data/../../../etc/passwd' escapes '/mnt/data/' scope`
+instead of content of the file.
+
+Also, with non-set parameter and reading '/etc/passwd' it will actually read
+/daemon/working/folder/etc/passwd since default for param is exactly daemon's
+working folder.
+
 Note also that this is a local option, it does not affect the agents
 anyhow. So you can safely set a prefix on a master server. The requests
 routed to the agents will not be affected by the master's setting. They
@@ -12855,6 +12868,10 @@ Example:
 
    | snippets_file_prefix = /mnt/common/server1/
 
+WARNING: If you still want to access files from the FS root, you have to
+explicitly set 'snippets_file_prefix' to empty value (by 
'snippets_file_prefix='
+line), or to root (by 'snippets_file_prefix=/').
+
 12.4.29. collation_server
 -------------------------
 
diff --git a/sphinx.conf.in b/sphinx.conf.in
index 6ba2dc9..527bbd8 100644
--- a/sphinx.conf.in
+++ b/sphinx.conf.in
@@ -604,7 +604,7 @@ index test1
        # snippet document file name prefix
        # preprended to file names when generating snippets using load_files 
option
        # WARNING, this is a prefix (not a path), trailing slash matters!
-       # optional, default is empty
+       # optional, default is current working directory of a running process
        #
        # snippets_file_prefix  = /mnt/mydocs/server1
 
@@ -1042,7 +1042,7 @@ searchd
 
        # a prefix to prepend to the local file names when creating snippets
        # with load_files and/or load_files_scatter options
-       # optional, default is empty
+       # optional, default is current working directory of a running process
        #
        # snippets_file_prefix          = /mnt/common/server1/
 }
diff --git a/src/searchd.cpp b/src/searchd.cpp
index 85b1cd6..6462b16 100644
--- a/src/searchd.cpp
+++ b/src/searchd.cpp
@@ -13330,6 +13330,12 @@ bool MakeSnippets ( CSphString sIndex, 
CSphVector<ExcerptQuery_t> & dQueries, CS
                                struct stat st;
                                CSphString sFilename;
                                sFilename.SetSprintf ( "%s%s", 
g_sSnippetsFilePrefix.cstr(), dQueries[i].m_sSource.cstr() );
+                               if ( !TestEscaping ( g_sSnippetsFilePrefix, 
sFilename ))
+                               {
+                                       sError.SetSprintf( "File '%s' escapes 
'%s' scope",
+                                               sFilename.scstr(), 
g_sSnippetsFilePrefix.scstr());
+                                       return false;
+                               }
                                if ( ::stat ( sFilename.cstr(), &st )<0 )
                                {
                                        if ( !bScattered )
@@ -23719,7 +23725,7 @@ int WINAPI ServiceMain ( int argc, char **argv )
        if ( hSearchd.Exists ( "snippets_file_prefix" ) )
                g_sSnippetsFilePrefix = hSearchd["snippets_file_prefix"].cstr();
        else
-               g_sSnippetsFilePrefix = "";
+               g_sSnippetsFilePrefix.SetSprintf("%s/", sphGetCwd().scstr());
 
        const char* sLogFormat = hSearchd.GetStr ( "query_log_format", "plain" 
);
        if ( !strcmp ( sLogFormat, "sphinxql" ) )
diff --git a/src/sphinx.cpp b/src/sphinx.cpp
index d6a7b9d..492c908 100644
--- a/src/sphinx.cpp
+++ b/src/sphinx.cpp
@@ -81,9 +81,11 @@
        #include <io.h> // for open()
 
        // workaround Windows quirks
+       #include <direct.h>
        #define popen           _popen
        #define pclose          _pclose
        #define snprintf        _snprintf
+       #define getcwd          _getcwd
        #define sphSeek         _lseeki64
 
        #define stat            _stat64
@@ -12420,6 +12422,75 @@ static bool sphTruncate ( int iFD )
 #endif
 }
 
+CSphString sphNormalizePath( const CSphString& sOrigPath )
+{
+       CSphVector<CSphString> dChunks;
+       const char* sBegin = sOrigPath.scstr();
+       const char* sEnd = sBegin + sOrigPath.Length();
+       const char* sPath = sBegin;
+       int iLevel = 0;
+
+       while ( sPath<sEnd )
+       {
+               const char* sSlash = ( char* ) memchr( sPath, '/', sEnd - sPath 
);
+               if ( !sSlash )
+                       sSlash = sEnd;
+
+               auto iChunkLen = sSlash - sPath;
+
+               switch ( iChunkLen )
+               {
+               case 0: // empty chunk skipped
+                       ++sPath;
+                       continue;
+               case 1: // simple dot chunk skipped
+                       if ( *sPath=='.' )
+                       {
+                               sPath += 2;
+                               continue;
+                       }
+                       break;
+               case 2: // double dot abandons chunks, then decrease level
+                       if ( sPath[0]=='.' && sPath[1]=='.' )
+                       {
+                               if ( dChunks.GetLength() <= 0 )
+                                       --iLevel;
+                               else
+                                       dChunks.Pop();
+                               sPath += 3;
+                               continue;
+                       }
+               default: break;
+               }
+               CSphString temp( "" );
+               temp.SetBinary( sPath, iChunkLen );
+               dChunks.Add( temp );
+               sPath = sSlash + 1;
+       }
+
+       CSphStringBuilder sResult;
+       if ( *sBegin=='/' )
+               sResult += "/";
+       else
+               while ( iLevel++<0 )
+                       dChunks.Insert(0, "..");
+
+       int i;
+       for ( i=0; i<dChunks.GetLength(); i++ ) {
+               sResult += dChunks[i].scstr();
+               if (i<dChunks.GetLength()-1)
+                       sResult += "/";
+       }
+
+       return sResult.cstr();
+}
+
+CSphString sphGetCwd()
+{
+       CSphVector<char> sBuf (65536);
+       return getcwd( sBuf.Begin(), sBuf.GetLength());
+}
+
 class DeleteOnFail : public ISphNoncopyable
 {
 public:
diff --git a/src/sphinxexcerpt.cpp b/src/sphinxexcerpt.cpp
index b42c6a2..ff593f0 100644
--- a/src/sphinxexcerpt.cpp
+++ b/src/sphinxexcerpt.cpp
@@ -3817,6 +3817,11 @@ void sphBuildExcerpt ( ExcerptQuery_t & tOptions, const 
CSphIndex * pIndex, cons
                {
                        CSphString sFilename;
                        sFilename.SetSprintf ( "%s%s", 
tOptions.m_sFilePrefix.cstr(), tOptions.m_sSource.cstr() );
+                       if ( !TestEscaping( tOptions.m_sFilePrefix.scstr(), 
sFilename ))
+                       {
+                               sError.SetSprintf( "File '%s' escapes '%s' 
scope", sFilename.scstr(), tOptions.m_sFilePrefix.scstr());
+                               return;
+                       }
                        if ( tFile.Open ( sFilename.cstr(), SPH_O_READ, sError 
)<0 )
                                return;
                } else if ( tOptions.m_sSource.IsEmpty() )
@@ -3859,6 +3864,15 @@ void sphBuildExcerpt ( ExcerptQuery_t & tOptions, const 
CSphIndex * pIndex, cons
                sWarning, sError, pQueryTokenizer, tOptions.m_dRes );
 }
 
+// check whether filepath from sPath does not escape area of sPrefix
+bool TestEscaping( const CSphString& sPrefix, const CSphString& sPath )
+{
+       if ( sPrefix.IsEmpty() || sPrefix==sPath )
+               return true;
+       auto sNormalized = sphNormalizePath( sPath );
+       return sPrefix==sNormalized.SubString( 0, sPrefix.Length());
+}
+
 //
 // $Id$
 //
diff --git a/src/sphinxexcerpt.h b/src/sphinxexcerpt.h
index cf48b1f..87a55d4 100644
--- a/src/sphinxexcerpt.h
+++ b/src/sphinxexcerpt.h
@@ -81,6 +81,9 @@ struct XQQuery_t;
 void sphBuildExcerpt ( ExcerptQuery_t & tOptions, const CSphIndex * pIndex, 
const CSphHTMLStripper * pStripper, const XQQuery_t & tExtQuery,
                                                DWORD eExtQuerySPZ, CSphString 
& sWarning, CSphString & sError, CSphDict * pDict, ISphTokenizer * 
pDocTokenizer, ISphTokenizer * pQueryTokenizer );
 
+// helper whether filepath from sPath does not escape area of sPrefix
+bool TestEscaping( const CSphString& sPrefix, const CSphString& sPath );
+
 #endif // _sphinxexcerpt_
 
 //
diff --git a/src/sphinxstd.h b/src/sphinxstd.h
index 39cc7ee..c1f15c1 100644
--- a/src/sphinxstd.h
+++ b/src/sphinxstd.h
@@ -2294,6 +2294,9 @@ int                               sphOpenFile ( const 
char * sFile, CSphString & sError );
 /// return size of file descriptor
 int64_t                        sphGetFileSize ( int iFD, CSphString & sError );
 
+// unwind different tricks like "../../../etc/passwd"
+CSphString             sphNormalizePath ( const CSphString& sOrigPath );
+CSphString             sphGetCwd();
 
 /// buffer trait that neither own buffer nor clean-up it on destroy
 template < typename T >
diff --git a/test/test_130/test.xml b/test/test_130/test.xml
index d8f746c..41e4961 100644
--- a/test/test_130/test.xml
+++ b/test/test_130/test.xml
@@ -7,6 +7,7 @@
 searchd
 {
        <searchd_settings/>
+       snippets_file_prefix=<this_test/>/
 }
 
 source test
@@ -30,15 +31,15 @@ index test
 
 $results = array();
 
-$docs = array( 'test_130/load_file.txt' );
+$docs = array( "load_file.txt" );
 $opts = array( 'load_files'=>true, 'limit'=>0 );
 
 $results[] = $client->BuildExcerpts($docs, 'test', 'end point', $opts );
 $results[] = $client->BuildExcerpts($docs, 'test', 'not_found', $opts );
-$results[] = $client->BuildExcerpts(array( 'test_130/empty.txt' ), 'test', 
'end point', $opts );
+$results[] = $client->BuildExcerpts(array( 'empty.txt' ), 'test', 'end point', 
$opts );
 $results[] = $client->BuildExcerpts(array( '' ), 'test', 'not_found', $opts );
 $results[] = $client->GetLastError();
-$results[] = $client->BuildExcerpts ( array ( 'test_130/512k.xml' ), 'test', 
'it builds', array ( "limit" => 100, "load_files" => true ) );
+$results[] = $client->BuildExcerpts ( array ( '512k.xml' ), 'test', 'it 
builds', array ( "limit" => 100, "load_files" => true ) );
 
 ]]></custom_test>
 
-- 
2.17.1

Reply via email to