Blame SOURCES/memcached-CVE-2013-7239.patch

77eb1b
commit 87c1cf0f20be20608d3becf854e9cf0910f4ad32
77eb1b
Author: 伊藤洋也 <hiroyan@gmail.com>
77eb1b
Date:   Fri Dec 20 18:49:54 2013 +0000
77eb1b
77eb1b
    explicitly record sasl auth states
77eb1b
    
77eb1b
    It was previously possible to bypass authentication due to implicit
77eb1b
    state management.  Now we explicitly consider ourselves
77eb1b
    unauthenticated on any new connections and authentication attempts.
77eb1b
    
77eb1b
    bug316
77eb1b
    
77eb1b
    Signed-off-by: Dustin Sallings <dustin@spy.net>
77eb1b
77eb1b
diff --git a/memcached.c b/memcached.c
77eb1b
index f129865..3a79fba 100644
77eb1b
--- a/memcached.c
77eb1b
+++ b/memcached.c
77eb1b
@@ -457,6 +457,7 @@ conn *conn_new(const int sfd, enum conn_states init_state,
77eb1b
     c->iovused = 0;
77eb1b
     c->msgcurr = 0;
77eb1b
     c->msgused = 0;
77eb1b
+    c->authenticated = false;
77eb1b
 
77eb1b
     c->write_and_go = init_state;
77eb1b
     c->write_and_free = 0;
77eb1b
@@ -1637,6 +1638,8 @@ static void init_sasl_conn(conn *c) {
77eb1b
     if (!settings.sasl)
77eb1b
         return;
77eb1b
 
77eb1b
+    c->authenticated = false;
77eb1b
+
77eb1b
     if (!c->sasl_conn) {
77eb1b
         int result=sasl_server_new("memcached",
77eb1b
                                    NULL,
77eb1b
@@ -1771,6 +1774,7 @@ static void process_bin_complete_sasl_auth(conn *c) {
77eb1b
 
77eb1b
     switch(result) {
77eb1b
     case SASL_OK:
77eb1b
+        c->authenticated = true;
77eb1b
         write_bin_response(c, "Authenticated", 0, 0, strlen("Authenticated"));
77eb1b
         pthread_mutex_lock(&c->thread->stats.mutex);
77eb1b
         c->thread->stats.auth_cmds++;
77eb1b
@@ -1807,11 +1811,7 @@ static bool authenticated(conn *c) {
77eb1b
         rv = true;
77eb1b
         break;
77eb1b
     default:
77eb1b
-        if (c->sasl_conn) {
77eb1b
-            const void *uname = NULL;
77eb1b
-            sasl_getprop(c->sasl_conn, SASL_USERNAME, &uname);
77eb1b
-            rv = uname != NULL;
77eb1b
-        }
77eb1b
+        rv = c->authenticated;
77eb1b
     }
77eb1b
 
77eb1b
     if (settings.verbose > 1) {
77eb1b
diff --git a/memcached.h b/memcached.h
77eb1b
index 45b3213..7c212d5 100644
77eb1b
--- a/memcached.h
77eb1b
+++ b/memcached.h
77eb1b
@@ -376,6 +376,7 @@ typedef struct conn conn;
77eb1b
 struct conn {
77eb1b
     int    sfd;
77eb1b
     sasl_conn_t *sasl_conn;
77eb1b
+    bool authenticated;
77eb1b
     enum conn_states  state;
77eb1b
     enum bin_substates substate;
77eb1b
     struct event event;
77eb1b
diff --git a/t/binary-sasl.t b/t/binary-sasl.t
77eb1b
index 69a05c2..85ef069 100755
77eb1b
--- a/t/binary-sasl.t
77eb1b
+++ b/t/binary-sasl.t
77eb1b
@@ -13,7 +13,7 @@ use Test::More;
77eb1b
 
77eb1b
 if (supports_sasl()) {
77eb1b
     if ($ENV{'RUN_SASL_TESTS'}) {
77eb1b
-        plan tests => 25;
77eb1b
+        plan tests => 33;
77eb1b
     } else {
77eb1b
         plan skip_all => 'Skipping SASL tests';
77eb1b
         exit 0;
77eb1b
@@ -229,6 +229,38 @@ $check->('x','somevalue');
77eb1b
 }
77eb1b
 $empty->('x');
77eb1b
 
77eb1b
+{
77eb1b
+    my $mc = MC::Client->new;
77eb1b
+
77eb1b
+    # Attempt bad authentication.
77eb1b
+    is ($mc->authenticate('testuser', 'wrongpassword'), 0x20, "bad auth");
77eb1b
+
77eb1b
+    # This should fail because $mc is not authenticated
77eb1b
+    my ($status, $val)= $mc->set('x', "somevalue");
77eb1b
+    ok($status, "this fails to authenticate");
77eb1b
+    cmp_ok($status,'==',ERR_AUTH_ERROR, "error code matches");
77eb1b
+}
77eb1b
+$empty->('x', 'somevalue');
77eb1b
+
77eb1b
+{
77eb1b
+    my $mc = MC::Client->new;
77eb1b
+
77eb1b
+    # Attempt bad authentication.
77eb1b
+    is ($mc->authenticate('testuser', 'wrongpassword'), 0x20, "bad auth");
77eb1b
+
77eb1b
+    # Mix an authenticated connection and an unauthenticated connection to
77eb1b
+    # confirm c->authenticated is not shared among connections
77eb1b
+    my $mc2 = MC::Client->new;
77eb1b
+    is ($mc2->authenticate('testuser', 'testpass'), 0, "authenticated");
77eb1b
+    my ($status, $val)= $mc2->set('x', "somevalue");
77eb1b
+    ok(! $status);
77eb1b
+
77eb1b
+    # This should fail because $mc is not authenticated
77eb1b
+    ($status, $val)= $mc->set('x', "somevalue");
77eb1b
+    ok($status, "this fails to authenticate");
77eb1b
+    cmp_ok($status,'==',ERR_AUTH_ERROR, "error code matches");
77eb1b
+}
77eb1b
+
77eb1b
 # check the SASL stats, make sure they track things correctly
77eb1b
 # note: the enabled or not is presence checked in stats.t
77eb1b
 
77eb1b
@@ -241,8 +273,8 @@ $empty->('x');
77eb1b
 
77eb1b
 {
77eb1b
     my %stats = $mc->stats('');
77eb1b
-    is ($stats{'auth_cmds'}, 2, "auth commands counted");
77eb1b
-    is ($stats{'auth_errors'}, 1, "auth errors correct");
77eb1b
+    is ($stats{'auth_cmds'}, 5, "auth commands counted");
77eb1b
+    is ($stats{'auth_errors'}, 3, "auth errors correct");
77eb1b
 }
77eb1b
 
77eb1b