From 8a7b8597717942861253a58bc0e3648ac9fdee50 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 17 Apr 2021 00:34:34 -0500 Subject: [PATCH] Update: redesign fl_execute_parameter_option_path in fll_execute. The previous design of fl_execute_parameter_option_path seemed pointless because it could be detected if a slash is in the progam name. Recent changes have utilized the slash in the path to do just that. While working with the controller program the SSHD program revealed that some programs are fickle about what is in their argument[0]. SSHD wants the full path and as such it needs to be provided. This makes sense as the normal behavior of most programs when started with a full path general expect a full path in argument[0]. The fl_execute_parameter_option_path is redesigned to instead provide a full path for program and for argument[0]. Examples: - "bash my_script.sh" (without fl_execute_parameter_option_path), results in: program="bash", argument[0]="bash", argument[1]="my_script.sh". - "/bin/bash my_script.sh" (without fl_execute_parameter_option_path), results in: program="/bin/bash", argument[0]="bash", argument[1]="my_script.sh". - "bash my_script.sh" (with fl_execute_parameter_option_path), results in: program="/bin/bash", argument[0]="/bin/bash", argument[1]="my_script.sh". - "/bin/bash my_script.sh" (with fl_execute_parameter_option_path), results in: program="/bin/bash", argument[0]="/bin/bash", argument[1]="my_script.sh". --- level_1/fl_execute/c/execute-common.h | 2 +- level_2/fll_execute/c/execute.c | 130 +++++++++++++++++++++++++++++--- level_2/fll_execute/c/execute.h | 6 +- level_2/fll_execute/c/private-execute.c | 8 +- level_2/fll_execute/c/private-execute.h | 10 ++- 5 files changed, 135 insertions(+), 21 deletions(-) diff --git a/level_1/fl_execute/c/execute-common.h b/level_1/fl_execute/c/execute-common.h index 1691908..deb4266 100644 --- a/level_1/fl_execute/c/execute-common.h +++ b/level_1/fl_execute/c/execute-common.h @@ -21,7 +21,7 @@ extern "C" { * * bitwise options: * fl_execute_parameter_option_exit: used to desginate to exit after calling child otherwise child process will return. - * fl_execute_parameter_option_path: used to designate that this is a path to a program (such as '/bin/bash'). + * fl_execute_parameter_option_path: used to designate that the full path to the program is to be passed in argument[0] instead of the program name (such as '/bin/bash' instead of 'bash'). * fl_execute_parameter_option_threadsafe: used to designate that threadsafe functions are to be used (such as: f_thread_signal_mask instead of f_signal_mask). * fl_execute_parameter_option_return: used to designate that the parent process will immediately return instead of waiting for the child process to complete. * diff --git a/level_2/fll_execute/c/execute.c b/level_2/fll_execute/c/execute.c index 8944a91..546bb19 100644 --- a/level_2/fll_execute/c/execute.c +++ b/level_2/fll_execute/c/execute.c @@ -140,15 +140,119 @@ extern "C" { f_string_t fixed_arguments[arguments.used + 2]; const f_string_t last_slash = strrchr(program ? program : arguments.array[0].string, f_path_separator_s[0]); - const f_array_length_t name_size = last_slash ? strnlen(last_slash + 1, f_path_length_max) : strnlen(program ? program : arguments.array[0].string, f_path_length_max); + const f_array_length_t size_name = last_slash ? strnlen(last_slash + 1, f_path_length_max) : strnlen(program ? program : arguments.array[0].string, f_path_length_max); + + char program_name[size_name + 1]; + + private_fll_execute_path_arguments_fixate(program ? program : arguments.array[0].string, arguments, last_slash, !program, size_name, program_name, fixed_arguments); + + int code = 0; + + // full path is explicitly requested. + if (option & fl_execute_parameter_option_path) { + f_string_dynamic_t path = f_string_dynamic_t_initialize; + f_string_dynamics_t paths = f_string_dynamics_t_initialize; + f_string_dynamic_t *found = 0; + + f_status_t status = F_none; + + if (last_slash) { + status = f_file_exists(program ? program : arguments.array[0].string); + + if (status != F_true) { + f_macro_string_dynamics_t_delete_simple(paths); + + return F_status_set_error(F_file_found_not); + } + + path.string = program ? program : arguments.array[0].string; + path.used = strnlen(program ? program : arguments.array[0].string, f_path_length_max); + found = &path; + } + else { + status = f_environment_get(f_path_environment_s, &path); + + if (F_status_is_error(status)) { + + // Do not consider PATH is not available (or valid?) to be an error. + if (F_status_set_fine(status) == F_valid_not || F_status_set_fine(status) == F_failure) { + status = F_none; + } + } + else { + status = fl_environment_path_explode_dynamic(path, &paths); + } + + f_macro_string_dynamic_t_delete_simple(path); + + if (F_status_is_error(status)) { + f_macro_string_dynamics_t_delete_simple(paths); + + return status; + } + + for (f_array_length_t i = 0; i < paths.used; ++i) { + + status = f_string_append(program_name, size_name, &paths.array[i]); + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_terminate_after(&paths.array[i]); + } + + if (F_status_is_error_not(status)) { + status = f_file_exists(paths.array[i].string); + + if (status == F_true) { + found = &paths.array[i]; + + break; + } + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + // don't consider bad/non-accessible paths an error, just ignore them. + if (status == F_name) { + continue; + } + else if (status == F_directory) { + continue; + } + else if (status == F_access_denied) { + continue; + } + } + } + + if (F_status_is_error(status)) { + f_macro_string_dynamics_t_delete_simple(paths); + + return status; + } + } // for + + if (!found) { + f_macro_string_dynamics_t_delete_simple(paths); + + return F_status_set_error(F_file_found_not); + } + } - char program_name[name_size + 1]; + char program_path[found->used + 1]; + program_path[found->used] = 0; - program_name[name_size] = 0; + memcpy(&program_path, found->string, found->used); - private_fll_execute_path_arguments_fixate(program ? program : arguments.array[0].string, arguments, last_slash, !program, name_size, program_name, fixed_arguments); + status = f_macro_string_dynamics_t_delete_simple(paths); + if (F_status_is_error(status)) return status; + + fixed_arguments[0] = program_path; - const int code = option & fl_execute_parameter_option_path ? execv(program ? program : arguments.array[0].string, fixed_arguments) : execvp(program ? program : arguments.array[0].string, fixed_arguments); + code = execv(program_path, fixed_arguments); + } + else { + code = last_slash ? execv(program ? program : arguments.array[0].string, fixed_arguments) : execvp(program ? program : arguments.array[0].string, fixed_arguments); + } // generally this does not return, but in some cases (such as with scripts) this does return so handle the results. if (result) { @@ -184,8 +288,8 @@ extern "C" { private_fll_execute_path_arguments_fixate(program ? program : arguments.array[0].string, arguments, last_slash, !program, size_name, program_name, fixed_arguments); - // when the environment is to be cleared, a full path must be used. - if (parameter && !(parameter->option & fl_execute_parameter_option_path) && parameter->environment) { + // determine full path when the environment is to be cleared or full path is explicitly requested. + if (parameter && parameter->environment || parameter && (parameter->option & fl_execute_parameter_option_path)) { f_string_dynamic_t path = f_string_dynamic_t_initialize; f_string_dynamics_t paths = f_string_dynamics_t_initialize; f_string_dynamic_t *found = 0; @@ -282,18 +386,22 @@ extern "C" { status = f_macro_string_dynamics_t_delete_simple(paths); if (F_status_is_error(status)) return status; + if (parameter && (parameter->option & fl_execute_parameter_option_path)) { + fixed_arguments[0] = program_path; + } + if (parameter && parameter->data) { - return private_fll_execute_fork_data(program_path, fixed_arguments, parameter, as, result); + return private_fll_execute_fork_data(F_true, program_path, fixed_arguments, parameter, as, result); } - return private_fll_execute_fork(program_path, fixed_arguments, parameter, as, result); + return private_fll_execute_fork(F_true, program_path, fixed_arguments, parameter, as, result); } if (parameter && parameter->data) { - return private_fll_execute_fork_data(program ? program : arguments.array[0].string, fixed_arguments, parameter, as, result); + return private_fll_execute_fork_data(last_slash, program ? program : arguments.array[0].string, fixed_arguments, parameter, as, result); } - return private_fll_execute_fork(program ? program : arguments.array[0].string, fixed_arguments, parameter, as, result); + return private_fll_execute_fork(last_slash, program ? program : arguments.array[0].string, fixed_arguments, parameter, as, result); } #endif // _di_fll_execute_program_ diff --git a/level_2/fll_execute/c/execute.h b/level_2/fll_execute/c/execute.h index 9c88259..3e18b53 100644 --- a/level_2/fll_execute/c/execute.h +++ b/level_2/fll_execute/c/execute.h @@ -362,7 +362,7 @@ extern "C" { * @param option * A bitwise set of options, such as: fl_execute_parameter_option_exit and fl_execute_parameter_option_path. * If fl_execute_parameter_option_exit: this will call exit() at the end of execution (be it success or failure). - * If fl_execute_parameter_option_path: this is a program path (such as "/bin/bash"), otherwise this is a program (such as "bash"). + * If fl_execute_parameter_option_path: use the whole program path (such as "/bin/bash" instead "bash" when populated argument[0]. * @param result * The code returned after finishing execution of program. * @@ -391,7 +391,7 @@ extern "C" { * The environment is defined by the names and values pair. * This requires paramete.values to also be specified with the same used length as parameter.names. * - * When parameter.option has the fl_execute_parameter_option_path bit set, then this does validate the path to the program. + * When the path has a slash "/" or the environment is to be cleared, then this does validate the path to the program. * Otherwise, this does not validate the path to the program. * * When the parameter.option has the fl_execute_parameter_option_exit bit set, then this calls exit() when the child process returns. @@ -411,7 +411,7 @@ extern "C" { * @param parameter * (optional) This and most of its fields are optional and are disabled when set to 0. * option: - * A bitwise set of options, such as: fl_execute_parameter_option_exit, and fl_execute_parameter_option_path. + * A bitwise set of options, such as: fl_execute_parameter_option_exit and fl_execute_parameter_option_path. * names: * An array of strings representing the environment variable names. * At most names.used variables are created. diff --git a/level_2/fll_execute/c/private-execute.c b/level_2/fll_execute/c/private-execute.c index 19c771b..8b65b2e 100644 --- a/level_2/fll_execute/c/private-execute.c +++ b/level_2/fll_execute/c/private-execute.c @@ -253,7 +253,7 @@ extern "C" { #endif // !defined(_di_fll_execute_program_) #if !defined(_di_fll_execute_program_) - f_status_t private_fll_execute_fork(const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) { + f_status_t private_fll_execute_fork(const bool direct, const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) { int descriptors[2] = { -1, -1 }; @@ -405,7 +405,7 @@ extern "C" { } } - const int code = parameter && (parameter->option & fl_execute_parameter_option_path) ? execv(program, fixed_arguments) : execvp(program, fixed_arguments); + const int code = direct ? execv(program, fixed_arguments) : execvp(program, fixed_arguments); if (result) { int *r = (int *) result; @@ -421,7 +421,7 @@ extern "C" { #endif // !defined(_di_fll_execute_program_) #if !defined(_di_fll_execute_program_) - f_status_t private_fll_execute_fork_data(const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) { + f_status_t private_fll_execute_fork_data(const bool direct, const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) { int descriptors[2] = { -1, -1 }; @@ -575,7 +575,7 @@ extern "C" { } } - const int code = parameter && parameter->option & fl_execute_parameter_option_path ? execv(program, fixed_arguments) : execvp(program, fixed_arguments); + const int code = direct ? execv(program, fixed_arguments) : execvp(program, fixed_arguments); // close the write pipe for the child when done. close(descriptors[0]); diff --git a/level_2/fll_execute/c/private-execute.h b/level_2/fll_execute/c/private-execute.h index 9d73114..09230ed 100644 --- a/level_2/fll_execute/c/private-execute.h +++ b/level_2/fll_execute/c/private-execute.h @@ -175,6 +175,9 @@ extern "C" { * * This implementation ignores parameter.data. * + * @param direct + * If TRUE, then use execv() to directly execute. + * If FALSE, then use execvp() to search for in PATH then execute. * @param program * The name or path of the program. * @param arguments @@ -240,7 +243,7 @@ extern "C" { * @see fll_execute_program() */ #if !defined(_di_fll_execute_program_) - extern f_status_t private_fll_execute_fork(const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) f_gcc_attribute_visibility_internal; + extern f_status_t private_fll_execute_fork(const bool direct, const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) f_gcc_attribute_visibility_internal; #endif // !defined(_di_fll_execute_program_) /** @@ -248,6 +251,9 @@ extern "C" { * * This implementation requires parameter.data. * + * @param direct + * If TRUE, then use execv() to directly execute. + * If FALSE, then use execvp() to search for in PATH then execute. * @param program * The name or path of the program. * @param arguments @@ -312,7 +318,7 @@ extern "C" { * @see fll_execute_program() */ #if !defined(_di_fll_execute_program_) - extern f_status_t private_fll_execute_fork_data(const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) f_gcc_attribute_visibility_internal; + extern f_status_t private_fll_execute_fork_data(const bool direct, const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, void *result) f_gcc_attribute_visibility_internal; #endif // !defined(_di_fll_execute_program_) /** -- 1.8.3.1