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
2224static EXTENSION_LOGGER_DESCRIPTOR * mc_logger = NULL ;
2325
2426static 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
2832struct 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+
171233static 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 */
0 commit comments