diff --git a/SOURCES/subversion-1.7.14-r1439592+.patch b/SOURCES/subversion-1.7.14-r1439592+.patch new file mode 100644 index 0000000..d95ed6b --- /dev/null +++ b/SOURCES/subversion-1.7.14-r1439592+.patch @@ -0,0 +1,63 @@ +# ./pullrev.sh 1439592 1447513 + +http://svn.apache.org/viewvc?view=revision&revision=1439592 +http://svn.apache.org/viewvc?view=revision&revision=1447513 + +https://bugzilla.redhat.com/show_bug.cgi?id=1379593 + +--- subversion-1.7.14/tools/hook-scripts/mailer/mailer.conf.example ++++ subversion-1.7.14/tools/hook-scripts/mailer/mailer.conf.example +@@ -146,7 +146,16 @@ + # + # from_addr = %(author)s@example.com + # ++# The substitution variable "repos_basename" is provided, and is set to ++# the directory name of the repository. This can be useful to set ++# a custom subject that can be re-used in multiple repositories: + # ++# commit_subject_prefix = [svn-%(repos_basename)s] ++# ++# For example if the repository is at /path/to/repo/project-x then ++# the subject of commit emails will be prefixed with [svn-project-x] ++# ++# + # SUMMARY + # + # While mailer.py will work to minimize the number of mail messages +--- subversion-1.7.14/tools/hook-scripts/mailer/mailer.py ++++ subversion-1.7.14/tools/hook-scripts/mailer/mailer.py +@@ -98,7 +98,10 @@ + if cmd == 'commit': + revision = int(cmd_args[0]) + repos = Repository(repos_dir, revision, pool) +- cfg = Config(config_fname, repos, { 'author' : repos.author }) ++ cfg = Config(config_fname, repos, ++ {'author': repos.author, ++ 'repos_basename': os.path.basename(repos.repos_dir) ++ }) + messenger = Commit(pool, cfg, repos) + elif cmd == 'propchange' or cmd == 'propchange2': + revision = int(cmd_args[0]) +@@ -108,14 +111,20 @@ + repos = Repository(repos_dir, revision, pool) + # Override the repos revision author with the author of the propchange + repos.author = author +- cfg = Config(config_fname, repos, { 'author' : author }) ++ cfg = Config(config_fname, repos, ++ {'author': author, ++ 'repos_basename': os.path.basename(repos.repos_dir) ++ }) + messenger = PropChange(pool, cfg, repos, author, propname, action) + elif cmd == 'lock' or cmd == 'unlock': + author = cmd_args[0] + repos = Repository(repos_dir, 0, pool) ### any old revision will do + # Override the repos revision author with the author of the lock/unlock + repos.author = author +- cfg = Config(config_fname, repos, { 'author' : author }) ++ cfg = Config(config_fname, repos, ++ {'author': author, ++ 'repos_basename': os.path.basename(repos.repos_dir) ++ }) + messenger = Lock(pool, cfg, repos, author, cmd == 'lock') + else: + raise UnknownSubcommand(cmd) diff --git a/SOURCES/subversion-1.7.14-r1564900.patch b/SOURCES/subversion-1.7.14-r1564900.patch new file mode 100644 index 0000000..ff7b575 --- /dev/null +++ b/SOURCES/subversion-1.7.14-r1564900.patch @@ -0,0 +1,367 @@ +# ./pullrev.sh r1564900 + +http://svn.apache.org/viewvc?view=revision&revision=r1564900 + +https://bugzilla.redhat.com/show_bug.cgi?id=1378178 + +--- subversion-1.7.14/subversion/tests/cmdline/diff_tests.py ++++ subversion-1.7.14/subversion/tests/cmdline/diff_tests.py +@@ -45,16 +45,39 @@ + ###################################################################### + # Generate expected output + +-def make_diff_header(path, old_tag, new_tag): ++def is_absolute_url(target): ++ return (target.startswith('file://') ++ or target.startswith('http://') ++ or target.startswith('https://') ++ or target.startswith('svn://') ++ or target.startswith('svn+ssh://')) ++ ++def make_diff_header(path, old_tag, new_tag, src_label=None, dst_label=None): + """Generate the expected diff header for file PATH, with its old and new +- versions described in parentheses by OLD_TAG and NEW_TAG. Return the header +- as an array of newline-terminated strings.""" ++ versions described in parentheses by OLD_TAG and NEW_TAG. SRC_LABEL and ++ DST_LABEL are paths or urls that are added to the diff labels if we're ++ diffing against the repository or diffing two arbitrary paths. ++ Return the header as an array of newline-terminated strings.""" ++ if src_label: ++ src_label = src_label.replace('\\', '/') ++ if not is_absolute_url(src_label): ++ src_label = '.../' + src_label ++ src_label = '\t(' + src_label + ')' ++ else: ++ src_label = '' ++ if dst_label: ++ dst_label = dst_label.replace('\\', '/') ++ if not is_absolute_url(dst_label): ++ dst_label = '.../' + dst_label ++ dst_label = '\t(' + dst_label + ')' ++ else: ++ dst_label = '' + path_as_shown = path.replace('\\', '/') + return [ + "Index: " + path_as_shown + "\n", + "===================================================================\n", +- "--- " + path_as_shown + "\t(" + old_tag + ")\n", +- "+++ " + path_as_shown + "\t(" + new_tag + ")\n", ++ "--- " + path_as_shown + src_label + "\t(" + old_tag + ")\n", ++ "+++ " + path_as_shown + dst_label + "\t(" + new_tag + ")\n", + ] + + def make_no_diff_deleted_header(path, old_tag, new_tag): +@@ -3867,6 +3890,122 @@ + 'diff', '-c2', + sbox.repo_url + '/A/D/H') + ++@Issue(4460) ++def diff_repo_wc_file_props(sbox): ++ "diff repo to wc file target with props" ++ sbox.build() ++ iota = sbox.ospath('iota') ++ ++ # add a mime-type and a line to iota to test the binary check ++ sbox.simple_propset('svn:mime-type', 'text/plain', 'iota') ++ sbox.simple_append('iota','second line\n') ++ ++ # test that we get the line and the property add ++ expected_output = make_diff_header(iota, 'revision 1', 'working copy') + \ ++ [ '@@ -1 +1,2 @@\n', ++ " This is the file 'iota'.\n", ++ "+second line\n", ] + \ ++ make_diff_prop_header(iota) + \ ++ make_diff_prop_added('svn:mime-type', 'text/plain') ++ svntest.actions.run_and_verify_svn(None, expected_output, [], ++ 'diff', '-r1', iota) ++ ++ # reverse the diff, should get a property delete and line delete ++ # skip actually testing the output since apparently 1.7 is busted ++ # this isn't related to issue #4460, older versions of 1.7 had the issue ++ # as well ++ #expected_output = make_diff_header(iota, 'working copy', 'revision 1') + \ ++ # [ '@@ -1,2 +1 @@\n', ++ # " This is the file 'iota'.\n", ++ # "-second line\n", ] + \ ++ # make_diff_prop_header(iota) + \ ++ # make_diff_prop_deleted('svn:mime-type', 'text/plain') ++ expected_output = None ++ svntest.actions.run_and_verify_svn(None, expected_output, [], ++ 'diff', '--old', iota, ++ '--new', iota + '@1') ++ ++ # copy iota to test with --show-copies as adds ++ sbox.simple_copy('iota', 'iota_copy') ++ iota_copy = sbox.ospath('iota_copy') ++ ++ # test that we get all lines as added and the property added ++ # TODO: We only test that this test doesn't error out because of Issue #4464 ++ # if and when that issue is fixed this test should check output ++ svntest.actions.run_and_verify_svn(None, None, [], 'diff', ++ '--show-copies-as-adds', '-r1', iota_copy) ++ ++ # reverse the diff, should get all lines as a delete and no property ++ # TODO: We only test that this test doesn't error out because of Issue #4464 ++ # if and when that issue is fixed this test should check output ++ svntest.actions.run_and_verify_svn(None, None, [], 'diff', ++ '--show-copies-as-adds', ++ '--old', iota_copy, ++ '--new', iota + '@1') ++ ++ # revert and commit with the eol-style of LF and then update so ++ # that we can see a change on either windows or *nix. ++ sbox.simple_revert('iota', 'iota_copy') ++ sbox.simple_propset('svn:eol-style', 'LF', 'iota') ++ sbox.simple_commit() #r2 ++ sbox.simple_update() ++ ++ # now that we have a LF file on disk switch to CRLF ++ sbox.simple_propset('svn:eol-style', 'CRLF', 'iota') ++ ++ # test that not only the property but also the file changes ++ # i.e. that the line endings substitution works ++ if svntest.main.is_os_windows(): ++ # test suite normalizes crlf output into just lf on Windows. ++ # so we have to assume it worked because there is an add and ++ # remove line with the same content. Fortunately, it does't ++ # do this on *nix so we can be pretty sure that it works right. ++ # TODO: Provide a way to handle this better ++ crlf = '\n' ++ else: ++ crlf = '\r\n' ++ expected_output = make_diff_header(iota, 'revision 1', 'working copy') + \ ++ [ '@@ -1 +1 @@\n', ++ "-This is the file 'iota'.\n", ++ "+This is the file 'iota'." + crlf ] + \ ++ make_diff_prop_header(iota) + \ ++ make_diff_prop_added('svn:eol-style', 'CRLF') ++ ++ svntest.actions.run_and_verify_svn(None, expected_output, [], ++ 'diff', '-r1', iota) ++ ++ ++@Issue(4460) ++def diff_repo_repo_added_file_mime_type(sbox): ++ "diff repo to repo added file with mime-type" ++ sbox.build() ++ wc_dir = sbox.wc_dir ++ newfile = sbox.ospath('newfile') ++ ++ # add a file with a mime-type ++ sbox.simple_append('newfile', "This is the file 'newfile'.\n") ++ sbox.simple_add('newfile') ++ sbox.simple_propset('svn:mime-type', 'text/plain', 'newfile') ++ sbox.simple_commit() # r2 ++ ++ # try to diff across the addition ++ expected_output = make_diff_header(newfile, 'revision 1', 'revision 2') + \ ++ [ '@@ -0,0 +1 @@\n', ++ "+This is the file 'newfile'.\n" ] + \ ++ make_diff_prop_header(newfile) + \ ++ make_diff_prop_added('svn:mime-type', 'text/plain') ++ ++ svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff', ++ '-r1:2', newfile) ++ ++ # reverse the diff to diff across a deletion ++ # Note no property delete is printed when whole file is deleted ++ expected_output = make_diff_header(newfile, 'revision 2', 'revision 1') + \ ++ [ '@@ -1, +0,0 @@\n', ++ "-This is the file 'newfile'.\n" ] ++ svntest.actions.run_and_verify_svn(None, None, [], 'diff', ++ '-r2:1', newfile) ++ + ######################################################################## + #Run the tests + +@@ -3935,6 +4074,8 @@ + no_spurious_conflict, + diff_deleted_url, + diff_git_format_wc_wc_dir_mv, ++ diff_repo_wc_file_props, ++ diff_repo_repo_added_file_mime_type, + ] + + if __name__ == '__main__': +--- subversion-1.7.14/subversion/libsvn_client/diff.c ++++ subversion-1.7.14/subversion/libsvn_client/diff.c +@@ -1892,6 +1892,7 @@ + const char *file_abspath; + svn_stream_t *content; + apr_hash_t *prop_hash; ++ svn_string_t *mimetype; + + SVN_ERR(svn_stream_open_unique(&content, &file_abspath, NULL, + svn_io_file_del_on_pool_cleanup, +@@ -1900,13 +1901,13 @@ + &prop_hash, scratch_pool)); + SVN_ERR(svn_stream_close(content)); + ++ mimetype = apr_hash_get(prop_hash, SVN_PROP_MIME_TYPE, APR_HASH_KEY_STRING); ++ + if (show_deletion) + { + SVN_ERR(callbacks->file_deleted(NULL, NULL, + target, file_abspath, empty_file, +- apr_hash_get(prop_hash, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), ++ mimetype ? mimetype->data : NULL, + NULL, + make_regular_props_hash( + prop_hash, scratch_pool, scratch_pool), +@@ -1917,8 +1918,7 @@ + SVN_ERR(callbacks->file_added(NULL, NULL, NULL, + target, empty_file, file_abspath, + rev1, rev2, NULL, +- apr_hash_get(prop_hash, SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), ++ mimetype ? mimetype->data : NULL, + NULL, SVN_INVALID_REVNUM, + make_regular_props_array(prop_hash, + scratch_pool, +@@ -2243,6 +2243,7 @@ + apr_hash_t *file1_props = NULL; + apr_hash_t *file2_props; + svn_boolean_t is_copy = FALSE; ++ svn_string_t *mimetype1, *mimetype2; + + /* Get content and props of file 1 (the remote file). */ + SVN_ERR(svn_stream_open_unique(&file1_content, &file1_abspath, NULL, +@@ -2292,6 +2293,7 @@ + { + apr_hash_t *keywords = NULL; + svn_string_t *keywords_prop; ++ svn_string_t *eol_prop; + svn_subst_eol_style_t eol_style; + const char *eol_str; + +@@ -2299,10 +2301,10 @@ + scratch_pool, scratch_pool)); + + /* We might have to create a normalised version of the working file. */ ++ eol_prop = apr_hash_get(file2_props, SVN_PROP_EOL_STYLE, ++ APR_HASH_KEY_STRING); + svn_subst_eol_style_from_value(&eol_style, &eol_str, +- apr_hash_get(file2_props, +- SVN_PROP_EOL_STYLE, +- APR_HASH_KEY_STRING)); ++ eol_prop ? eol_prop->data : NULL); + keywords_prop = apr_hash_get(file2_props, SVN_PROP_KEYWORDS, + APR_HASH_KEY_STRING); + if (keywords_prop) +@@ -2309,7 +2311,7 @@ + SVN_ERR(svn_subst_build_keywords2(&keywords, keywords_prop->data, + NULL, NULL, 0, NULL, + scratch_pool)); +- if (svn_subst_translation_required(eol_style, SVN_SUBST_NATIVE_EOL_STR, ++ if (svn_subst_translation_required(eol_style, eol_str, + keywords, FALSE, TRUE)) + { + svn_stream_t *working_content; +@@ -2323,7 +2325,7 @@ + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + normalized_content = svn_subst_stream_translated( +- file2_content, SVN_SUBST_NATIVE_EOL_STR, ++ file2_content, eol_str, + TRUE, keywords, FALSE, scratch_pool); + SVN_ERR(svn_stream_copy3(working_content, normalized_content, + ctx->cancel_func, ctx->cancel_baton, +@@ -2331,42 +2333,46 @@ + } + } + ++ mimetype1 = file1_props ? apr_hash_get(file1_props, SVN_PROP_MIME_TYPE, ++ APR_HASH_KEY_STRING) ++ : NULL; ++ mimetype2 = apr_hash_get(file2_props, SVN_PROP_MIME_TYPE, ++ APR_HASH_KEY_STRING); ++ + if (kind1 == svn_node_file && !(show_copies_as_adds && is_copy)) + { ++ apr_array_header_t *propchanges; ++ + SVN_ERR(callbacks->file_opened(NULL, NULL, target, + reverse ? SVN_INVALID_REVNUM : rev, + callback_baton, scratch_pool)); + + if (reverse) +- SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target, +- file2_abspath, file1_abspath, +- SVN_INVALID_REVNUM, rev, +- apr_hash_get(file2_props, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), +- apr_hash_get(file1_props, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), +- make_regular_props_array( +- file1_props, scratch_pool, +- scratch_pool), +- file2_props, +- callback_baton, scratch_pool)); ++ { ++ SVN_ERR(svn_prop_diffs(&propchanges, file1_props, file2_props, ++ scratch_pool)); ++ ++ SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target, ++ file2_abspath, file1_abspath, ++ SVN_INVALID_REVNUM, rev, ++ mimetype2 ? mimetype2->data : NULL, ++ mimetype1 ? mimetype1->data : NULL, ++ propchanges, file2_props, ++ callback_baton, scratch_pool)); ++ } + else +- SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target, +- file1_abspath, file2_abspath, +- rev, SVN_INVALID_REVNUM, +- apr_hash_get(file1_props, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), +- apr_hash_get(file2_props, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), +- make_regular_props_array( +- file2_props, scratch_pool, +- scratch_pool), +- file1_props, +- callback_baton, scratch_pool)); ++ { ++ SVN_ERR(svn_prop_diffs(&propchanges, file2_props, file1_props, ++ scratch_pool)); ++ ++ SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target, ++ file1_abspath, file2_abspath, ++ rev, SVN_INVALID_REVNUM, ++ mimetype1 ? mimetype1->data : NULL, ++ mimetype2 ? mimetype2->data : NULL, ++ propchanges, file1_props, ++ callback_baton, scratch_pool)); ++ } + } + else + { +@@ -2374,9 +2380,7 @@ + { + SVN_ERR(callbacks->file_deleted(NULL, NULL, + target, file2_abspath, file1_abspath, +- apr_hash_get(file2_props, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), ++ mimetype2 ? mimetype2->data : NULL, + NULL, + make_regular_props_hash( + file2_props, scratch_pool, +@@ -2389,9 +2393,7 @@ + file1_abspath, file2_abspath, + rev, SVN_INVALID_REVNUM, + NULL, +- apr_hash_get(file2_props, +- SVN_PROP_MIME_TYPE, +- APR_HASH_KEY_STRING), ++ mimetype2 ? mimetype2->data : NULL, + NULL, SVN_INVALID_REVNUM, + make_regular_props_array( + file2_props, scratch_pool, diff --git a/SOURCES/subversion-1.7.14-r1708699.patch b/SOURCES/subversion-1.7.14-r1708699.patch new file mode 100644 index 0000000..6aba793 --- /dev/null +++ b/SOURCES/subversion-1.7.14-r1708699.patch @@ -0,0 +1,37 @@ +# ./pullrev.sh 1708699 +http://svn.apache.org/viewvc?view=revision&revision=1708699 + +https://bugzilla.redhat.com/show_bug.cgi?id=1306431 + +--- subversion-1.7.14/subversion/mod_authz_svn/mod_authz_svn.c.r1708699 ++++ subversion-1.7.14/subversion/mod_authz_svn/mod_authz_svn.c +@@ -807,19 +807,21 @@ + #if USE_FORCE_AUTHN + if (authn_configured) { + /* We have to check to see if authn is required because if so we must +- * return UNAUTHORIZED (401) rather than FORBIDDEN (403) since returning ++ * return DECLINED rather than FORBIDDEN (403) since returning + * the 403 leaks information about what paths may exist to +- * unauthenticated users. We must set a note here in order +- * to use ap_some_authn_rquired() without triggering an infinite +- * loop since the call will trigger this function to be called again. */ ++ * unauthenticated users. Returning DECLINED means apache's request ++ * handling will continue until the authn module itself generates ++ * UNAUTHORIZED (401). ++ ++ * We must set a note here in order to use ++ * ap_some_authn_rquired() without triggering an infinite ++ * loop since the call will trigger this function to be ++ * called again. */ + apr_table_setn(r->notes, IN_SOME_AUTHN_NOTE, (const char*)1); + authn_required = ap_some_authn_required(r); + apr_table_unset(r->notes, IN_SOME_AUTHN_NOTE); + if (authn_required) +- { +- ap_note_auth_failure(r); +- return HTTP_UNAUTHORIZED; +- } ++ return DECLINED; + } + #else + if (!ap_some_auth_required(r)) diff --git a/SPECS/subversion.spec b/SPECS/subversion.spec index 3c72e08..dbf413d 100644 --- a/SPECS/subversion.spec +++ b/SPECS/subversion.spec @@ -22,7 +22,7 @@ Summary: A Modern Concurrent Version Control System Name: subversion Version: 1.7.14 -Release: 11%{?dist} +Release: 14%{?dist} License: ASL 2.0 Group: Development/Tools URL: http://subversion.apache.org/ @@ -52,6 +52,9 @@ Patch17: subversion-1.7.14-CVE-2015-0251.patch Patch18: subversion-1.7.14-CVE-2015-3184.patch Patch19: subversion-1.7.14-CVE-2015-3187.patch Patch20: subversion-1.7.14-CVE-2017-9800.patch +Patch21: subversion-1.7.14-r1439592+.patch +Patch22: subversion-1.7.14-r1708699.patch +Patch23: subversion-1.7.14-r1564900.patch BuildRequires: autoconf, libtool, python, python-devel, texinfo, which BuildRequires: libdb-devel, swig >= 1.3.24, gettext BuildRequires: apr-devel >= 1.3.0, apr-util-devel >= 1.3.0 @@ -202,6 +205,9 @@ This package includes supplementary tools for use with Subversion. %patch18 -p1 -b .cve3184 %patch19 -p1 -b .cve3187 %patch20 -p0 -b .cve9800 +%patch21 -p1 -b .r1439592+ +%patch22 -p1 -b .r1708699 +%patch23 -p1 -b .r1564900 %build # Regenerate the buildsystem, so that: @@ -305,7 +311,9 @@ rm -f ${RPM_BUILD_ROOT}%{_libdir}/libsvn_swig_*.{so,la,a} rm -f ${RPM_BUILD_ROOT}%{ruby_vendorarchdir}/svn/ext/*.*a # Trim what goes in docdir -rm -rf tools/*/*.in +rm -v tools/*/*.in \ + tools/hook-scripts/mailer/mailer.conf.example.* \ + tools/hook-scripts/mailer/mailer.py.* # Install psvn for emacs and xemacs for f in emacs/site-lisp xemacs/site-packages/lisp; do @@ -429,7 +437,7 @@ rm -rf ${RPM_BUILD_ROOT} %dir %{_sysconfdir}/subversion %exclude %{_mandir}/man*/*::* %{_unitdir}/*.service -%dir /run/svnserve +%attr(0700,root,root) %dir /run/svnserve %{_prefix}/lib/tmpfiles.d/svnserve.conf %files tools -f tools.files @@ -499,6 +507,17 @@ rm -rf ${RPM_BUILD_ROOT} %endif %changelog +* Wed Oct 25 2017 Joe Orton - 1.7.14-14 +- remove installed backup files (#1379593) + +* Fri Oct 20 2017 Joe Orton - 1.7.14-13 +- fix mod_authz_svn regression with mod_auth_kerb (#1306431) +- fix "svn diff" property handling (#1378178) +- fix permissions of /run/svnserve to match tmpfiles (#1496243) + +* Fri Oct 20 2017 Joe Orton - 1.7.14-12 +- add repos_basename substitution variable in mailer.py (#1379593) + * Wed Aug 9 2017 Joe Orton - 1.7.14-11 - add security fix for CVE-2017-9800