|
|
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 |
|