This diff gets the lang/ruby/2.2 tests passing. I started by getting
the tests passing on the ruby master branch, then backported the fixes
to ruby 2.2. All of these fixes are already either sent or fixed
upstream, don't apply to the ruby master branch, or are
OpenBSD-specific.
The main important fix in this is the fix to String#crypt. Currently,
String#crypt can crash the interpreter since it assumes that if crypt(3)
fails that either errno is set or there is a fatal bug, and OpenBSD's
crypt(3) returns NULL without setting errno on failure.
I've modified String#crypt so that if the salt does not start with
'$2', a random salt is created and used. The alternative is having
it raise an exception in that case, but that's probably going to
cause more errors in otherwise portable ruby code.
Due to the severity, I will be backporting the crypt(3) fixes to older
versions of ruby, but I don't plan to backport the other fixes.
The rest of these changes are bug fixes, except that this changes
Webrick's htpasswd support to default to SHA hashes. Currently the
Webrick htpasswd support is broken on OpenBSD since it only works
with DES-based crypt hashes. The only real option was supporting
and defaulting to SHA htpasswd, since there isn't a DES-based
crypt supported in ruby, the MD5 htpasswd uses an Apache specific
algorithm, and plain text is probably a bad idea.
Since the String#crypt and Webrick SHA htpasswd changes are significant
and potentially affect security, I'd at least like to get an OK from
another developer for those changes.
As an aside, crypt("passwd", "$2") returns ":" instead of NULL. I'm not
sure if that's a security issue, but I think it is and we should fix it.
I'll see if I can get a patch for that and send it to tech@.
Thanks,
Jeremy
Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/ruby/2.2/Makefile,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 Makefile
--- Makefile 29 Jun 2015 18:55:03 -0000 1.5
+++ Makefile 17 Jul 2015 23:55:52 -0000
@@ -99,7 +99,6 @@ pre-install:
do-test:
-cd ${WRKSRC} && make test-sample
-cd ${WRKSRC} && make btest-ruby
- cd ${WRKSRC} && make test-all TESTOPTS="-v -q -x test/ruby/test_io.rb \
- -x test/net/http/test_http.rb"
+ cd ${WRKSRC} && make test-all TESTOPTS="-v -q"
.include <bsd.port.mk>
Index: patches/patch-common_mk
===================================================================
RCS file: /cvs/ports/lang/ruby/2.2/patches/patch-common_mk,v
retrieving revision 1.1.1.1
diff -u -p -u -p -r1.1.1.1 patch-common_mk
--- patches/patch-common_mk 8 Jan 2015 18:48:32 -0000 1.1.1.1
+++ patches/patch-common_mk 17 Jul 2015 23:55:52 -0000
@@ -2,9 +2,9 @@ $OpenBSD: patch-common_mk,v 1.1.1.1 2015
Don't regenerate rdoc documentation during install.
---- common.mk.orig Tue Dec 23 18:56:32 2014
-+++ common.mk Tue Dec 30 00:56:35 2014
-@@ -184,7 +184,7 @@ $(EXTS_MK): $(MKFILES) all-incs $(PREP) $(RBCONFIG) $(
+--- common.mk.orig Sat Mar 21 21:39:38 2015
++++ common.mk Fri Jul 17 16:09:34 2015
+@@ -186,7 +186,7 @@ $(EXTS_MK): $(MKFILES) all-incs $(PREP) $(RBCONFIG) $(
configure-ext: $(EXTS_MK)
build-ext: $(EXTS_MK)
@@ -13,7 +13,7 @@ Don't regenerate rdoc documentation duri
ENCOBJS="$(ENCOBJS)" UPDATE_LIBRARIES=no $(EXTSTATIC)
prog: program wprogram
-@@ -407,7 +407,7 @@ dont-install-man: $(PREP)
+@@ -409,7 +409,7 @@ dont-install-man: $(PREP)
post-no-install-man::
@$(NULLCMD)
Index: patches/patch-configure
===================================================================
RCS file: /cvs/ports/lang/ruby/2.2/patches/patch-configure,v
retrieving revision 1.1.1.1
diff -u -p -u -p -r1.1.1.1 patch-configure
--- patches/patch-configure 8 Jan 2015 18:48:32 -0000 1.1.1.1
+++ patches/patch-configure 17 Jul 2015 23:55:52 -0000
@@ -5,8 +5,8 @@ Fix so name, checking for DOT and DOXYGE
Override the arch setting to remove OpenBSD version from it,
so ports don't have to be bumped when OpenBSD version changes.
---- configure.orig Thu Dec 25 00:44:47 2014
-+++ configure Tue Dec 30 00:56:35 2014
+--- configure.orig Mon Apr 13 08:18:08 2015
++++ configure Fri Jul 17 16:09:34 2015
@@ -22359,7 +22359,7 @@ esac
openbsd*|mirbsd*) :
@@ -16,7 +16,7 @@ so ports don't have to be bumped when Op
;; #(
solaris*) :
-@@ -23620,7 +23620,7 @@ _ACEOF
+@@ -23625,7 +23625,7 @@ _ACEOF
_ACEOF
else
Index: patches/patch-ext_openssl_ossl_ssl_c
===================================================================
RCS file: patches/patch-ext_openssl_ossl_ssl_c
diff -N patches/patch-ext_openssl_ossl_ssl_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-ext_openssl_ossl_ssl_c 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,21 @@
+$OpenBSD$
+
+Raise an error if a selected NPN protocol is too long.
+
+--- ext/openssl/ossl_ssl.c.orig Fri Dec 12 14:58:34 2014
++++ ext/openssl/ossl_ssl.c Fri Jul 17 16:10:25 2015
+@@ -637,9 +637,12 @@ ssl_npn_select_cb(SSL *s, unsigned char **out, unsigne
+
+ selected = rb_funcall(cb, rb_intern("call"), 1, protocols);
+ StringValue(selected);
++ i = RSTRING_LENINT(selected);
++ if (i < 1 || i >= 256) {
++ ossl_raise(eSSLError, "Selected protocol must have length 1..255");
++ }
+ *out = (unsigned char *) StringValuePtr(selected);
+- *outlen = RSTRING_LENINT(selected);
+-
++ *outlen = i;
+ return SSL_TLSEXT_ERR_OK;
+ }
+ #endif
Index: patches/patch-lib_webrick_httpauth_basicauth_rb
===================================================================
RCS file: patches/patch-lib_webrick_httpauth_basicauth_rb
diff -N patches/patch-lib_webrick_httpauth_basicauth_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_webrick_httpauth_basicauth_rb 17 Jul 2015 23:55:52
-0000
@@ -0,0 +1,37 @@
+$OpenBSD$
+
+Default to creating SHA htpasswd hashes.
+
+Add ability to check SHA htpasswd hashes in addition to crypt htpasswd
+hashes (which don't work on OpenBSD since DES-based passwds were
+removed from crypt(3)).
+
+--- lib/webrick/httpauth/basicauth.rb.orig Fri Jan 25 18:12:54 2013
++++ lib/webrick/httpauth/basicauth.rb Fri Jul 17 16:10:25 2015
+@@ -10,6 +10,7 @@
+ require 'webrick/config'
+ require 'webrick/httpstatus'
+ require 'webrick/httpauth/authenticator'
++require 'digest/sha1'
+
+ module WEBrick
+ module HTTPAuth
+@@ -41,7 +42,8 @@ module WEBrick
+
+ def self.make_passwd(realm, user, pass)
+ pass ||= ""
+- pass.crypt(Utils::random_string(2))
++ encpass = Digest::SHA1.new.update(pass).base64digest
++ "{SHA}#{encpass}"
+ end
+
+ attr_reader :realm, :userdb, :logger
+@@ -80,7 +82,7 @@ module WEBrick
+ error("%s: the user is not allowed.", userid)
+ challenge(req, res)
+ end
+- if password.crypt(encpass) != encpass
++ if (encpass.length == 13 ? password.crypt(encpass) != encpass :
Digest::SHA1.new.update(password).base64digest != encpass)
+ error("%s: password unmatch.", userid)
+ challenge(req, res)
+ end
Index: patches/patch-lib_webrick_httpauth_htpasswd_rb
===================================================================
RCS file: patches/patch-lib_webrick_httpauth_htpasswd_rb
diff -N patches/patch-lib_webrick_httpauth_htpasswd_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_webrick_httpauth_htpasswd_rb 17 Jul 2015 23:55:52
-0000
@@ -0,0 +1,24 @@
+$OpenBSD$
+
+Support reading SHA htpasswd lines.
+
+--- lib/webrick/httpauth/htpasswd.rb.orig Sat Apr 20 09:10:29 2013
++++ lib/webrick/httpauth/htpasswd.rb Fri Jul 17 16:10:25 2015
+@@ -54,11 +54,14 @@ module WEBrick
+ while line = io.gets
+ line.chomp!
+ case line
+- when %r!\A[^:]+:[a-zA-Z0-9./]{13}\z!
++ when
%r!\A[^:]+:\{SHA\}(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?\z!
+ user, pass = line.split(":")
+- when /:\$/, /:{SHA}/
++ pass = pass[5..-1]
++ when /:[a-zA-Z0-9.\/]{13}\z/
++ user, pass = line.split(":")
++ when /:\$/
+ raise NotImplementedError,
+- 'MD5, SHA1 .htpasswd file not supported'
++ 'MD5 .htpasswd file not supported'
+ else
+ raise StandardError, 'bad .htpasswd file'
+ end
Index: patches/patch-string_c
===================================================================
RCS file: patches/patch-string_c
diff -N patches/patch-string_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-string_c 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,64 @@
+$OpenBSD$
+
+Fix bug causing String#crypt to crash the interpreter if errno
+was nonzero and an invalid bcrypt salt was passed.
+
+--- string.c.orig Tue Feb 24 00:40:44 2015
++++ string.c Fri Jul 17 16:10:25 2015
+@@ -22,6 +22,8 @@
+
+ #include <math.h>
+ #include <ctype.h>
++#include <stdlib.h>
++#include <pwd.h>
+
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+@@ -7656,18 +7658,20 @@ rb_str_oct(VALUE str)
+ * This method is for use in system specific scripts, so if you want
+ * a cross-platform hash function consider using Digest or OpenSSL
+ * instead.
++ *
++ * On OpenBSD, the salt value is checked, but ignored unless it starts
++ * with "$2". If the salt value starts with "$2", it is used as-is,
++ * otherwise a new salt is generated via bcrypt_gensalt(3). This is
++ * because crypt(3) on OpenBSD does not use the historical DES-based
++ * encryption, it fails unless the salt starts with "$2".
+ */
+
+ static VALUE
+ rb_str_crypt(VALUE str, VALUE salt)
+ {
+- extern char *crypt(const char *, const char *);
+ VALUE result;
+ const char *s, *saltp;
+ char *res;
+-#ifdef BROKEN_CRYPT
+- char salt_8bit_clean[3];
+-#endif
+
+ StringValue(salt);
+ mustnot_wchar(str);
+@@ -7681,17 +7685,12 @@ rb_str_crypt(VALUE str, VALUE salt)
+ if (!s) s = "";
+ saltp = RSTRING_PTR(salt);
+ if (!saltp[0] || !saltp[1]) goto short_salt;
+-#ifdef BROKEN_CRYPT
+- if (!ISASCII((unsigned char)saltp[0]) || !ISASCII((unsigned
char)saltp[1])) {
+- salt_8bit_clean[0] = saltp[0] & 0x7f;
+- salt_8bit_clean[1] = saltp[1] & 0x7f;
+- salt_8bit_clean[2] = '\0';
+- saltp = salt_8bit_clean;
+- }
+-#endif
++ if (saltp[0] != '$' || saltp[1] != '2') {
++ saltp = bcrypt_gensalt(8);
++ }
+ res = crypt(s, saltp);
+- if (!res) {
+- rb_sys_fail("crypt");
++ if (!res || res[0] == ':') {
++ rb_raise(rb_eRuntimeError, "crypt failure");
+ }
+ result = rb_str_new_cstr(res);
+ OBJ_INFECT(result, str);
Index: patches/patch-test_openssl_test_ssl_rb
===================================================================
RCS file: patches/patch-test_openssl_test_ssl_rb
diff -N patches/patch-test_openssl_test_ssl_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_openssl_test_ssl_rb 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,15 @@
+$OpenBSD$
+
+Fix LocalJumpError being raised instead of no exception.
+
+--- test/openssl/test_ssl.rb.orig Mon Apr 13 07:13:01 2015
++++ test/openssl/test_ssl.rb Fri Jul 17 16:10:25 2015
+@@ -906,7 +906,7 @@ end
+ ssl = ctx ? OpenSSL::SSL::SSLSocket.new(sock, ctx) :
OpenSSL::SSL::SSLSocket.new(sock)
+ ssl.sync_close = true
+ ssl.connect
+- yield ssl
++ yield ssl if block_given?
+ ensure
+ if ssl
+ ssl.close
Index: patches/patch-test_openssl_test_ssl_session_rb
===================================================================
RCS file: patches/patch-test_openssl_test_ssl_session_rb
diff -N patches/patch-test_openssl_test_ssl_session_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_openssl_test_ssl_session_rb 17 Jul 2015 23:55:52
-0000
@@ -0,0 +1,34 @@
+$OpenBSD$
+
+Use OP_NO_TICKET so that external session caches work.
+
+Remove explicit use of SSLv3.
+
+--- test/openssl/test_ssl_session.rb.orig Fri Dec 12 20:05:43 2014
++++ test/openssl/test_ssl_session.rb Fri Jul 17 17:53:50 2015
+@@ -278,7 +278,7 @@ __EOS__
+
+ def test_ctx_client_session_cb
+ called = {}
+- ctx = OpenSSL::SSL::SSLContext.new("SSLv3")
++ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT
+
+ ctx.session_new_cb = lambda { |ary|
+@@ -316,6 +316,7 @@ __EOS__
+
+ ctx_proc = Proc.new { |ctx, ssl|
+ ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER
++ ctx.options = OpenSSL::SSL::OP_NO_TICKET
+ last_server_session = nil
+
+ # get_cb is called whenever a client proposed to resume a session but
+@@ -355,7 +356,7 @@ __EOS__
+ 3.times do
+ sock = TCPSocket.new("127.0.0.1", port)
+ begin
+- ssl = OpenSSL::SSL::SSLSocket.new(sock,
OpenSSL::SSL::SSLContext.new("SSLv3"))
++ ssl = OpenSSL::SSL::SSLSocket.new(sock,
OpenSSL::SSL::SSLContext.new)
+ ssl.sync_close = true
+ ssl.session = last_client_session if last_client_session
+ ssl.connect
Index: patches/patch-test_ruby_test_fiber_rb
===================================================================
RCS file: patches/patch-test_ruby_test_fiber_rb
diff -N patches/patch-test_ruby_test_fiber_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_ruby_test_fiber_rb 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,15 @@
+$OpenBSD$
+
+Relax check for fiber stack size.
+
+--- test/ruby/test_fiber.rb.orig Fri Jul 17 17:18:10 2015
++++ test/ruby/test_fiber.rb Fri Jul 17 17:18:13 2015
+@@ -315,7 +315,7 @@ class TestFiber < Test::Unit::TestCase
+ vm_stack_size = 1024 * 1024
+ size_default = invoke_rec script, vm_stack_size, nil
+ size_0 = invoke_rec script, vm_stack_size, 0
+- assert_operator(size_default, :>=, size_0)
++ assert_operator(size_default, :>=, size_0 - 1)
+ size_large = invoke_rec script, vm_stack_size, 1024 * 1024 * 10
+ assert_operator(size_default, :<=, size_large)
+ end
Index: patches/patch-test_ruby_test_gc_rb
===================================================================
RCS file: patches/patch-test_ruby_test_gc_rb
diff -N patches/patch-test_ruby_test_gc_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_ruby_test_gc_rb 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,15 @@
+$OpenBSD$
+
+Relax check for head_eden_pages, fixing occassional failure.
+
+--- test/ruby/test_gc.rb.orig Fri Jul 17 17:15:15 2015
++++ test/ruby/test_gc.rb Fri Jul 17 17:16:29 2015
+@@ -289,7 +289,7 @@ class TestGc < Test::Unit::TestCase
+ base_length = GC.stat[:heap_eden_pages]
+ (base_length * 500).times{ 'a' }
+ GC.start
+- assert_in_delta base_length, (v = GC.stat[:heap_eden_pages]), 1,
++ assert_in_delta base_length, (v = GC.stat[:heap_eden_pages]), 10,
+ "invalid heap expanding (base_length: #{base_length},
GC.stat[:heap_eden_pages]: #{v})"
+
+ a = []
Index: patches/patch-test_ruby_test_m17n_comb_rb
===================================================================
RCS file: patches/patch-test_ruby_test_m17n_comb_rb
diff -N patches/patch-test_ruby_test_m17n_comb_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_ruby_test_m17n_comb_rb 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,15 @@
+$OpenBSD$
+
+Test crypt using encrypted password as salt.
+
+--- test/ruby/test_m17n_comb.rb.orig Tue Feb 24 00:40:44 2015
++++ test/ruby/test_m17n_comb.rb Fri Jul 17 16:13:59 2015
+@@ -760,7 +760,7 @@ class TestM17NComb < Test::Unit::TestCase
+ next
+ end
+ t = str.crypt(salt)
+- assert_equal(b(str).crypt(b(salt)), t,
"#{encdump(str)}.crypt(#{encdump(salt)})")
++ assert_equal(b(str).crypt(b(t)), t,
"#{encdump(str)}.crypt(#{encdump(t)})")
+ assert_encoding('ASCII-8BIT', t.encoding)
+ }
+ end
Index: patches/patch-test_ruby_test_string_rb
===================================================================
RCS file: patches/patch-test_ruby_test_string_rb
diff -N patches/patch-test_ruby_test_string_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_ruby_test_string_rb 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,20 @@
+$OpenBSD$
+
+Test crypt using encrypted password as salt.
+
+--- test/ruby/test_string.rb.orig Tue Feb 24 00:36:55 2015
++++ test/ruby/test_string.rb Fri Jul 17 16:10:25 2015
+@@ -502,8 +502,11 @@ class TestString < Test::Unit::TestCase
+ end
+
+ def test_crypt
+- assert_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("aa")))
+- assert_not_equal(S('aaGUC/JkO9/Sc'), S("mypassword").crypt(S("ab")))
++ assert_instance_of String, S("mypassword").crypt(S("aa"))
++ enc = S("mypassword").crypt(S("aa"))
++ assert_equal S("mypassword").crypt(S(enc)), S("mypassword").crypt(S(enc))
++ assert_not_equal S("mypassword").crypt(S("aa")),
S("mypassword").crypt(S("ab"))
++ assert_not_equal S("mypassword").crypt(S("aa")),
S("mypasswor").crypt(S("aa"))
+ assert_raise(ArgumentError) {S("mypassword").crypt(S(""))}
+ assert_raise(ArgumentError) {S("mypassword").crypt(S("\0a"))}
+ assert_raise(ArgumentError) {S("mypassword").crypt(S("a\0"))}
Index: patches/patch-test_rubygems_test_gem_remote_fetcher_rb
===================================================================
RCS file: patches/patch-test_rubygems_test_gem_remote_fetcher_rb
diff -N patches/patch-test_rubygems_test_gem_remote_fetcher_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_rubygems_test_gem_remote_fetcher_rb 17 Jul 2015
23:55:52 -0000
@@ -0,0 +1,26 @@
+$OpenBSD$
+
+Fix test for endpoint after rubygems security fix.
+
+Don't use a too-small dh param size (r50972).
+
+--- test/rubygems/test_gem_remote_fetcher.rb.orig Fri Jul 17 17:23:01 2015
++++ test/rubygems/test_gem_remote_fetcher.rb Fri Jul 17 17:23:06 2015
+@@ -176,7 +176,7 @@ gems:
+
+ fetch = Gem::RemoteFetcher.new nil, dns
+ @fetcher = fetcher
+- assert_equal URI.parse("http://blah.com/foo"), fetch.api_endpoint(uri)
++ assert_equal URI.parse("http://gems.example.com/foo"),
fetch.api_endpoint(uri)
+
+ target.verify
+ dns.verify
+@@ -854,7 +854,7 @@ gems:
+ server.mount_proc("/insecure_redirect") { |req, res|
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently,
req.query['to'])
+ }
+- server.ssl_context.tmp_dh_callback = proc { OpenSSL::PKey::DH.new 128 }
++ server.ssl_context.tmp_dh_callback = proc {|_, _, k|
OpenSSL::PKey::DH.new(k) }
+ t = Thread.new do
+ begin
+ server.start
Index: patches/patch-test_webrick_test_httpauth_rb
===================================================================
RCS file: patches/patch-test_webrick_test_httpauth_rb
diff -N patches/patch-test_webrick_test_httpauth_rb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_webrick_test_httpauth_rb 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,22 @@
+$OpenBSD$
+
+Remove negative test for SHA htpasswd files, since they are now
+supported and the default.
+
+--- test/webrick/test_httpauth.rb.orig Sun Nov 9 07:01:20 2014
++++ test/webrick/test_httpauth.rb Fri Jul 17 16:10:25 2015
+@@ -81,14 +81,6 @@ class TestWEBrickHTTPAuth < Test::Unit::TestCase
+
+ def test_basic_auth3
+ Tempfile.create("test_webrick_auth") {|tmpfile|
+- tmpfile.puts("webrick:{SHA}GJYFRpBbdchp595jlh3Bhfmgp8k=")
+- tmpfile.flush
+- assert_raise(NotImplementedError){
+- WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
+- }
+- }
+-
+- Tempfile.create("test_webrick_auth") {|tmpfile|
+ tmpfile.puts("webrick:$apr1$IOVMD/..$rmnOSPXr0.wwrLPZHBQZy0")
+ tmpfile.flush
+ assert_raise(NotImplementedError){
Index: patches/patch-test_xmlrpc_htpasswd
===================================================================
RCS file: patches/patch-test_xmlrpc_htpasswd
diff -N patches/patch-test_xmlrpc_htpasswd
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-test_xmlrpc_htpasswd 17 Jul 2015 23:55:52 -0000
@@ -0,0 +1,12 @@
+$OpenBSD$
+
+Make test htpasswd file use SHA passwords instead of DES
+crypt passwords.
+
+--- test/xmlrpc/htpasswd.orig Tue Jul 26 09:48:16 2011
++++ test/xmlrpc/htpasswd Fri Jul 17 16:10:25 2015
+@@ -1,2 +1,2 @@
+-admin:Qg266hq/YYKe2
+-01234567890123456789012345678901234567890123456789012345678901234567890123456789:Yl.SJmoFETpS2
++admin:{SHA}0DPiKuNIrrVmD8IUCuw1hQxNqZc=
++01234567890123456789012345678901234567890123456789012345678901234567890123456789:{SHA}NWdeaPS1r3uZXZIFrQ/EOELxZFA=