Skip to content

Commit d4cb819

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

File tree

5 files changed

+165
-16
lines changed

5 files changed

+165
-16
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: 110 additions & 14 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+
// 16: buffer for "/arcus_acl", "/" separator, "\0" terminator, etc.
21+
#define TABLE_KEY_LEN 16 + GROUP_MAXLEN + USERNAME_MAXLEN + PROPNAME_MAXLEN
2022
#define 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[TABLE_KEY_LEN];
3135
size_t value_len;
3236
char value[];
3337
};
@@ -84,14 +88,14 @@ 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];
97+
char user_zpath[16 + GROUP_MAXLEN + USERNAME_MAXLEN];
98+
char prop_zpath[TABLE_KEY_LEN];
9599
char value[VALUE_MAXLEN];
96100
int value_len;
97101
int ret;
@@ -168,6 +172,63 @@ 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[TABLE_KEY_LEN];
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+
mc_logger->log(EXTENSION_LOG_WARNING, NULL,
203+
"SECURITY_EVENT ACL group change to %s failed: missing key %s\n",
204+
new_group_name, old_entry->key);
205+
break;
206+
}
207+
new_entry = new_entry->next;
208+
}
209+
if (new_entry == NULL) {
210+
is_valid = false;
211+
break;
212+
}
213+
old_entry = old_entry->next;
214+
}
215+
}
216+
217+
if (is_valid) {
218+
pthread_mutex_lock(&g_sasltable_lock);
219+
struct sasl_entry **old_table = g_sasltable;
220+
g_sasltable = new_table;
221+
snprintf(g_group_name, sizeof(g_group_name), "%s", new_group_name);
222+
snprintf(g_group_zpath, sizeof(g_group_zpath), "%s", new_group_zpath);
223+
pthread_mutex_unlock(&g_sasltable_lock);
224+
_table_free(old_table);
225+
return 0;
226+
} else {
227+
_table_free(new_table);
228+
return -1;
229+
}
230+
}
231+
171232
static void* acl_refresh_thread(void *arg)
172233
{
173234
struct timespec ts;
@@ -184,7 +245,7 @@ static void* acl_refresh_thread(void *arg)
184245
while (!acl_thread_stopreq) {
185246
ts.tv_sec += REFRESH_PERIOD;
186247
pthread_mutex_lock(&acl_thread_lock);
187-
if (!acl_thread_stopreq) {
248+
if (!acl_thread_stopreq && !change_acl_group) {
188249
pthread_cond_timedwait(&acl_thread_cond, &acl_thread_lock, &ts);
189250
}
190251
pthread_mutex_unlock(&acl_thread_lock);
@@ -193,7 +254,8 @@ static void* acl_refresh_thread(void *arg)
193254
}
194255

195256
mc_logger->log(EXTENSION_LOG_INFO, NULL, "ACL refresh started.\n");
196-
new_table = get_arcus_acl_table();
257+
258+
new_table = get_arcus_acl_table(g_group_zpath);
197259
if (new_table != NULL) {
198260
pthread_mutex_lock(&g_sasltable_lock);
199261
old_table = g_sasltable;
@@ -202,6 +264,16 @@ static void* acl_refresh_thread(void *arg)
202264

203265
_table_free(old_table);
204266
}
267+
268+
if (change_acl_group) {
269+
int ret = validate_new_acl_group();
270+
pthread_mutex_lock(&acl_thread_lock);
271+
change_acl_group = false;
272+
pthread_mutex_unlock(&acl_thread_lock);
273+
if (ret == 0) {
274+
mc_logger->log(EXTENSION_LOG_INFO, NULL, "SECURITY_EVENT ACL group changed to: %s\n", g_group_name);
275+
}
276+
}
205277
mc_logger->log(EXTENSION_LOG_INFO, NULL, "ACL refresh %s.\n", new_table ? "completed" : "failed");
206278
}
207279

@@ -223,18 +295,18 @@ static int _arcus_getdata(const char *user,
223295
char *out, const size_t max_out,
224296
size_t *out_len)
225297
{
226-
char key[sizeof(group_zpath) + USERNAME_MAXLEN + PROPNAME_MAXLEN];
298+
char key[sizeof(g_group_zpath) + USERNAME_MAXLEN + PROPNAME_MAXLEN];
299+
pthread_mutex_lock(&g_sasltable_lock);
227300
if (propName) {
228-
snprintf(key, sizeof(key), "%s/%s/%s", group_zpath, user, propName);
301+
snprintf(key, sizeof(key), "%s/%s/%s", g_group_zpath, user, propName);
229302
} else {
230-
snprintf(key, sizeof(key), "%s/%s", group_zpath, user);
303+
snprintf(key, sizeof(key), "%s/%s", g_group_zpath, user);
231304
}
232305

233306
int ret = SASL_NOUSER;
234307
unsigned long index = hash_function(key) % SASL_TABLE_SIZE;
235308
struct sasl_entry *entry;
236309

237-
pthread_mutex_lock(&g_sasltable_lock);
238310
if (g_sasltable) {
239311
entry = g_sasltable[index];
240312
while (entry) {
@@ -395,9 +467,10 @@ int arcus_auxprop_plug_init(const sasl_utils_t *utils,
395467
mc_logger->log(EXTENSION_LOG_WARNING, NULL, "ARCUS_ACL_GROUP environment is not set\n");
396468
return SASL_FAIL;
397469
}
398-
snprintf(group_zpath, sizeof(group_zpath), "/arcus_acl/%s", acl_group);
470+
snprintf(g_group_name, sizeof(g_group_name), "%s", acl_group);
471+
snprintf(g_group_zpath, sizeof(g_group_zpath), "/arcus_acl/%s", acl_group);
399472

400-
g_sasltable = get_arcus_acl_table();
473+
g_sasltable = get_arcus_acl_table(g_group_zpath);
401474
if (!g_sasltable) {
402475
mc_logger->log(EXTENSION_LOG_WARNING, NULL, "Failed to initialize SASL table\n");
403476
return SASL_FAIL;
@@ -428,5 +501,28 @@ void arcus_auxprop_wakeup(void)
428501
pthread_mutex_unlock(&acl_thread_lock);
429502
}
430503

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