/* Set the Exclude context */
set_incexe(jcr, bctx->exclude);
- add_file_to_fileset(jcr, file, true);
+ if (add_file_to_fileset(jcr, file, true) != state_include) {
+ Dmsg1(100, "Failed to add exclude file=%s\n", file);
+ return bRC_Error;
+ }
/* Restore the current context */
set_incexe(jcr, old);
}
set_incexe(jcr, bctx->include);
- add_file_to_fileset(jcr, file, true);
+ if (add_file_to_fileset(jcr, file, true) != state_include) {
+ Dmsg1(100, "Failed to add include file=%s\n", file);
+ return bRC_Error;
+ }
/* Restore the current context */
set_incexe(jcr, old);
}
set_incexe(jcr, bctx->include);
- add_file_to_fileset(jcr, file, false);
+ if (add_file_to_fileset(jcr, file, false) != state_include) {
+ Dmsg1(100, "Failed to plugin=%s\n", file);
+ return bRC_Error;
+ }
/* Restore the current context */
set_incexe(jcr, old);
set_incexe(jcr, exclude);
}
Mmsg(t, "%s", elt->snap->SnapDirectory);
+ if (add_file_to_fileset(jcr, t.c_str(), true) != state_include) {
+ Jmsg(jcr, M_ERROR, 0, " Failed to exclude=%s\n", t.c_str());
+ return false;
+ }
Dmsg1(DT_SNAPSHOT|10, "Excluding %s\n", t.c_str());
- add_file_to_fileset(jcr, t.c_str(), true);
}
}
}
quit = true;
break;
}
+
+ /* Set per-director list of allowed directories for scripts/program being run */
+ if (jcr->director && jcr->director->allowed_script_dirs) {
+ jcr->allowed_script_dirs = jcr->director->allowed_script_dirs;
+ }
+
Dmsg1(100, "Executing Dir %s command.\n", dir->msg);
if (!cmds[i].func(jcr)) { /* do command */
quit = true; /* error or fully terminated, get out */
* Add fname to include/exclude fileset list. First check for
* | and < and if necessary perform command.
*/
-void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
+int add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
{
findFILESET *fileset = jcr->ff->fileset;
char *p;
Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
p, be.bstrerror());
free_pool_memory(fn);
- return;
+ return state_error;
}
free_pool_memory(fn);
while (fgets(buf, sizeof(buf), bpipe->rfd)) {
berrno be;
Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
p, be.code(stat), be.bstrerror(stat));
- return;
+ return state_error;
}
break;
case '<':
Jmsg(jcr, M_FATAL, 0,
_("Cannot open FileSet input file: %s. ERR=%s\n"),
p, be.bstrerror());
- return;
+ return state_error;
}
while (fgets(buf, sizeof(buf), ffd)) {
strip_trailing_junk(buf);
append_file(jcr, fileset->incexe, fname, is_file);
break;
}
+
+ //TODO check all calls for add_file_to_fileset() to check for ret code now
+ return state_include;
}
findINCEXE *get_incexe(JCR *jcr)
break;
case 'F': /* file = */
/* File item to include or exclude list */
- state = state_include;
- add_file_to_fileset(jcr, item, true);
+ state = add_file_to_fileset(jcr, item, true);
break;
case 'P': /* plugin */
/* Plugin item to include list */
- state = state_include;
- add_file_to_fileset(jcr, item, false);
+ state = add_file_to_fileset(jcr, item, false);
break;
case 'R': /* regex */
state = add_regex_to_fileset(jcr, item, subcode);
findINCEXE *get_incexe(JCR *jcr);
void set_incexe(JCR *jcr, findINCEXE *incexe);
void new_options(JCR *jcr, findINCEXE *incexe);
-void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file);
+int add_file_to_fileset(JCR *jcr, const char *fname, bool is_file);
int add_options_to_fileset(JCR *jcr, const char *item);
int add_wild_to_fileset(JCR *jcr, const char *item, int type);
int add_regex_to_fileset(JCR *jcr, const char *item, int type);
pthread_mutex_t msg_queue_mutex; /* message queue mutex */
bool dequeuing_msgs; /* Set when dequeuing messages */
alist job_end_push; /* Job end pushed calls */
+ alist *allowed_script_dirs; /* Daemon-specific Allowed directory list to run
+ scripts/programs from */
POOLMEM *VolumeName; /* Volume name desired -- pool_memory */
POOLMEM *errmsg; /* edited error message */
char Job[MAX_NAME_LENGTH]; /* Unique name of this Job */
*bargc = 3;
}
+int forbidden_chars[] = {
+ '$', '!', ';', '\\', '&', '|', '<', '>', '`', '(', ')'
+};
+
+static bool check_for_forbidden_chars(const char *str)
+{
+ bool ret = true;
+ int size = sizeof(forbidden_chars) / sizeof(int);
+ for (int i=0; i<size; i++) {
+ if (strchr(str, forbidden_chars[i]) != NULL) {
+ ret = false;
+ break;
+ }
+ }
+
+ return ret;
+}
+
/*
* Run an external program. Optionally wait a specified number
* of seconds. Program killed if wait exceeded. We open
POOLMEM *tprog;
int mode_map = 0;
BPIPE *bpipe;
+ JCR *jcr;
int save_errno;
-
-#if !defined(HAVE_FCNTL_F_CLOSEM) && !defined(HAVE_CLOSEFROM)
- struct rlimit rl;
- int64_t rlimitResult=0;
-#endif
+ bool allowed = false;
if (!prog || !*prog) {
/* execve(3) A component of the file does not name an existing file or file is an empty string. */
return NULL;
}
+ /* Get JCR from the thread context.
+ * It's needed for per-daemon specific data, e.g. list of allowed scripts/programs directories. */
+ jcr = get_jcr_from_tsd();
+ if (!jcr) {
+ allowed = true; /* Allow everything */
+ } else if (jcr->allowed_script_dirs) {
+ /* JCR has some allowed script directories set, so we need to check if command matches it */
+ char *dir, *p;
+ foreach_alist(dir, jcr->allowed_script_dirs) {
+ if ((p = b_path_match(prog, dir)) == prog) {
+ /* Path is ok, now check if program contains forbidden characters */
+ //TODO too many ifs, refactor that
+ if (!check_for_forbidden_chars(prog)) {
+ errno = berr_not_allowed_char;
+ allowed = false;
+ break;
+ } else {
+ allowed = true;
+ }
+ break;
+ }
+ }
+
+ if (!allowed && errno != berr_not_allowed_char) {
+ errno = berr_not_allowed_path;
+ }
+
+ } else {
+ /* Nothing specified, so we should allow to run scripts from every dir provided */
+ allowed = true;
+ }
+
+ /* Check if script/program can be executed */
+ if (!allowed) {
+ return NULL;
+ }
+
bpipe = (BPIPE *)malloc(sizeof(BPIPE));
memset(bpipe, 0, sizeof(BPIPE));
if (strchr(mode,'r')) mode_map|=MODE_READ;