Skip to content

Commit 8a0fbb4

Browse files
committed
FEATURE: Add config auth_group command
1 parent fed884c commit 8a0fbb4

File tree

5 files changed

+167
-19
lines changed

5 files changed

+167
-19
lines changed

memcached.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9730,6 +9730,30 @@ static void process_config_auth_command(conn *c, token_t *tokens, const size_t n
97309730
out_string(c, "CLIENT_ERROR bad command line format");
97319731
}
97329732
}
9733+
9734+
static void process_config_auth_group_command(conn *c, token_t *tokens, const size_t ntokens)
9735+
{
9736+
assert(c != NULL);
9737+
char *config_val = tokens[SUBCOMMAND_TOKEN+1].value;
9738+
9739+
if (ntokens == 3) {
9740+
char buf[50];
9741+
char *group_name = sasl_get_auth_group();
9742+
if (group_name) {
9743+
sprintf(buf, "auth_group %s\r\nEND", group_name);
9744+
out_string(c, buf);
9745+
free(group_name);
9746+
} else {
9747+
out_string(c, "SERVER_ERROR internal");
9748+
}
9749+
} else if (ntokens == 4) {
9750+
if (sasl_set_auth_group(config_val) == 0) {
9751+
out_string(c, "END");
9752+
} else {
9753+
out_string(c, "SERVER_ERROR internal");
9754+
}
9755+
}
9756+
}
97339757
#endif
97349758

97359759
static void process_config_command(conn *c, token_t *tokens, const size_t ntokens)
@@ -9810,6 +9834,9 @@ static void process_config_command(conn *c, token_t *tokens, const size_t ntoken
98109834
else if (strcmp(config_key, "auth") == 0) {
98119835
process_config_auth_command(c, tokens, ntokens);
98129836
}
9837+
else if (strcmp(config_key, "auth_group") == 0) {
9838+
process_config_auth_group_command(c, tokens, ntokens);
9839+
}
98139840
#endif
98149841
else {
98159842
print_invalid_command(c, tokens, ntokens);

sasl_auxprop.c

Lines changed: 112 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,21 @@
1717
#define GROUP_MAXLEN 32
1818
#define USERNAME_MAXLEN 32
1919
#define PROPNAME_MAXLEN 32
20-
#define VALUE_MAXLEN 8192 /* from Cyrus SASL's sasldb auxprop plugin */
20+
// 16: buffer for "/arcus_acl", "/" separator, "\0" terminator, etc.
21+
#define SASL_KEY_MAXLEN 16 + GROUP_MAXLEN + USERNAME_MAXLEN + PROPNAME_MAXLEN
22+
#define SASL_VALUE_MAXLEN 8192 /* from Cyrus SASL's sasldb auxprop plugin */
2123

2224
static EXTENSION_LOGGER_DESCRIPTOR *mc_logger = NULL;
2325

2426
static const char *ensemble_list;
25-
// 16: buffer for "/arcus_acl", "/" separator, "\0" terminator, etc.
26-
static char group_zpath[16 + GROUP_MAXLEN];
27+
static char g_group_name[GROUP_MAXLEN];
28+
static volatile bool change_acl_group = false;
29+
static char new_group_name[GROUP_MAXLEN];
30+
static char g_group_zpath[16 + GROUP_MAXLEN];
2731

2832
struct sasl_entry {
2933
struct sasl_entry *next;
30-
char key[sizeof(group_zpath) + USERNAME_MAXLEN + PROPNAME_MAXLEN];
34+
char key[SASL_KEY_MAXLEN];
3135
size_t value_len;
3236
char value[];
3337
};
@@ -84,15 +88,15 @@ static void _table_free(struct sasl_entry **table)
8488
free(table);
8589
}
8690

87-
static struct sasl_entry** get_arcus_acl_table(void)
91+
static struct sasl_entry** get_arcus_acl_table(char *group_zpath)
8892
{
8993
struct sasl_entry **table = NULL;
9094
zhandle_t *zh = NULL;
9195
struct String_vector users;
9296
struct String_vector props;
93-
char user_zpath[sizeof(group_zpath) + USERNAME_MAXLEN];
94-
char prop_zpath[sizeof(user_zpath) + PROPNAME_MAXLEN];
95-
char value[VALUE_MAXLEN];
97+
char user_zpath[16 + GROUP_MAXLEN + USERNAME_MAXLEN];
98+
char prop_zpath[SASL_KEY_MAXLEN];
99+
char value[SASL_VALUE_MAXLEN];
96100
int value_len;
97101
int ret;
98102

@@ -168,6 +172,64 @@ static struct sasl_entry** get_arcus_acl_table(void)
168172
return table;
169173
}
170174

175+
static int validate_new_acl_group(void)
176+
{
177+
char new_group_zpath[16 + GROUP_MAXLEN];
178+
snprintf(new_group_zpath, sizeof(new_group_zpath), "/arcus_acl/%s", new_group_name);
179+
180+
struct sasl_entry **new_table = get_arcus_acl_table(new_group_zpath);
181+
if (!new_table) {
182+
mc_logger->log(EXTENSION_LOG_WARNING, NULL,
183+
"SECURITY_EVENT ACL group change to %s failed: unable to fetch group data\n", new_group_name);
184+
return -1;
185+
}
186+
187+
int origin_group_zpath_len = strlen("/arcus_acl") + strlen(g_group_name) + 2;
188+
char new_key[SASL_KEY_MAXLEN];
189+
struct sasl_entry *new_entry;
190+
bool is_valid = true;
191+
192+
for (int i = 0; i < SASL_TABLE_SIZE; i++) {
193+
struct sasl_entry *old_entry = g_sasltable[i];
194+
while (old_entry) {
195+
snprintf(new_key, sizeof(new_key), "%s/%s",
196+
new_group_zpath, old_entry->key + origin_group_zpath_len);
197+
new_entry = new_table[hash_function(new_key) % SASL_TABLE_SIZE];
198+
while (new_entry) {
199+
if (strcmp(new_entry->key, new_key) == 0 &&
200+
new_entry->value_len == old_entry->value_len &&
201+
memcmp(new_entry->value, old_entry->value, old_entry->value_len) == 0) {
202+
break;
203+
}
204+
new_entry = new_entry->next;
205+
}
206+
if (new_entry == NULL) {
207+
is_valid = false;
208+
break;
209+
}
210+
old_entry = old_entry->next;
211+
}
212+
}
213+
214+
if (is_valid) {
215+
pthread_mutex_lock(&g_sasltable_lock);
216+
struct sasl_entry **old_table = g_sasltable;
217+
g_sasltable = new_table;
218+
snprintf(g_group_name, sizeof(g_group_name), "%s", new_group_name);
219+
snprintf(g_group_zpath, sizeof(g_group_zpath), "%s", new_group_zpath);
220+
pthread_mutex_unlock(&g_sasltable_lock);
221+
_table_free(old_table);
222+
mc_logger->log(EXTENSION_LOG_INFO, NULL,
223+
"SECURITY_EVENT ACL group changed to %s\n", g_group_name);
224+
return 0;
225+
} else {
226+
mc_logger->log(EXTENSION_LOG_WARNING, NULL,
227+
"SECURITY_EVENT ACL group change to %s failed\n", new_group_name);
228+
_table_free(new_table);
229+
return -1;
230+
}
231+
}
232+
171233
static void* acl_refresh_thread(void *arg)
172234
{
173235
struct timespec ts;
@@ -182,9 +244,10 @@ static void* acl_refresh_thread(void *arg)
182244

183245
acl_thread_running = true;
184246
while (!acl_thread_stopreq) {
247+
clock_gettime(CLOCK_REALTIME, &ts);
185248
ts.tv_sec += REFRESH_PERIOD;
186249
pthread_mutex_lock(&acl_thread_lock);
187-
if (!acl_thread_stopreq) {
250+
if (!acl_thread_stopreq && !change_acl_group) {
188251
pthread_cond_timedwait(&acl_thread_cond, &acl_thread_lock, &ts);
189252
}
190253
pthread_mutex_unlock(&acl_thread_lock);
@@ -193,7 +256,8 @@ static void* acl_refresh_thread(void *arg)
193256
}
194257

195258
mc_logger->log(EXTENSION_LOG_INFO, NULL, "ACL refresh started.\n");
196-
new_table = get_arcus_acl_table();
259+
260+
new_table = get_arcus_acl_table(g_group_zpath);
197261
if (new_table != NULL) {
198262
pthread_mutex_lock(&g_sasltable_lock);
199263
old_table = g_sasltable;
@@ -203,6 +267,13 @@ static void* acl_refresh_thread(void *arg)
203267
_table_free(old_table);
204268
}
205269
mc_logger->log(EXTENSION_LOG_INFO, NULL, "ACL refresh %s.\n", new_table ? "completed" : "failed");
270+
271+
if (change_acl_group) {
272+
validate_new_acl_group();
273+
pthread_mutex_lock(&acl_thread_lock);
274+
change_acl_group = false;
275+
pthread_mutex_unlock(&acl_thread_lock);
276+
}
206277
}
207278

208279
pthread_mutex_lock(&g_sasltable_lock);
@@ -223,18 +294,18 @@ static int _arcus_getdata(const char *user,
223294
char *out, const size_t max_out,
224295
size_t *out_len)
225296
{
226-
char key[sizeof(group_zpath) + USERNAME_MAXLEN + PROPNAME_MAXLEN];
297+
char key[sizeof(g_group_zpath) + USERNAME_MAXLEN + PROPNAME_MAXLEN];
298+
pthread_mutex_lock(&g_sasltable_lock);
227299
if (propName) {
228-
snprintf(key, sizeof(key), "%s/%s/%s", group_zpath, user, propName);
300+
snprintf(key, sizeof(key), "%s/%s/%s", g_group_zpath, user, propName);
229301
} else {
230-
snprintf(key, sizeof(key), "%s/%s", group_zpath, user);
302+
snprintf(key, sizeof(key), "%s/%s", g_group_zpath, user);
231303
}
232304

233305
int ret = SASL_NOUSER;
234306
unsigned long index = hash_function(key) % SASL_TABLE_SIZE;
235307
struct sasl_entry *entry;
236308

237-
pthread_mutex_lock(&g_sasltable_lock);
238309
if (g_sasltable) {
239310
entry = g_sasltable[index];
240311
while (entry) {
@@ -261,7 +332,7 @@ static int arcus_auxprop_lookup(void *glob_context __attribute__((unused)),
261332
unsigned ulen)
262333
{
263334
const struct propval *to_fetch, *cur;
264-
char value[VALUE_MAXLEN];
335+
char value[SASL_VALUE_MAXLEN];
265336
size_t value_len;
266337
bool saw_user_password = false;
267338

@@ -395,9 +466,10 @@ int arcus_auxprop_plug_init(const sasl_utils_t *utils,
395466
mc_logger->log(EXTENSION_LOG_WARNING, NULL, "ARCUS_ACL_GROUP environment is not set\n");
396467
return SASL_FAIL;
397468
}
398-
snprintf(group_zpath, sizeof(group_zpath), "/arcus_acl/%s", acl_group);
469+
snprintf(g_group_name, sizeof(g_group_name), "%s", acl_group);
470+
snprintf(g_group_zpath, sizeof(g_group_zpath), "/arcus_acl/%s", acl_group);
399471

400-
g_sasltable = get_arcus_acl_table();
472+
g_sasltable = get_arcus_acl_table(g_group_zpath);
401473
if (!g_sasltable) {
402474
mc_logger->log(EXTENSION_LOG_WARNING, NULL, "Failed to initialize SASL table\n");
403475
return SASL_FAIL;
@@ -428,5 +500,28 @@ void arcus_auxprop_wakeup(void)
428500
pthread_mutex_unlock(&acl_thread_lock);
429501
}
430502

503+
char *arcus_auxprop_get_group(void)
504+
{
505+
char *ret;
506+
pthread_mutex_lock(&g_sasltable_lock);
507+
ret = strdup(g_group_name);
508+
pthread_mutex_unlock(&g_sasltable_lock);
509+
return ret;
510+
}
511+
512+
int arcus_auxprop_set_group(char *group_name)
513+
{
514+
int ret = -1;
515+
pthread_mutex_lock(&acl_thread_lock);
516+
if (!change_acl_group) {
517+
snprintf(new_group_name, sizeof(new_group_name), "%s", group_name);
518+
change_acl_group = true;
519+
ret = 0;
520+
}
521+
pthread_cond_signal(&acl_thread_cond);
522+
pthread_mutex_unlock(&acl_thread_lock);
523+
return ret;
524+
}
525+
431526
#endif /* ENABLE_ZK_INTEGRATION */
432527
#endif /* ENABLE_SASL */

sasl_auxprop.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ int arcus_auxprop_plug_init(const sasl_utils_t *utils,
2020
int arcus_getdata(const char *user, char *out, const size_t max_out);
2121

2222
void arcus_auxprop_wakeup(void);
23+
char *arcus_auxprop_get_group(void);
24+
int arcus_auxprop_set_group(char *group_name);
2325

2426
#endif /* ENABLE_ZK_INTEGRATION */
2527
#endif /* ENABLE_SASL */

sasl_defs.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
#include <string.h>
88
#include "sasl_auxprop.h"
99

10+
#if defined(ENABLE_SASL) && defined(ENABLE_ZK_INTEGRATION)
11+
static bool use_acl_zookeeper = false;
12+
#endif
13+
1014
const char *sasl_engine_string(void)
1115
{
1216
#if defined(ENABLE_SASL)
@@ -31,10 +35,26 @@ void sasl_get_auth_data(sasl_conn_t *conn, auth_data_t *data)
3135
#endif
3236
}
3337
}
38+
39+
char *sasl_get_auth_group(void)
40+
{
41+
#ifdef ENABLE_ZK_INTEGRATION
42+
if (use_acl_zookeeper) {
43+
return arcus_auxprop_get_group();
44+
}
3445
#endif
46+
return NULL;
47+
}
3548

36-
#if defined(ENABLE_SASL) && defined(ENABLE_ZK_INTEGRATION)
37-
static bool use_acl_zookeeper = false;
49+
int sasl_set_auth_group(char *group_name)
50+
{
51+
#ifdef ENABLE_ZK_INTEGRATION
52+
if (use_acl_zookeeper) {
53+
return arcus_auxprop_set_group(group_name);
54+
}
55+
#endif
56+
return -1;
57+
}
3858
#endif
3959

4060
#ifdef ENABLE_SASL_PWDB

sasl_defs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ int init_sasl(EXTENSION_LOGGER_DESCRIPTOR *logger);
1515
void shutdown_sasl(void);
1616
int reload_sasl(void);
1717
void sasl_get_auth_data(sasl_conn_t *conn, auth_data_t *data);
18+
char *sasl_get_auth_group(void);
19+
int sasl_set_auth_group(char *group_name);
1820

1921

2022
#elif defined(ENABLE_ISASL)
@@ -27,6 +29,8 @@ int init_sasl(EXTENSION_LOGGER_DESCRIPTOR *logger);
2729
void shutdown_sasl(void);
2830
int reload_sasl(void);
2931
void sasl_get_auth_data(sasl_conn_t *conn, auth_data_t *data);
32+
char *sasl_get_auth_group(void);
33+
int sasl_set_auth_group(char *group_name);
3034

3135
#endif /* End of SASL support */
3236

0 commit comments

Comments
 (0)