Skip to content
This repository was archived by the owner on Mar 21, 2025. It is now read-only.

Commit 93b6117

Browse files
committed
add commands-need-adminpass config option.
1 parent bd761a3 commit 93b6117

File tree

7 files changed

+159
-29
lines changed

7 files changed

+159
-29
lines changed

conf/vire.conf

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ internal-dbs-per-databases 6
6666
#
6767
# adminpass iamadmin
6868

69+
# Make some commands need adminpass to execute. Those commands just allowed
70+
# administrator to execute. This might be useful to prevent users from
71+
# doing some dangerous actions to the host running Vire.
72+
#
73+
# commands-need-adminpass flushall flushdb keys config
74+
6975
################################### CLIENTS ####################################
7076

7177
# Set the max number of connected clients at the same time. By default

src/vr_command.c

+23
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,29 @@ void populateCommandTable(void) {
216216
}
217217
}
218218

219+
int populateCommandsNeedAdminpass(void) {
220+
struct array commands_need_adminpass;
221+
sds *command_name;
222+
struct redisCommand *command;
223+
224+
array_init(&commands_need_adminpass,1,sizeof(sds));
225+
conf_server_get(CONFIG_SOPN_COMMANDSNAP,&commands_need_adminpass);
226+
while (array_n(&commands_need_adminpass)) {
227+
command_name = array_pop(&commands_need_adminpass);
228+
command = lookupCommand(*command_name);
229+
if (command == NULL) {
230+
log_error("Unknow command %s for commands-need-amdminpass",
231+
command_name);
232+
return VR_ERROR;
233+
}
234+
command->needadmin = 1;
235+
sdsfree(*command_name);
236+
}
237+
array_deinit(&commands_need_adminpass);
238+
239+
return VR_OK;
240+
}
241+
219242
struct redisCommand *lookupCommand(sds name) {
220243
return dictFetchValue(server.commands, name);
221244
}

src/vr_command.h

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ typedef struct redisOpArray {
9090
extern dictType commandTableDictType;
9191

9292
void populateCommandTable(void);
93+
int populateCommandsNeedAdminpass(void);
94+
9395
struct redisCommand *lookupCommand(sds name);
9496
struct redisCommand *lookupCommandOrOriginal(sds name);
9597
struct redisCommand *lookupCommandByCString(char *s);

src/vr_conf.c

+95-5
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ static conf_option conf_server_options[] = {
109109
CONF_FIELD_TYPE_SDS, 0,
110110
conf_set_password, conf_get_sds,
111111
offsetof(conf_server, adminpass) },
112+
{ (char *)CONFIG_SOPN_COMMANDSNAP,
113+
CONF_FIELD_TYPE_ARRAYSDS, 1,
114+
conf_set_commands_need_adminpass, conf_get_array_sds,
115+
offsetof(conf_server, commands_need_adminpass) },
112116
{ NULL, NULL, 0 }
113117
};
114118

@@ -579,6 +583,53 @@ conf_set_array_sds(void *obj, conf_option *opt, void *data)
579583
return VR_OK;
580584
}
581585

586+
int
587+
conf_set_commands_need_adminpass(void *obj, conf_option *opt, void *data)
588+
{
589+
uint8_t *p;
590+
uint32_t j;
591+
conf_value **cv_sub, *cv = data;
592+
struct array *gt;
593+
sds *str;
594+
595+
if(cv->type != CONF_VALUE_TYPE_STRING &&
596+
cv->type != CONF_VALUE_TYPE_ARRAY){
597+
log_error("conf pool %s in the conf file is not a string or array",
598+
opt->name);
599+
return VR_ERROR;
600+
} else if (cv->type == CONF_VALUE_TYPE_ARRAY) {
601+
cv_sub = array_get(cv->value, j);
602+
if ((*cv_sub)->type != CONF_VALUE_TYPE_STRING) {
603+
log_error("conf pool %s in the conf file is not a string array",
604+
opt->name);
605+
return VR_ERROR;
606+
}
607+
}
608+
609+
CONF_WLOCK();
610+
p = obj;
611+
gt = (struct array*)(p + opt->offset);
612+
613+
while (array_n(gt) > 0) {
614+
str = array_pop(gt);
615+
sdsfree(*str);
616+
}
617+
618+
if (cv->type == CONF_VALUE_TYPE_STRING) {
619+
str = array_push(gt);
620+
*str = sdsdup(cv->value);
621+
} else if (cv->type == CONF_VALUE_TYPE_ARRAY) {
622+
for (j = 0; j < array_n(cv->value); j ++) {
623+
cv_sub = array_get(cv->value, j);
624+
str = array_push(gt);
625+
*str = sdsdup((*cv_sub)->value);
626+
}
627+
}
628+
conf->version ++;
629+
CONF_UNLOCK();
630+
return VR_OK;
631+
}
632+
582633
int
583634
conf_get_array_sds(void *obj, conf_option *opt, void *data)
584635
{
@@ -724,6 +775,7 @@ static int conf_server_init(conf_server *cs)
724775
cs->requirepass = CONF_UNSET_PTR;
725776
cs->adminpass = CONF_UNSET_PTR;
726777
cs->dir = CONF_UNSET_PTR;
778+
array_init(&cs->commands_need_adminpass,1,sizeof(sds));
727779

728780
return VR_OK;
729781
}
@@ -768,6 +820,11 @@ static int conf_server_set_default(conf_server *cs)
768820
}
769821
cs->dir = sdsnew(CONFIG_DEFAULT_DATA_DIR);
770822

823+
while (array_n(&cs->commands_need_adminpass) > 0) {
824+
str = array_pop(&cs->commands_need_adminpass);
825+
sdsfree(*str);
826+
}
827+
771828
return VR_OK;
772829
}
773830

@@ -809,6 +866,12 @@ static void conf_server_deinit(conf_server *cs)
809866
sdsfree(cs->adminpass);
810867
cs->adminpass = CONF_UNSET_PTR;
811868
}
869+
870+
while (array_n(&cs->commands_need_adminpass) > 0) {
871+
str = array_pop(&cs->commands_need_adminpass);
872+
sdsfree(*str);
873+
}
874+
array_deinit(&cs->commands_need_adminpass);
812875
}
813876

814877
int
@@ -1497,9 +1560,7 @@ static void addReplyConfOption(client *c,conf_option *cop)
14971560

14981561
static void configGetCommand(client *c) {
14991562
robj *o = c->argv[2];
1500-
void *replylen = addDeferredMultiBulkLength(c);
15011563
char *pattern = o->ptr;
1502-
int matches = 0;
15031564
conf_option *cop;
15041565
serverAssertWithInfo(c,o,sdsEncodedObject(o));
15051566

@@ -1508,12 +1569,14 @@ static void configGetCommand(client *c) {
15081569
/* Don't show adminpass if user has no right. */
15091570
if (!strcmp(cop->name,CONFIG_SOPN_ADMINPASS) &&
15101571
c->vel->cc.adminpass && c->authenticated < 2) {
1511-
/* Nothing to show */
1572+
addReply(c,shared.noadminerr);
15121573
} else {
1574+
addReplyMultiBulkLen(c,2);
15131575
addReplyConfOption(c,cop);
1514-
matches ++;
15151576
}
15161577
} else {
1578+
int matches = 0;
1579+
void * replylen = addDeferredMultiBulkLength(c);
15171580
for (cop = conf_server_options; cop&&cop->name; cop++) {
15181581
if (stringmatch(pattern,cop->name,1)) {
15191582
/* Don't show adminpass if user has no right. */
@@ -1525,8 +1588,8 @@ static void configGetCommand(client *c) {
15251588
matches ++;
15261589
}
15271590
}
1591+
setDeferredMultiBulkLength(c,replylen,matches*2);
15281592
}
1529-
setDeferredMultiBulkLength(c,replylen,matches*2);
15301593
}
15311594

15321595
/*-----------------------------------------------------------------------------
@@ -1952,6 +2015,32 @@ static void rewriteConfigBindOption(struct rewriteConfigState *state) {
19522015
rewriteConfigRewriteLine(state,option,line,force);
19532016
}
19542017

2018+
/* Rewrite the save option. */
2019+
void rewriteConfigCommandsNAPOption(struct rewriteConfigState *state) {
2020+
struct array values;
2021+
sds *value, line;
2022+
int force = 1;
2023+
char *option = CONFIG_SOPN_COMMANDSNAP;
2024+
2025+
array_init(&values,1,sizeof(sds));
2026+
conf_server_get(option,&values);
2027+
/* Nothing to rewrite if we don't have commands that need adminpass. */
2028+
if (array_n(&values) == 0) {
2029+
array_deinit(&values);
2030+
rewriteConfigMarkAsProcessed(state,option);
2031+
return;
2032+
}
2033+
2034+
while(array_n(&values) > 0) {
2035+
value = array_pop(&values);
2036+
line = sdscatprintf(sdsempty(),"%s %s",option,*value);
2037+
rewriteConfigRewriteLine(state,option,line,force);
2038+
sdsfree(*value);
2039+
}
2040+
array_deinit(&values);
2041+
rewriteConfigMarkAsProcessed(state,option);
2042+
}
2043+
19552044
/* Rewrite the configuration file at "path".
19562045
* If the configuration file already exists, we try at best to retain comments
19572046
* and overall structure.
@@ -1989,6 +2078,7 @@ static int rewriteConfig(char *path) {
19892078
rewriteConfigIntOption(state,CONFIG_SOPN_MAXCLIENTS,CONFIG_DEFAULT_MAX_CLIENTS);
19902079
rewriteConfigSdsOption(state,CONFIG_SOPN_REQUIREPASS,NULL);
19912080
rewriteConfigSdsOption(state,CONFIG_SOPN_ADMINPASS,NULL);
2081+
rewriteConfigCommandsNAPOption(state);
19922082

19932083
/* Step 3: remove all the orphaned lines in the old file, that is, lines
19942084
* that were used by a config option and are no longer used, like in case

src/vr_conf.h

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define CONFIG_SOPN_SLOWLOGML "slowlog-max-len"
1818
#define CONFIG_SOPN_REQUIREPASS "requirepass"
1919
#define CONFIG_SOPN_ADMINPASS "adminpass"
20+
#define CONFIG_SOPN_COMMANDSNAP "commands-need-adminpass"
2021

2122
#define CONFIG_RUN_ID_SIZE 40
2223
#define CONFIG_DEFAULT_ACTIVE_REHASHING 1
@@ -111,6 +112,7 @@ typedef struct conf_server {
111112

112113
sds requirepass; /* Pass for AUTH command, or NULL */
113114
sds adminpass; /* Pass for ADMIN command, or NULL */
115+
struct array commands_need_adminpass;
114116
} conf_server;
115117

116118
typedef struct vr_conf {
@@ -176,6 +178,7 @@ int conf_set_int(void *obj, conf_option *opt, void *data);
176178
int conf_set_longlong(void *obj, conf_option *opt, void *data);
177179
int conf_set_yesorno(void *obj, conf_option *opt, void *data);
178180
int conf_set_array_sds(void *obj, conf_option *opt, void *data);
181+
int conf_set_commands_need_adminpass(void *obj, conf_option *opt, void *data);
179182

180183
int CONF_RLOCK(void);
181184
int CONF_WLOCK(void);

src/vr_server.c

+29-23
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,36 @@ static void createSharedObjects(void) {
300300
}
301301
}
302302

303-
rstatus_t
303+
int
304304
init_server(struct instance *nci)
305305
{
306-
rstatus_t status;
306+
int ret;
307307
uint32_t i;
308308
redisDb *db;
309+
310+
server.pid = getpid();
311+
server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
312+
server.starttime = time(NULL);
313+
get_random_hex_chars(server.runid, CONFIG_RUN_ID_SIZE);
314+
315+
server.commands = dictCreate(&commandTableDictType,NULL);
316+
populateCommandTable();
317+
server.delCommand = lookupCommandByCString("del");
318+
server.multiCommand = lookupCommandByCString("multi");
319+
server.lpushCommand = lookupCommandByCString("lpush");
320+
server.lpopCommand = lookupCommandByCString("lpop");
321+
server.rpopCommand = lookupCommandByCString("rpop");
322+
server.sremCommand = lookupCommandByCString("srem");
323+
server.execCommand = lookupCommandByCString("exec");
309324

310325
conf = conf_create(nci->conf_filename);
311326

312-
server.pid = getpid();
327+
ret = populateCommandsNeedAdminpass();
328+
if (ret != VR_OK) {
329+
log_error("Populate need adminpass commands failed");
330+
return VR_ERROR;
331+
}
332+
313333
server.configfile = getAbsolutePath(nci->conf_filename);
314334
server.hz = 10;
315335
server.dblnum = cserver->databases;
@@ -319,23 +339,9 @@ init_server(struct instance *nci)
319339
server.pidfile = nci->pid_filename;
320340
server.executable = NULL;
321341
server.activerehashing = CONFIG_DEFAULT_ACTIVE_REHASHING;
322-
get_random_hex_chars(server.runid, CONFIG_RUN_ID_SIZE);
323-
server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
324-
325-
server.starttime = time(NULL);
326342

327343
server.client_max_querybuf_len = PROTO_MAX_QUERYBUF_LEN;
328344

329-
server.commands = dictCreate(&commandTableDictType,NULL);
330-
populateCommandTable();
331-
server.delCommand = lookupCommandByCString("del");
332-
server.multiCommand = lookupCommandByCString("multi");
333-
server.lpushCommand = lookupCommandByCString("lpush");
334-
server.lpopCommand = lookupCommandByCString("lpop");
335-
server.rpopCommand = lookupCommandByCString("rpop");
336-
server.sremCommand = lookupCommandByCString("srem");
337-
server.execCommand = lookupCommandByCString("exec");
338-
339345
for (i = 0; i < server.dbnum; i ++) {
340346
db = array_push(&server.dbs);
341347
redisDbInit(db);
@@ -379,16 +385,16 @@ init_server(struct instance *nci)
379385
server.port = cserver->port;
380386

381387
/* Init worker first */
382-
status = workers_init(nci->thread_num);
383-
if (status != VR_OK) {
384-
log_error("init worker threads failed");
388+
ret = workers_init(nci->thread_num);
389+
if (ret != VR_OK) {
390+
log_error("Init worker threads failed");
385391
return VR_ERROR;
386392
}
387393

388394
/* Init master after worker init */
389-
status = master_init(conf);
390-
if (status != VR_OK) {
391-
log_error("init master thread failed");
395+
ret = master_init(conf);
396+
if (ret != VR_OK) {
397+
log_error("Init master thread failed");
392398
return VR_ERROR;
393399
}
394400

src/vr_server.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ unsigned int dictObjHash(const void *key);
335335
int dictObjKeyCompare(void *privdata, const void *key1, const void *key2);
336336
void dictListDestructor(void *privdata, void *val);
337337

338-
rstatus_t init_server(struct instance *nci);
338+
int init_server(struct instance *nci);
339339

340340
unsigned int getLRUClock(void);
341341

0 commit comments

Comments
 (0)