Revision e0a45fb4
client/client.c | ||
---|---|---|
25 | 25 |
#include "client/client.h" |
26 | 26 |
#include "sysdep/unix/unix.h" |
27 | 27 |
|
28 |
static char *opt_list = "s:v"; |
|
28 |
static char *opt_list = "s:vr";
|
|
29 | 29 |
static int verbose; |
30 |
static char *init_cmd; |
|
31 |
static int once; |
|
30 | 32 |
|
31 | 33 |
static char *server_path = PATH_CONTROL_SOCKET; |
32 | 34 |
static int server_fd; |
... | ... | |
49 | 51 |
static void |
50 | 52 |
usage(void) |
51 | 53 |
{ |
52 |
fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v]\n"); |
|
54 |
fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v] [-r]\n");
|
|
53 | 55 |
exit(1); |
54 | 56 |
} |
55 | 57 |
|
... | ... | |
67 | 69 |
case 'v': |
68 | 70 |
verbose++; |
69 | 71 |
break; |
72 |
case 'r': |
|
73 |
init_cmd = "restrict"; |
|
74 |
break; |
|
70 | 75 |
default: |
71 | 76 |
usage(); |
72 | 77 |
} |
78 |
|
|
79 |
/* If some arguments are not options, we take it as commands */ |
|
73 | 80 |
if (optind < argc) |
74 |
usage(); |
|
81 |
{ |
|
82 |
char *tmp; |
|
83 |
int i; |
|
84 |
int len = 0; |
|
85 |
|
|
86 |
if (init_cmd) |
|
87 |
usage(); |
|
88 |
|
|
89 |
for (i = optind; i < argc; i++) |
|
90 |
len += strlen(argv[i]) + 1; |
|
91 |
|
|
92 |
tmp = init_cmd = malloc(len); |
|
93 |
for (i = optind; i < argc; i++) |
|
94 |
{ |
|
95 |
strcpy(tmp, argv[i]); |
|
96 |
tmp += strlen(tmp); |
|
97 |
*tmp++ = ' '; |
|
98 |
} |
|
99 |
|
|
100 |
once = 1; |
|
101 |
} |
|
75 | 102 |
} |
76 | 103 |
|
77 | 104 |
/*** Input ***/ |
... | ... | |
267 | 294 |
if (nstate == cstate) |
268 | 295 |
return; |
269 | 296 |
|
297 |
if (init_cmd) |
|
298 |
{ |
|
299 |
/* First transition - client received hello from BIRD |
|
300 |
and there is waiting initial command */ |
|
301 |
submit_server_command(init_cmd); |
|
302 |
init_cmd = NULL; |
|
303 |
return; |
|
304 |
} |
|
305 |
|
|
306 |
if (!init_cmd && once) |
|
307 |
{ |
|
308 |
/* Initial command is finished and we want to exit */ |
|
309 |
cleanup(); |
|
310 |
exit(0); |
|
311 |
} |
|
312 |
|
|
270 | 313 |
if (nstate == STATE_PROMPT) |
271 | 314 |
if (input_initialized) |
272 | 315 |
input_reveal(); |
doc/reply_codes | ||
---|---|---|
24 | 24 |
0013 Status report |
25 | 25 |
0014 Route count |
26 | 26 |
0015 Reloading |
27 |
0016 Access restricted |
|
27 | 28 |
|
28 | 29 |
1000 BIRD version |
29 | 30 |
1001 Interface list |
... | ... | |
51 | 52 |
8004 Stopped due to reconfiguration |
52 | 53 |
8005 Protocol is down => cannot dump |
53 | 54 |
8006 Reload failed |
55 |
8007 Access denied |
|
54 | 56 |
|
55 | 57 |
9000 Command too long |
56 | 58 |
9001 Parse error |
nest/cli.h | ||
---|---|---|
33 | 33 |
void (*cleanup)(struct cli *c); |
34 | 34 |
void *rover; /* Private to continuation routine */ |
35 | 35 |
int last_reply; |
36 |
int restricted; /* CLI is restricted to read-only commands */ |
|
36 | 37 |
struct linpool *parser_pool; /* Pool used during parsing */ |
37 | 38 |
byte *ring_buf; /* Ring buffer for asynchronous messages */ |
38 | 39 |
byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */ |
... | ... | |
60 | 61 |
void cli_written(cli *); |
61 | 62 |
void cli_echo(unsigned int class, byte *msg); |
62 | 63 |
|
64 |
static inline int cli_access_restricted(void) |
|
65 |
{ |
|
66 |
if (this_cli && this_cli->restricted) |
|
67 |
return (cli_printf(this_cli, 8007, "Access denied"), 1); |
|
68 |
else |
|
69 |
return 0; |
|
70 |
} |
|
71 |
|
|
63 | 72 |
/* Functions provided by sysdep layer */ |
64 | 73 |
|
65 | 74 |
void cli_write_trigger(cli *); |
nest/config.Y | ||
---|---|---|
45 | 45 |
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) |
46 | 46 |
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) |
47 | 47 |
CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION) |
48 |
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES) |
|
48 |
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT)
|
|
49 | 49 |
|
50 | 50 |
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, |
51 | 51 |
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) |
... | ... | |
325 | 325 |
{ cmd_show_status(); } ; |
326 | 326 |
|
327 | 327 |
CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]]) |
328 |
{ proto_apply_cmd($3, proto_cmd_show, 0); } ; |
|
328 |
{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
|
|
329 | 329 |
|
330 | 330 |
CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]]) |
331 |
{ proto_apply_cmd($4, proto_cmd_show, 1); } ; |
|
331 |
{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
|
|
332 | 332 |
|
333 | 333 |
optsym: |
334 | 334 |
SYM |
... | ... | |
459 | 459 |
; |
460 | 460 |
|
461 | 461 |
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]]) |
462 |
{ proto_apply_cmd($2, proto_cmd_disable, 0); } ; |
|
462 |
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
|
|
463 | 463 |
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]]) |
464 |
{ proto_apply_cmd($2, proto_cmd_enable, 0); } ; |
|
464 |
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
|
|
465 | 465 |
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]]) |
466 |
{ proto_apply_cmd($2, proto_cmd_restart, 0); } ; |
|
466 |
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
|
|
467 | 467 |
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]]) |
468 |
{ proto_apply_cmd($2, proto_cmd_reload, CMD_RELOAD); } ; |
|
468 |
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
|
|
469 | 469 |
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]]) |
470 |
{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_IN); } ; |
|
470 |
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
|
|
471 | 471 |
CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]]) |
472 |
{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_OUT); } ; |
|
472 |
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
|
|
473 | 473 |
|
474 | 474 |
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]]) |
475 | 475 |
CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging via BIRD logs]]) |
476 |
{ proto_apply_cmd($2, proto_cmd_debug, $3); } ; |
|
476 |
{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
|
|
477 | 477 |
|
478 | 478 |
CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]]) |
479 | 479 |
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) |
480 |
{ proto_apply_cmd($2, proto_cmd_mrtdump, $3); } ; |
|
480 |
{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ; |
|
481 |
|
|
482 |
CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]]) |
|
483 |
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ; |
|
481 | 484 |
|
482 | 485 |
proto_patt: |
483 | 486 |
SYM { $$.ptr = $1; $$.patt = 0; } |
nest/proto.c | ||
---|---|---|
1006 | 1006 |
} |
1007 | 1007 |
|
1008 | 1008 |
void |
1009 |
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) |
|
1009 |
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), |
|
1010 |
int restricted, unsigned int arg) |
|
1010 | 1011 |
{ |
1012 |
if (restricted && cli_access_restricted()) |
|
1013 |
return; |
|
1014 |
|
|
1011 | 1015 |
if (ps.patt) |
1012 | 1016 |
proto_apply_cmd_patt(ps.ptr, cmd, arg); |
1013 | 1017 |
else |
nest/protocol.h | ||
---|---|---|
213 | 213 |
void proto_cmd_debug(struct proto *, unsigned int, int); |
214 | 214 |
void proto_cmd_mrtdump(struct proto *, unsigned int, int); |
215 | 215 |
|
216 |
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg); |
|
216 |
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), int restricted, unsigned int arg);
|
|
217 | 217 |
struct proto *proto_get_named(struct symbol *, struct protocol *); |
218 | 218 |
|
219 | 219 |
#define CMD_RELOAD 0 |
sysdep/unix/config.Y | ||
---|---|---|
107 | 107 |
{ cmd_reconfig($3, RECONFIG_SOFT); } ; |
108 | 108 |
|
109 | 109 |
CF_CLI(DOWN,,, [[Shut the daemon down]]) |
110 |
{ cli_msg(7, "Shutdown requested"); order_shutdown(); } ;
|
|
110 |
{ cmd_shutdown(); } ;
|
|
111 | 111 |
|
112 | 112 |
cfg_name: |
113 | 113 |
/* empty */ { $$ = NULL; } |
sysdep/unix/main.c | ||
---|---|---|
141 | 141 |
{ |
142 | 142 |
struct config *conf; |
143 | 143 |
|
144 |
if (cli_access_restricted()) |
|
145 |
return; |
|
146 |
|
|
144 | 147 |
if (!name) |
145 | 148 |
name = config_name; |
146 | 149 |
cli_msg(-2, "Reading configuration from %s", name); |
... | ... | |
304 | 307 |
*/ |
305 | 308 |
|
306 | 309 |
void |
310 |
cmd_shutdown(void) |
|
311 |
{ |
|
312 |
if (cli_access_restricted()) |
|
313 |
return; |
|
314 |
|
|
315 |
cli_msg(7, "Shutdown requested"); |
|
316 |
order_shutdown(); |
|
317 |
} |
|
318 |
|
|
319 |
void |
|
307 | 320 |
async_shutdown(void) |
308 | 321 |
{ |
309 | 322 |
DBG("Shutting down...\n"); |
Also available in: Unified diff