diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d72f14..13ff9628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ Expected: January 2025 Developers may need to change their code +* Moved callbacks starting programs from libclixon_cli to example code + * The functions are: `cli_start_shell` and `cli_start_program` + * If you need them, add them to your application plugin code instead * Changed C-API: add `system-only` parameter with default value `0` last: * `clixon_json2file()` -> `clixon_json2file(,0)` * `clixon_json2cbuf()` -> `clixon_json2cbuf(,0)` diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 22a7c249..196630d1 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -774,229 +774,6 @@ cli_set_mode(clixon_handle h, return retval; } -/*! - * @brief Spawns a new process and runs the specified program within it - * - * The function creates a new child process and runs the specified program within it. - * Before launching the program in the child process, environment variables taken from cvv are set. - * - * The function checks the parameters passed to it. Situations where at least one function argument - * is missing, or when two arguments are present in both the function and the cvv vector are considered invalid. - * - * Example usage: - * @code - * python3_args("Run program"), cli_start_program("python3"); { - * ("Single shell command"), cli_start_program("python3", "/tmp/test.py"); - * } - * - * python3_single("Run program"), cli_start_program("python3"); { - * ("Single shell command"), cli_start_program("python3"); - * } - * - * python3_script("Run program") ("Path program"), cli_start_program("python3"); - * @endcode - * - * @warning Please note that the usage of this function consists of executing an arbitrary command given to - * the function as an argument. It may pose a serious security risk if the function is used improperly. - * Developers should take necessary precautions to ensure safety, such as using `chroot` to limit the - * space of accessible scripts for execution. - * - * @param[in] h Clixon handle - * @param[in] cvv Vector of command variables - * @param[in] argv Function arguments - * @retval 0 OK, returns the exit code of the program - * @retval -1 Error - * @note utility, should probably not be in lib - * @see cli_start_shell - */ -int -cli_start_program(clixon_handle h, - cvec *cvv, - cvec *argv) -{ - int pid = 0; - int retval = -1; - int s = 0; - int arg_count = 0; - int cvv_count = 0; - int i = 0; - int status = 0; - char *script_path = NULL; - char *runner = NULL; - char *buf = NULL; - char *work_dir = NULL; - char *reserve_path = NULL; - char **args = NULL; - size_t bufsize = 0; - struct passwd pw, *pwresult = NULL; - - /* Check parameters */ - if (cvec_len(argv) == 0){ - clixon_err(OE_PLUGIN, EINVAL, "Can not find argument"); - goto done; - } - - /* get data */ - arg_count = cvec_len(argv); - cvv_count = cvec_len(cvv); - - runner = cv_string_get(cvec_i(argv, 0)); - - if (arg_count > 1) { - script_path = cv_string_get(cvec_i(argv, 1)); - } - - if (script_path){ - reserve_path = strdup(script_path); - work_dir = dirname(reserve_path); - } - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == -1){ - bufsize = 16384; - } - buf = malloc(bufsize); - if (buf == NULL) { - perror("malloc"); - goto done; - } - s = getpwuid_r(getuid(), &pw, buf, bufsize, &pwresult); - if (pwresult == NULL) { - if (s == 0) - clixon_err(OE_PLUGIN, errno, "getpwuid_r"); - else - perror("getpwuid_r"); - goto done; - } - - /* Prepare arguments for execlp */ - args = malloc((arg_count + cvv_count) * sizeof(char *)); - if (args == NULL) { - perror("malloc"); - goto done; - } - - for (i = 0; i < arg_count; i++) { - args[i] = cv_string_get(cvec_i(argv, i)); - } - - for (i = 0; i < cvv_count; i++) { - args[arg_count + i] = cv_string_get(cvec_i(cvv, i + 1)); - } - - /* main run */ - if ((pid = fork()) == 0) { - /* child process */ - if ((work_dir ? chdir(work_dir) : chdir(pw.pw_dir)) < 0) { - clixon_err(OE_PLUGIN, errno, "chdir"); - } - execvp(runner, args); - clixon_err(OE_PLUGIN, errno, "Error running script"); - goto done; - } - else if(pid == -1){ - clixon_err(OE_PLUGIN, errno, "fork"); - } - else{ - /* parent process */ - if (waitpid(pid, &status, 0) != pid ){ - clixon_err(OE_PLUGIN, errno, "waitpid error"); - goto done; - } - else { - retval = WEXITSTATUS(status); - goto done; - } - } -done: - if(buf) - free(buf); - if(reserve_path) - free(reserve_path); - if(args) - free(args); - return retval; -} - -/*! Start bash from cli callback - * - * Typical usage: shell("System Bash") , cli_start_shell(); - * @param[in] h Clixon handle - * @param[in] cvv Vector of command variables - * @param[in] argv [], defaults to "sh" - * @retval 0 OK - * @retval -1 Error - * @note utility, should probably not be in lib - * @see cli_start_program - */ -int -cli_start_shell(clixon_handle h, - cvec *cvv, - cvec *argv) -{ - int retval = -1; - char *cmd; - char *shcmd = "sh"; - struct passwd *pw; - char bcmd[128]; - cg_var *cv1 = cvec_i(cvv, 1); - sigset_t oldsigset; - struct sigaction oldsigaction[32] = {{{0,},},}; - - if (cvec_len(argv) > 1){ - clixon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected: []", - cvec_len(argv)); - goto done; - } - if (cvec_len(argv) == 1){ - shcmd = cv_string_get(cvec_i(argv, 0)); - } - cmd = (cvec_len(cvv)>1 ? cv_string_get(cv1) : NULL); - if ((pw = getpwuid(getuid())) == NULL){ - clixon_err(OE_UNIX, errno, "getpwuid"); - goto done; - } - if (chdir(pw->pw_dir) < 0){ - clixon_err(OE_UNIX, errno, "chdir"); - endpwent(); - goto done; - } - endpwent(); - - if (clixon_signal_save(&oldsigset, oldsigaction) < 0) - goto done; - cli_signal_flush(h); - cli_signal_unblock(h); - if (cmd){ - snprintf(bcmd, 128, "%s -c \"%s\"", shcmd, cmd); - if (system(bcmd) < 0){ - cli_signal_block(h); - clixon_err(OE_UNIX, errno, "system(bash -c)"); - goto done; - } - } - else{ - snprintf(bcmd, 128, "%s ", shcmd); /* -l (login shell) but is applicable to bash only */ - if (system(bcmd) < 0){ - cli_signal_block(h); - clixon_err(OE_UNIX, errno, "system(bash)"); - goto done; - } - } - cli_signal_block(h); -#if 0 /* Allow errcodes from bash */ - if (retval != 0){ - clixon_err(OE_UNIX, errno, "system(%s) %d", cmd, retval); - goto done; - } -#endif - if (clixon_signal_restore(&oldsigset, oldsigaction) < 0) - goto done; - retval = 0; - done: - return retval; -} - /*! Generic quit callback * * @param[in] h Clixon handle diff --git a/apps/cli/clixon_cli_api.h b/apps/cli/clixon_cli_api.h index e4251ff1..a05b1bb6 100644 --- a/apps/cli/clixon_cli_api.h +++ b/apps/cli/clixon_cli_api.h @@ -80,11 +80,12 @@ cligen_handle cli_cligen(clixon_handle h); int cli_notification_register(clixon_handle h, char *stream, enum format_enum format, char *filter, int status, int (*fn)(int, void*), void *arg); - +void cli_signal_block(clixon_handle h); +void cli_signal_unblock(clixon_handle h); +void cli_signal_flush(clixon_handle h); int mtpoint_paths(yang_stmt *yspec0, char *mtpoint, char *api_path_fmt1, char **api_path_fmt01); int dbxml_body(cxobj *xbot, cvec *cvv); int identityref_add_ns(cxobj *x, void *arg); - int cli_dbxml(clixon_handle h, cvec *vars, cvec *argv, enum operation_type op, cvec *nsctx); int cli_set(clixon_handle h, cvec *vars, cvec *argv); int cli_merge(clixon_handle h, cvec *vars, cvec *argv); diff --git a/example/main/example_cli.c b/example/main/example_cli.c index c79f978b..733cf68b 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include #include @@ -110,6 +112,84 @@ mycallback(clixon_handle h, return retval; } +/*! Start bash from cli callback + * + * Typical usage: shell("System Bash") , cli_start_shell(); + * @param[in] h Clixon handle + * @param[in] cvv Vector of command variables + * @param[in] argv [], defaults to "sh" + * @retval 0 OK + * @retval -1 Error + * @note Code potentially unsafe + */ +int +cli_start_shell(clixon_handle h, + cvec *cvv, + cvec *argv) +{ + int retval = -1; + char *cmd; + char *shcmd = "sh"; + struct passwd *pw; + char bcmd[128]; + cg_var *cv1 = cvec_i(cvv, 1); + sigset_t oldsigset; + struct sigaction oldsigaction[32] = {{{0,},},}; + + if (cvec_len(argv) > 1){ + clixon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected: []", + cvec_len(argv)); + goto done; + } + if (cvec_len(argv) == 1){ + shcmd = cv_string_get(cvec_i(argv, 0)); + } + cmd = (cvec_len(cvv)>1 ? cv_string_get(cv1) : NULL); + if ((pw = getpwuid(getuid())) == NULL){ + clixon_err(OE_UNIX, errno, "getpwuid"); + goto done; + } + if (chdir(pw->pw_dir) < 0){ + clixon_err(OE_UNIX, errno, "chdir"); + endpwent(); + goto done; + } + endpwent(); + + if (clixon_signal_save(&oldsigset, oldsigaction) < 0) + goto done; + cli_signal_flush(h); + cli_signal_unblock(h); + if (cmd){ + snprintf(bcmd, 128, "%s -c \"%s\"", shcmd, cmd); + if (system(bcmd) < 0){ + cli_signal_block(h); + clixon_err(OE_UNIX, errno, "system(bash -c)"); + goto done; + } + } + else{ + snprintf(bcmd, 128, "%s ", shcmd); /* -l (login shell) but is applicable to bash only */ + if (system(bcmd) < 0){ + cli_signal_block(h); + clixon_err(OE_UNIX, errno, "system(bash)"); + goto done; + } + } + cli_signal_block(h); +#if 0 /* Allow errcodes from bash */ + if (retval != 0){ + clixon_err(OE_UNIX, errno, "system(%s) %d", cmd, retval); + goto done; + } +#endif + if (clixon_signal_restore(&oldsigset, oldsigaction) < 0) + goto done; + retval = 0; + done: + return retval; +} + /*! Example "downcall", ie initiate an RPC to the backend */ int