On 07/17 05:15, Jeremy Evans wrote:
> 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@.
Here's a new diff that takes into account recent changes to crypt(3),
and bumps REVISION correctly.
I'd still like to get an OK from another developer for the String#crypt
and Webrick htpasswd changes.
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 18 Jul 2015 00:53:24 -0000
@@ -17,7 +17,8 @@ PKGNAME-gdbm = ruby22-gdbm-${VERSION}
PKGNAME-tk = ruby22-tk-${VERSION}
PKGNAME-ri_docs = ruby22-ri_docs-${VERSION}
-REVISION-main = 0
+REVISION-main = 1
+REVISION-ri_docs = 0
PKG_ARCH-ri_docs = *
WANTLIB-ri_docs = # empty
@@ -99,7 +100,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 22:14:39 -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 22:14:39 -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 22:18:59 -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 22:18:31
-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 22:18:46
-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 18 Jul 2015 01:52:48 -0000
@@ -0,0 +1,62 @@
+$OpenBSD$
+
+Automatically create salt if given salt doesn't start with "$2", since
+portable ruby code doesn't expect crypt to fail with other crypt values.
+
+--- 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");
+ }
+ 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 22:15:29 -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:54:05
-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:24:57 -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:24:43 -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 22:16:39 -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 22:16:53 -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:24:30 -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 22:15:06 -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 22:17:19 -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=