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
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 [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+
171232static 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 */
0 commit comments