Description: CVE-2013-7239: SASL authentication allows wrong credentials to access memcache It was previously possible to bypass authentication due to implicit state management. Now we explicitly consider ourselves unauthenticated on any new connections and authentication attempts. Origin: upstream, https://github.com/memcached/memcached/commit/87c1cf0f20be20608d3becf854e9cf0910f4ad32 Bug: https://code.google.com/p/memcached/issues/detail?id=316 Bug-Debian: http://bugs.debian.org/733643 Forwarded: not-needed Last-Update: 2013-12-30 Applied-Upstream: 1.4.17 --- a/memcached.c +++ b/memcached.c @@ -442,6 +442,7 @@ c->iovused = 0; c->msgcurr = 0; c->msgused = 0; + c->authenticated = false; c->write_and_go = init_state; c->write_and_free = 0; @@ -1602,6 +1603,8 @@ if (!settings.sasl) return; + c->authenticated = false; + if (!c->sasl_conn) { int result=sasl_server_new("memcached", NULL, @@ -1736,6 +1739,7 @@ switch(result) { case SASL_OK: + c->authenticated = true; write_bin_response(c, "Authenticated", 0, 0, strlen("Authenticated")); pthread_mutex_lock(&c->thread->stats.mutex); c->thread->stats.auth_cmds++; @@ -1772,11 +1776,7 @@ rv = true; break; default: - if (c->sasl_conn) { - const void *uname = NULL; - sasl_getprop(c->sasl_conn, SASL_USERNAME, &uname); - rv = uname != NULL; - } + rv = c->authenticated; } if (settings.verbose > 1) { --- a/memcached.h +++ b/memcached.h @@ -367,6 +367,7 @@ struct conn { int sfd; sasl_conn_t *sasl_conn; + bool authenticated; enum conn_states state; enum bin_substates substate; struct event event; --- a/t/binary-sasl.t +++ b/t/binary-sasl.t @@ -13,7 +13,7 @@ if (supports_sasl()) { if ($ENV{'RUN_SASL_TESTS'}) { - plan tests => 25; + plan tests => 33; } else { plan skip_all => 'Skipping SASL tests'; exit 0; @@ -229,6 +229,38 @@ } $empty->('x'); +{ + my $mc = MC::Client->new; + + # Attempt bad authentication. + is ($mc->authenticate('testuser', 'wrongpassword'), 0x20, "bad auth"); + + # This should fail because $mc is not authenticated + my ($status, $val)= $mc->set('x', "somevalue"); + ok($status, "this fails to authenticate"); + cmp_ok($status,'==',ERR_AUTH_ERROR, "error code matches"); +} +$empty->('x', 'somevalue'); + +{ + my $mc = MC::Client->new; + + # Attempt bad authentication. + is ($mc->authenticate('testuser', 'wrongpassword'), 0x20, "bad auth"); + + # Mix an authenticated connection and an unauthenticated connection to + # confirm c->authenticated is not shared among connections + my $mc2 = MC::Client->new; + is ($mc2->authenticate('testuser', 'testpass'), 0, "authenticated"); + my ($status, $val)= $mc2->set('x', "somevalue"); + ok(! $status); + + # This should fail because $mc is not authenticated + ($status, $val)= $mc->set('x', "somevalue"); + ok($status, "this fails to authenticate"); + cmp_ok($status,'==',ERR_AUTH_ERROR, "error code matches"); +} + # check the SASL stats, make sure they track things correctly # note: the enabled or not is presence checked in stats.t @@ -241,8 +273,8 @@ { my %stats = $mc->stats(''); - is ($stats{'auth_cmds'}, 2, "auth commands counted"); - is ($stats{'auth_errors'}, 1, "auth errors correct"); + is ($stats{'auth_cmds'}, 5, "auth commands counted"); + is ($stats{'auth_errors'}, 3, "auth errors correct"); }