@@ -386,6 +386,7 @@ user *ACLCreateUser(const char *name, size_t namelen) {
386
386
u -> flags = USER_FLAG_DISABLED ;
387
387
u -> flags |= USER_FLAG_SANITIZE_PAYLOAD ;
388
388
u -> passwords = listCreate ();
389
+ u -> acl_string = NULL ;
389
390
listSetMatchMethod (u -> passwords ,ACLListMatchSds );
390
391
listSetFreeMethod (u -> passwords ,ACLListFreeSds );
391
392
listSetDupMethod (u -> passwords ,ACLListDupSds );
@@ -423,6 +424,10 @@ user *ACLCreateUnlinkedUser(void) {
423
424
* will not remove the user from the Users global radix tree. */
424
425
void ACLFreeUser (user * u ) {
425
426
sdsfree (u -> name );
427
+ if (u -> acl_string ) {
428
+ decrRefCount (u -> acl_string );
429
+ u -> acl_string = NULL ;
430
+ }
426
431
listRelease (u -> passwords );
427
432
listRelease (u -> selectors );
428
433
zfree (u );
@@ -467,6 +472,14 @@ void ACLCopyUser(user *dst, user *src) {
467
472
dst -> passwords = listDup (src -> passwords );
468
473
dst -> selectors = listDup (src -> selectors );
469
474
dst -> flags = src -> flags ;
475
+ if (dst -> acl_string ) {
476
+ decrRefCount (dst -> acl_string );
477
+ }
478
+ dst -> acl_string = src -> acl_string ;
479
+ if (dst -> acl_string ) {
480
+ /* if src is NULL, we set it to NULL, if not, need to increment reference count */
481
+ incrRefCount (dst -> acl_string );
482
+ }
470
483
}
471
484
472
485
/* Free all the users registered in the radix tree 'users' and free the
@@ -803,7 +816,12 @@ sds ACLDescribeSelector(aclSelector *selector) {
803
816
* the ACLDescribeSelectorCommandRules() function. This is the function we call
804
817
* when we want to rewrite the configuration files describing ACLs and
805
818
* in order to show users with ACL LIST. */
806
- sds ACLDescribeUser (user * u ) {
819
+ robj * ACLDescribeUser (user * u ) {
820
+ if (u -> acl_string ) {
821
+ incrRefCount (u -> acl_string );
822
+ return u -> acl_string ;
823
+ }
824
+
807
825
sds res = sdsempty ();
808
826
809
827
/* Flags. */
@@ -837,7 +855,12 @@ sds ACLDescribeUser(user *u) {
837
855
}
838
856
sdsfree (default_perm );
839
857
}
840
- return res ;
858
+
859
+ u -> acl_string = createObject (OBJ_STRING , res );
860
+ /* because we are returning it, have to increase count */
861
+ incrRefCount (u -> acl_string );
862
+
863
+ return u -> acl_string ;
841
864
}
842
865
843
866
/* Get a command from the original command table, that is not affected
@@ -1211,6 +1234,12 @@ int ACLSetSelector(aclSelector *selector, const char* op, size_t oplen) {
1211
1234
* ECHILD: Attempt to allow a specific first argument of a subcommand
1212
1235
*/
1213
1236
int ACLSetUser (user * u , const char * op , ssize_t oplen ) {
1237
+ /* as we are changing the ACL, the old generated string is now invalid */
1238
+ if (u -> acl_string ) {
1239
+ decrRefCount (u -> acl_string );
1240
+ u -> acl_string = NULL ;
1241
+ }
1242
+
1214
1243
if (oplen == -1 ) oplen = strlen (op );
1215
1244
if (oplen == 0 ) return C_OK ; /* Empty string is a no-operation. */
1216
1245
if (!strcasecmp (op ,"on" )) {
@@ -1940,6 +1969,68 @@ sds *ACLMergeSelectorArguments(sds *argv, int argc, int *merged_argc, int *inval
1940
1969
return acl_args ;
1941
1970
}
1942
1971
1972
+ /* takes an acl string already split on spaces and adds it to the given user
1973
+ * if the user object is NULL, will create a user with the given username
1974
+ *
1975
+ * Returns an error as an sds string if the ACL string is not parsable
1976
+ */
1977
+ sds ACLStringSetUser (user * u , sds username , sds * argv , int argc ) {
1978
+ serverAssert (u != NULL || username != NULL );
1979
+
1980
+ sds error = NULL ;
1981
+
1982
+ int merged_argc = 0 , invalid_idx = 0 ;
1983
+ sds * acl_args = ACLMergeSelectorArguments (argv , argc , & merged_argc , & invalid_idx );
1984
+
1985
+ if (!acl_args ) {
1986
+ return sdscatfmt (sdsempty (),
1987
+ "Unmatched parenthesis in acl selector starting "
1988
+ "at '%s'." , (char * ) argv [invalid_idx ]);
1989
+ }
1990
+
1991
+ /* Create a temporary user to validate and stage all changes against
1992
+ * before applying to an existing user or creating a new user. If all
1993
+ * arguments are valid the user parameters will all be applied together.
1994
+ * If there are any errors then none of the changes will be applied. */
1995
+ user * tempu = ACLCreateUnlinkedUser ();
1996
+ if (u ) {
1997
+ ACLCopyUser (tempu , u );
1998
+ }
1999
+
2000
+ for (int j = 0 ; j < merged_argc ; j ++ ) {
2001
+ if (ACLSetUser (tempu ,acl_args [j ],(ssize_t ) sdslen (acl_args [j ])) != C_OK ) {
2002
+ const char * errmsg = ACLSetUserStringError ();
2003
+ error = sdscatfmt (sdsempty (),
2004
+ "Error in ACL SETUSER modifier '%s': %s" ,
2005
+ (char * )acl_args [j ], errmsg );
2006
+ goto cleanup ;
2007
+ }
2008
+ }
2009
+
2010
+ /* Existing pub/sub clients authenticated with the user may need to be
2011
+ * disconnected if (some of) their channel permissions were revoked. */
2012
+ if (u ) {
2013
+ ACLKillPubsubClientsIfNeeded (tempu , u );
2014
+ }
2015
+
2016
+ /* Overwrite the user with the temporary user we modified above. */
2017
+ if (!u ) {
2018
+ u = ACLCreateUser (username ,sdslen (username ));
2019
+ }
2020
+ serverAssert (u != NULL );
2021
+
2022
+ ACLCopyUser (u , tempu );
2023
+
2024
+ cleanup :
2025
+ ACLFreeUser (tempu );
2026
+ for (int i = 0 ; i < merged_argc ; i ++ ) {
2027
+ sdsfree (acl_args [i ]);
2028
+ }
2029
+ zfree (acl_args );
2030
+
2031
+ return error ;
2032
+ }
2033
+
1943
2034
/* Given an argument vector describing a user in the form:
1944
2035
*
1945
2036
* user <username> ... ACL rules and flags ...
@@ -2255,9 +2346,9 @@ int ACLSaveToFile(const char *filename) {
2255
2346
sds user = sdsnew ("user " );
2256
2347
user = sdscatsds (user ,u -> name );
2257
2348
user = sdscatlen (user ," " ,1 );
2258
- sds descr = ACLDescribeUser (u );
2259
- user = sdscatsds (user ,descr );
2260
- sdsfree (descr );
2349
+ robj * descr = ACLDescribeUser (u );
2350
+ user = sdscatsds (user ,descr -> ptr );
2351
+ decrRefCount (descr );
2261
2352
acl = sdscatsds (acl ,user );
2262
2353
acl = sdscatlen (acl ,"\n" ,1 );
2263
2354
sdsfree (user );
@@ -2590,50 +2681,18 @@ void aclCommand(client *c) {
2590
2681
return ;
2591
2682
}
2592
2683
2593
- int merged_argc = 0 , invalid_idx = 0 ;
2684
+ user * u = ACLGetUserByName (username ,sdslen (username ));
2685
+
2594
2686
sds * temp_argv = zmalloc (c -> argc * sizeof (sds ));
2595
2687
for (int i = 3 ; i < c -> argc ; i ++ ) temp_argv [i - 3 ] = c -> argv [i ]-> ptr ;
2596
- sds * acl_args = ACLMergeSelectorArguments (temp_argv , c -> argc - 3 , & merged_argc , & invalid_idx );
2597
- zfree (temp_argv );
2598
-
2599
- if (!acl_args ) {
2600
- addReplyErrorFormat (c ,
2601
- "Unmatched parenthesis in acl selector starting "
2602
- "at '%s'." , (char * ) c -> argv [invalid_idx ]-> ptr );
2603
- return ;
2604
- }
2605
-
2606
- /* Create a temporary user to validate and stage all changes against
2607
- * before applying to an existing user or creating a new user. If all
2608
- * arguments are valid the user parameters will all be applied together.
2609
- * If there are any errors then none of the changes will be applied. */
2610
- user * tempu = ACLCreateUnlinkedUser ();
2611
- user * u = ACLGetUserByName (username ,sdslen (username ));
2612
- if (u ) ACLCopyUser (tempu , u );
2613
2688
2614
- for (int j = 0 ; j < merged_argc ; j ++ ) {
2615
- if (ACLSetUser (tempu ,acl_args [j ],sdslen (acl_args [j ])) != C_OK ) {
2616
- const char * errmsg = ACLSetUserStringError ();
2617
- addReplyErrorFormat (c ,
2618
- "Error in ACL SETUSER modifier '%s': %s" ,
2619
- (char * )acl_args [j ], errmsg );
2620
- goto setuser_cleanup ;
2621
- }
2689
+ sds error = ACLStringSetUser (u , username , temp_argv , c -> argc - 3 );
2690
+ zfree (temp_argv );
2691
+ if (error == NULL ) {
2692
+ addReply (c ,shared .ok );
2693
+ } else {
2694
+ addReplyErrorSdsSafe (c , error );
2622
2695
}
2623
-
2624
- /* Existing pub/sub clients authenticated with the user may need to be
2625
- * disconnected if (some of) their channel permissions were revoked. */
2626
- if (u ) ACLKillPubsubClientsIfNeeded (tempu , u );
2627
-
2628
- /* Overwrite the user with the temporary user we modified above. */
2629
- if (!u ) u = ACLCreateUser (username ,sdslen (username ));
2630
- serverAssert (u != NULL );
2631
- ACLCopyUser (u , tempu );
2632
- addReply (c ,shared .ok );
2633
- setuser_cleanup :
2634
- ACLFreeUser (tempu );
2635
- for (int i = 0 ; i < merged_argc ; i ++ ) sdsfree (acl_args [i ]);
2636
- zfree (acl_args );
2637
2696
return ;
2638
2697
} else if (!strcasecmp (sub ,"deluser" ) && c -> argc >= 3 ) {
2639
2698
int deleted = 0 ;
@@ -2720,9 +2779,9 @@ void aclCommand(client *c) {
2720
2779
sds config = sdsnew ("user " );
2721
2780
config = sdscatsds (config ,u -> name );
2722
2781
config = sdscatlen (config ," " ,1 );
2723
- sds descr = ACLDescribeUser (u );
2724
- config = sdscatsds (config ,descr );
2725
- sdsfree (descr );
2782
+ robj * descr = ACLDescribeUser (u );
2783
+ config = sdscatsds (config ,descr -> ptr );
2784
+ decrRefCount (descr );
2726
2785
addReplyBulkSds (c ,config );
2727
2786
}
2728
2787
}
0 commit comments