]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Restricted read-only CLI.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 21 Feb 2010 08:57:26 +0000 (09:57 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 21 Feb 2010 08:57:26 +0000 (09:57 +0100)
Also adds support for executing commands using birdc <cmd>.

client/client.c
doc/reply_codes
nest/cli.h
nest/config.Y
nest/proto.c
nest/protocol.h
sysdep/unix/config.Y
sysdep/unix/main.c

index 88a6095f7ecf389c87cc76e70c509ac0e242790a..8f514f6206d25a53174a3bc1a8d0abebc5377c99 100644 (file)
 #include "client/client.h"
 #include "sysdep/unix/unix.h"
 
-static char *opt_list = "s:v";
+static char *opt_list = "s:vr";
 static int verbose;
+static char *init_cmd;
+static int once;
 
 static char *server_path = PATH_CONTROL_SOCKET;
 static int server_fd;
@@ -49,7 +51,7 @@ static int num_lines, skip_input, interactive;
 static void
 usage(void)
 {
-  fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v]\n");
+  fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v] [-r]\n");
   exit(1);
 }
 
@@ -67,11 +69,36 @@ parse_args(int argc, char **argv)
       case 'v':
        verbose++;
        break;
+      case 'r':
+       init_cmd = "restrict";
+       break;
       default:
        usage();
       }
+
+  /* If some arguments are not options, we take it as commands */
   if (optind < argc)
-    usage();
+    {
+      char *tmp;
+      int i;
+      int len = 0;
+
+      if (init_cmd)
+       usage();
+
+      for (i = optind; i < argc; i++)
+       len += strlen(argv[i]) + 1;
+
+      tmp = init_cmd = malloc(len);
+      for (i = optind; i < argc; i++)
+       {
+         strcpy(tmp, argv[i]);
+         tmp += strlen(tmp);
+         *tmp++ = ' ';
+       }
+
+      once = 1;
+    }
 }
 
 /*** Input ***/
@@ -267,6 +294,22 @@ update_state(void)
   if (nstate == cstate)
     return;
 
+  if (init_cmd)
+    {
+      /* First transition - client received hello from BIRD
+        and there is waiting initial command */
+      submit_server_command(init_cmd);
+      init_cmd = NULL;
+      return;
+    }
+
+  if (!init_cmd && once)
+    {
+      /* Initial command is finished and we want to exit */
+      cleanup();
+      exit(0);
+    }
+
   if (nstate == STATE_PROMPT)
     if (input_initialized)
       input_reveal();
index db760fb46c7eca8b5d106ff5d992c23e28744000..22e0fd2d682244fb651abe1ab4d04a48ecc7bc62 100644 (file)
@@ -24,6 +24,7 @@ Reply codes of BIRD command-line interface
 0013   Status report
 0014   Route count
 0015   Reloading
+0016   Access restricted
 
 1000   BIRD version
 1001   Interface list
@@ -51,6 +52,7 @@ Reply codes of BIRD command-line interface
 8004   Stopped due to reconfiguration
 8005   Protocol is down => cannot dump
 8006   Reload failed
+8007   Access denied
 
 9000   Command too long
 9001   Parse error
index f816ef18afcdbef30a49d287ebcf02957aab238c..57414a29eb9cff81b5505586a41d459b4a122145 100644 (file)
@@ -33,6 +33,7 @@ typedef struct cli {
   void (*cleanup)(struct cli *c);
   void *rover;                         /* Private to continuation routine */
   int last_reply;
+  int restricted;                      /* CLI is restricted to read-only commands */
   struct linpool *parser_pool;         /* Pool used during parsing */
   byte *ring_buf;                      /* Ring buffer for asynchronous messages */
   byte *ring_end, *ring_read, *ring_write;     /* Pointers to the ring buffer */
@@ -60,6 +61,14 @@ void cli_kick(cli *);
 void cli_written(cli *);
 void cli_echo(unsigned int class, byte *msg);
 
+static inline int cli_access_restricted(void)
+{
+  if (this_cli && this_cli->restricted)
+    return (cli_printf(this_cli, 8007, "Access denied"), 1);
+  else
+    return 0;
+}
+
 /* Functions provided by sysdep layer */
 
 void cli_write_trigger(cli *);
index 8dc8c713c90eddcf50af77e7e4a46e4bc644d6ef..5a8950512576f61dfe48bb4846cc7cec69b1192f 100644 (file)
@@ -45,7 +45,7 @@ CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILT
 CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
 CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
 CF_KEYWORDS(LISTEN, BGP, V6ONLY, ADDRESS, PORT, PASSWORDS, DESCRIPTION)
-CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES)
+CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT)
 
 CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
        RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@@ -325,10 +325,10 @@ CF_CLI(SHOW STATUS,,, [[Show router status]])
 { cmd_show_status(); } ;
 
 CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]])
-{ proto_apply_cmd($3, proto_cmd_show, 0); } ;
+{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
 
 CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
-{ proto_apply_cmd($4, proto_cmd_show, 1); } ;
+{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
 
 optsym:
    SYM
@@ -459,25 +459,28 @@ echo_size:
  ;
 
 CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]])
-{ proto_apply_cmd($2, proto_cmd_disable, 0); } ;
+{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
 CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]])
-{ proto_apply_cmd($2, proto_cmd_enable, 0); } ;
+{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
 CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]])
-{ proto_apply_cmd($2, proto_cmd_restart, 0); } ;
+{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
 CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
-{ proto_apply_cmd($2, proto_cmd_reload, CMD_RELOAD); } ;
+{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
 CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
-{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_IN); } ;
+{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
 CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
-{ proto_apply_cmd($3, proto_cmd_reload, CMD_RELOAD_OUT); } ;
+{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
 
 CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
 CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | events | packets }), [[Control protocol debugging via BIRD logs]])
-{ proto_apply_cmd($2, proto_cmd_debug, $3); } ;
+{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
 
 CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
 CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]])
-{ proto_apply_cmd($2, proto_cmd_mrtdump, $3); } ;
+{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;
+
+CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
+{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
 
 proto_patt:
    SYM  { $$.ptr = $1; $$.patt = 0; }
index 7c4d32d06c9f8ed69873c8f20fa43ff1f9e776a2..e9cf3dfa4f3c92abfb84ed9378bbe92a60c8d859 100644 (file)
@@ -1006,8 +1006,12 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int)
 }
 
 void
-proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg)
+proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int),
+               int restricted, unsigned int arg)
 {
+  if (restricted && cli_access_restricted())
+    return;
+
   if (ps.patt)
     proto_apply_cmd_patt(ps.ptr, cmd, arg);
   else
index d652c4fb8bc5f3ea7edc70989358e96603f9f718..99356a3d26e24654cb78a55491ce7a11d5540960 100644 (file)
@@ -213,7 +213,7 @@ void proto_cmd_reload(struct proto *, unsigned int, int);
 void proto_cmd_debug(struct proto *, unsigned int, int);
 void proto_cmd_mrtdump(struct proto *, unsigned int, int);
 
-void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg);
+void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), int restricted, unsigned int arg);
 struct proto *proto_get_named(struct symbol *, struct protocol *);
 
 #define CMD_RELOAD     0
index 8c2b690343179d8ab77f86fd1345b4c8af453b53..ac5be7e2e78045328f36e1732afe4ec69f1c33ae 100644 (file)
@@ -107,7 +107,7 @@ CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore
 { cmd_reconfig($3, RECONFIG_SOFT); } ;
 
 CF_CLI(DOWN,,, [[Shut the daemon down]])
-{ cli_msg(7, "Shutdown requested"); order_shutdown(); } ;
+{ cmd_shutdown(); } ;
 
 cfg_name:
    /* empty */ { $$ = NULL; }
index 7a1ef2869cb9c1b49044c3e3f9cdf0d10f749d1a..2245692ca36b6f14380d5c559f98a88226042366 100644 (file)
@@ -141,6 +141,9 @@ cmd_reconfig(char *name, int type)
 {
   struct config *conf;
 
+  if (cli_access_restricted())
+    return;
+
   if (!name)
     name = config_name;
   cli_msg(-2, "Reading configuration from %s", name);
@@ -303,6 +306,16 @@ cli_init_unix(void)
  *     Shutdown
  */
 
+void
+cmd_shutdown(void)
+{
+  if (cli_access_restricted())
+    return;
+
+  cli_msg(7, "Shutdown requested");
+  order_shutdown();
+}
+
 void
 async_shutdown(void)
 {