summaryrefslogtreecommitdiff
path: root/home/shemminger/vyatta/mendocino/vyatta-bash/vyatta-restricted.c
diff options
context:
space:
mode:
Diffstat (limited to 'home/shemminger/vyatta/mendocino/vyatta-bash/vyatta-restricted.c')
-rw-r--r--home/shemminger/vyatta/mendocino/vyatta-bash/vyatta-restricted.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/home/shemminger/vyatta/mendocino/vyatta-bash/vyatta-restricted.c b/home/shemminger/vyatta/mendocino/vyatta-bash/vyatta-restricted.c
new file mode 100644
index 0000000..c0337e7
--- /dev/null
+++ b/home/shemminger/vyatta/mendocino/vyatta-bash/vyatta-restricted.c
@@ -0,0 +1,569 @@
+/* vyatta-restricted.c -- Vyatta restricted mode functionality */
+
+/* This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+
+ This code was originally developed by Vyatta, Inc.
+ Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. */
+
+#include "shell.h"
+#include "bashhist.h"
+#include "vyatta-restricted.h"
+
+#define FILENAME_MODE "restricted-mode"
+#define FILENAME_OP "allowed-op"
+#define FILENAME_CFG "allowed-cfg"
+#define FILENAME_PIPE "allowed-pipe"
+
+static char *prev_cmdline = NULL;
+
+/* allowed commands lists */
+static char **allowed_op_cmds = NULL;
+static char **allowed_cfg_cmds = NULL;
+static char **allowed_pipe_cmds = NULL;
+static int *pipe_cmd_args = NULL;
+
+static char *vyatta_user_level_dir = NULL;
+
+/* default restricted mode */
+static int vyatta_default_output_restricted = 0;
+static int vyatta_default_full_restricted = 0;
+
+static char *expand_disable_cmds[] = { "_vyatta_op_run",
+ "/opt/vyatta/sbin/my_set",
+ "/opt/vyatta/sbin/my_delete",
+ "/opt/vyatta/sbin/my_commit",
+ NULL };
+
+static int
+is_expansion_disabled()
+{
+ char *exp = getenv("VYATTA_ENABLE_SHELL_EXPANSION");
+ if (!exp) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+vyatta_reset_hist_expansion()
+{
+#if defined (BANG_HISTORY)
+ if (is_expansion_disabled()) {
+ history_expansion_inhibited = 1;
+ } else {
+ history_expansion_inhibited = 0;
+ }
+#endif
+}
+
+static int
+is_in_command_list(const char *cmd, char *cmds[])
+{
+ int idx = 0;
+ for (idx = 0; cmds[idx]; idx++) {
+ if (strcmp(cmd, cmds[idx]) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+is_vyatta_restricted_pipe_command(WORD_LIST *words)
+{
+ WORD_LIST *w = words;
+ int count = 1;
+ while (w = w->next) {
+ count++;
+ }
+ if (words) {
+ int i = 0;
+ if (!allowed_pipe_cmds) {
+ /* no restriction */
+ return 1;
+ }
+ for (i = 0; allowed_pipe_cmds[i]; i++) {
+ if (strcmp(words->word->word, allowed_pipe_cmds[i]) == 0
+ && count == pipe_cmd_args[i]) {
+ return 1;
+ }
+ }
+ }
+ /* not allowed */
+ return 0;
+}
+
+static void
+make_restricted_word(WORD_DESC *word)
+{
+ char *c, *ns, *n;
+ int sq_count = 0;
+ char *uqs = string_quote_removal(word->word, 0);
+
+ for (c = uqs; *c; c++) {
+ if (*c == '\'') {
+ sq_count++;
+ }
+ }
+
+ /* strlen + start/end quotes + \0 + extra "'\''" */
+ ns = (char *) xmalloc(strlen(uqs) + 2 + 1 + (3 * sq_count));
+ n = ns;
+ *n = '\'';
+ n++;
+ for (c = uqs; *c; c++) {
+ if (*c == '\'') {
+ *n = '\'';
+ *(n + 1) = '\\';
+ *(n + 2) = '\'';
+ *(n + 3) = '\'';
+ n += 4;
+ } else {
+ *n = *c;
+ n++;
+ }
+ }
+ *n = '\'';
+ *(n + 1) = '\0';
+
+ free(word->word);
+ free(uqs);
+ word->word = ns;
+ word->flags = W_QUOTED;
+}
+
+static void
+make_restricted_wordlist(WORD_LIST *words)
+{
+ WORD_LIST *l = words->next; /* skip the first word */
+ for (; l; l = l->next) {
+ make_restricted_word(l->word);
+ }
+}
+
+/* this basically disables shell expansions for "simple" commands. */
+/* full: do a "full" check (disallow env override && also check pipe). */
+void
+vyatta_check_expansion(COMMAND *cmd, int full)
+{
+ struct simple_com *cS;
+ struct connection *cC;
+
+ if (!cmd) {
+ return;
+ }
+ if (!full && !is_expansion_disabled()) {
+ /* enabled */
+ return;
+ }
+
+ switch (cmd->type) {
+ case cm_simple:
+ cS = cmd->value.Simple;
+ if (cS && !(cS->redirects)) {
+ /* simple command, no redirects */
+ if (cS->words && cS->words->word &&
+ is_in_command_list(cS->words->word->word, expand_disable_cmds)) {
+ /* user command => quote all words */
+ make_restricted_wordlist(cS->words);
+ }
+ }
+ break;
+ case cm_connection:
+ cC = cmd->value.Connection;
+ if ((cC->connector == '|') && (cC->first->type == cm_simple)) {
+ struct simple_com *cS1 = cC->first->value.Simple;
+ if (!(cS1->redirects)) {
+ /* simple, no redirects */
+ if (is_in_command_list(cS1->words->word->word, expand_disable_cmds)) {
+ /* user command => quote all words */
+ make_restricted_wordlist(cS1->words);
+ }
+ }
+ if (full && (cC->second->type == cm_simple)) {
+ struct simple_com *cS2 = cC->second->value.Simple;
+ if (!(cS2->redirects)) {
+ /* simple, no redirects */
+ /* quote all words (not checking user command after pipe) */
+ make_restricted_wordlist(cS2->words);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+is_vyatta_restricted_command(COMMAND *cmd)
+{
+ struct simple_com *cS;
+ struct connection *cC;
+
+ if (!cmd) {
+ return 1;
+ }
+
+ switch (cmd->type) {
+ case cm_simple:
+ cS = cmd->value.Simple;
+ if (!(cS->redirects)) {
+ /* simple command, no redirects */
+ return 1;
+ }
+ break;
+ case cm_connection:
+ cC = cmd->value.Connection;
+ if (cC->connector == '|') {
+ if ((cC->first->type == cm_simple) && (cC->second->type == cm_simple)) {
+ struct simple_com *cS1 = cC->first->value.Simple;
+ struct simple_com *cS2 = cC->second->value.Simple;
+ if (!(cS1->redirects) && !(cS2->redirects)) {
+ /* both are simple and no redirects */
+ if (is_vyatta_restricted_pipe_command(cS2->words)) {
+ /* pipe command is allowed => allowed */
+ return 1;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ /* not allowed */
+ return 0;
+}
+
+static int
+is_vyatta_cfg_command(const char *cmd)
+{
+ if (!allowed_cfg_cmds) {
+ /* no restriction */
+ return 1;
+ }
+ return is_in_command_list(cmd, allowed_cfg_cmds);
+}
+
+static int
+is_vyatta_op_command(const char *cmd)
+{
+ if (!allowed_op_cmds) {
+ /* no restriction */
+ return 1;
+ }
+ return is_in_command_list(cmd, allowed_op_cmds);
+}
+
+int
+is_vyatta_command(char *cmdline, COMMAND *cmd)
+{
+ char *cfg = getenv("_OFR_CONFIGURE");
+ int in_cfg = (cfg) ? (strcmp(cfg, "ok") == 0) : 0;
+ char *start = cmdline;
+ char *end = NULL;
+ char save = 0;
+ int ret = 0;
+
+ /* check expansions (full) */
+ vyatta_check_expansion(cmd, 1);
+
+ if (!prev_cmdline) {
+ prev_cmdline = strdup("");
+ }
+ if (strcmp(cmdline, prev_cmdline) == 0) {
+ /* still at the same line. not checking. */
+ return 1;
+ }
+ if (!is_vyatta_restricted_command(cmd)) {
+ return 0;
+ }
+
+ while (*start && (whitespace(*start) || *start == '\n')) {
+ start++;
+ }
+ if (*start == 0) {
+ /* empty command line is valid */
+ free(prev_cmdline);
+ prev_cmdline = strdup(cmdline);
+ return 1;
+ }
+ end = start;
+ while (*end && (!whitespace(*end) && *end != '\n')) {
+ end++;
+ }
+ save = *end;
+ *end = 0;
+
+ if (in_cfg) {
+ ret = is_vyatta_cfg_command(start);
+ } else {
+ ret = is_vyatta_op_command(start);
+ }
+ *end = save;
+
+ if (ret) {
+ /* valid command */
+ free(prev_cmdline);
+ prev_cmdline = strdup(cmdline);
+ }
+ return ret;
+}
+
+static FILE *
+fopen_level_file(char *file_name)
+{
+ FILE *f = NULL;
+#define BUF_SIZE 1024
+ char *buf = (char *) xmalloc(BUF_SIZE);
+ if (!buf) {
+ return NULL;
+ }
+
+ do {
+ int r = snprintf(buf, BUF_SIZE, "%s/%s", vyatta_user_level_dir, file_name);
+ if (r >= BUF_SIZE) {
+ break;
+ }
+
+ f = fopen(buf, "r");
+ } while (0);
+
+ free(buf);
+ return f;
+}
+
+static char *
+fgets_level_file(char *buf, int size, FILE *lfile)
+{
+ if (fgets(buf, size, lfile)) {
+ int end = 0;
+ while (buf[end] && isprint(buf[end]) && !isspace(buf[end])) {
+ end++;
+ }
+ buf[end] = 0;
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+set_default_mode()
+{
+ FILE *lfile = NULL;
+ char *line = NULL;
+ char buf[256];
+
+ /* default to full restricted */
+ vyatta_default_output_restricted = 0;
+ vyatta_default_full_restricted = 1;
+
+ if (!(lfile = fopen_level_file(FILENAME_MODE))) {
+ return;
+ }
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ if (strcmp(line, "output") == 0) {
+ vyatta_default_output_restricted = 1;
+ vyatta_default_full_restricted = 0;
+ break;
+ }
+ if (strcmp(line, "full") == 0) {
+ vyatta_default_output_restricted = 0;
+ vyatta_default_full_restricted = 1;
+ break;
+ }
+ }
+ fclose(lfile);
+ return;
+}
+
+static void
+set_allowed_op_cmds()
+{
+ FILE *lfile = NULL;
+ char *line = NULL;
+ char buf[256];
+ int count = 1;
+
+ if (allowed_op_cmds) {
+ return;
+ }
+
+ if (!(lfile = fopen_level_file(FILENAME_OP))) {
+ return;
+ }
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ count++;
+ }
+ fclose(lfile);
+
+ /* count is 1 more than number of lines */
+ allowed_op_cmds = (char **) xmalloc(sizeof(char *) * count);
+ memset(allowed_op_cmds, 0, sizeof(char *) * count);
+
+ if (!(lfile = fopen_level_file(FILENAME_OP))) {
+ return;
+ }
+ count = 0;
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ allowed_op_cmds[count] = strdup(line);
+ count++;
+ }
+ fclose(lfile);
+ return;
+}
+
+static void
+set_allowed_cfg_cmds()
+{
+ FILE *lfile = NULL;
+ char *line = NULL;
+ char buf[256];
+ int count = 1;
+
+ if (allowed_cfg_cmds) {
+ return;
+ }
+
+ if (!(lfile = fopen_level_file(FILENAME_CFG))) {
+ return;
+ }
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ count++;
+ }
+ fclose(lfile);
+
+ /* count is 1 more than number of lines */
+ allowed_cfg_cmds = (char **) xmalloc(sizeof(char *) * count);
+ memset(allowed_cfg_cmds, 0, sizeof(char *) * count);
+
+ if (!(lfile = fopen_level_file(FILENAME_CFG))) {
+ return;
+ }
+ count = 0;
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ allowed_cfg_cmds[count] = strdup(line);
+ count++;
+ }
+ fclose(lfile);
+ return;
+}
+
+static void
+set_allowed_pipe_cmds()
+{
+ FILE *lfile = NULL;
+ char *line = NULL;
+ char buf[256];
+ int count = 0;
+
+ if (allowed_pipe_cmds) {
+ return;
+ }
+
+ if (!(lfile = fopen_level_file(FILENAME_PIPE))) {
+ return;
+ }
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ count++;
+ }
+ fclose(lfile);
+
+ count = (count / 2) + 2;
+ /* count is 1 more than entries */
+ allowed_pipe_cmds = (char **) xmalloc(sizeof(char *) * count);
+ memset(allowed_pipe_cmds, 0, sizeof(char *) * count);
+ pipe_cmd_args = (int *) xmalloc(sizeof(int *) * count);
+ memset(pipe_cmd_args, 0, sizeof(int *) * count);
+
+ if (!(lfile = fopen_level_file(FILENAME_PIPE))) {
+ return;
+ }
+ count = 0;
+ while (line = fgets_level_file(buf, 256, lfile)) {
+ allowed_pipe_cmds[count] = strdup(line);
+ if (!(line = fgets_level_file(buf, 256, lfile))) {
+ free(allowed_pipe_cmds[count]);
+ allowed_pipe_cmds[count] = NULL;
+ break;
+ }
+ pipe_cmd_args[count] = atoi(line);
+ /* limit to between 1 and 256 */
+ if (pipe_cmd_args[count] < 1 || pipe_cmd_args[count] > 256) {
+ free(allowed_pipe_cmds[count]);
+ allowed_pipe_cmds[count] = NULL;
+ pipe_cmd_args[count] = 0;
+ break;
+ }
+ count++;
+ }
+ fclose(lfile);
+ return;
+}
+
+static int
+init_vyatta_restricted_mode()
+{
+ if (!(vyatta_user_level_dir = getenv("VYATTA_USER_LEVEL_DIR"))) {
+ /* level dir not set, return failure */
+ return 0;
+ }
+
+ /* set the default restricted mode based on level */
+ set_default_mode();
+
+ /* set the allowed commands */
+ set_allowed_op_cmds();
+ set_allowed_cfg_cmds();
+ set_allowed_pipe_cmds();
+
+ return 1;
+}
+
+int
+in_vyatta_restricted_mode(enum vyatta_restricted_type type)
+{
+ char *rval = getenv("VYATTA_RESTRICTED_MODE");
+ int output = 0;
+ int full = 0;
+
+ if (!vyatta_user_level_dir && !init_vyatta_restricted_mode()) {
+ /* init failed, return false (not restricted) */
+ return 0;
+ }
+
+ output = vyatta_default_output_restricted;
+ full = vyatta_default_full_restricted;
+
+ /* environment var overrides default */
+ if (rval) {
+ output = (strcmp(rval, "output") == 0);
+ full = (strcmp(rval, "full") == 0);
+ }
+
+ if (type == OUTPUT && (output || full)) {
+ return 1;
+ }
+ if (type == FULL && full) {
+ return 1;
+ }
+
+ return 0;
+}
+