From beafe7afee539331be1e1147875b0a73ba08c22d Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Fri, 25 Dec 2020 21:39:17 -0600 Subject: [PATCH] Progress: controller program and other changes. Lots of changes with the most notable described below. This adds support for capabilities, which depends on the external libcap (-lcap). This introduces a problem because it is POSIX complaint in the sense of a draft and Linux has adopted it. The end result is that instead of being in libc, the functions are defined in libcap. To address this complication, a new project f_capability, is added to conditional compile in support and otherwise provide stubs. This allows the rest of the projects to just call the f_capability functions without needing as many macros. A define macro is still needed and the appropriate libary (-lcap) is still needed (or not if disabled). I have further observed that when adding -lcap, the ar progam's ficklness on the order becomes a problem. As a temporary work around, I am appending the "build_libraries" after all libaries introduced by a mode. --- build/level_0/settings | 7 +- build/level_2/settings | 3 +- build/monolithic/settings | 7 +- build/scripts/bootstrap-example.sh | 2 +- build/scripts/bootstrap.sh | 2 +- level_0/f_account/c/account.c | 10 +- level_0/f_account/c/account.h | 6 +- level_0/f_capability/c/capability-common.h | 58 +++ level_0/f_capability/c/capability.c | 501 ++++++++++++++++++ level_0/f_capability/c/capability.h | 450 ++++++++++++++++ level_0/f_capability/data/build/defines | 3 + level_0/f_capability/data/build/dependencies | 6 + level_0/f_capability/data/build/settings | 56 ++ level_0/f_status/c/status.h | 2 + level_1/fl_conversion/c/conversion.c | 12 +- level_1/fl_execute/c/execute-common.h | 55 +- level_1/fl_execute/c/execute.h | 2 +- level_1/fl_execute/data/build/defines | 1 + level_1/fl_execute/data/build/dependencies | 1 + level_1/fl_execute/data/build/settings | 5 +- level_1/fl_status/c/status.c | 6 + level_1/fl_status/c/status.h | 4 + level_2/fll_execute/c/execute.h | 7 +- level_2/fll_execute/c/private-execute.c | 10 +- level_2/fll_execute/c/private-execute.h | 2 +- level_2/fll_execute/data/build/defines | 2 +- level_2/fll_execute/data/build/dependencies | 1 + level_2/fll_execute/data/build/settings | 4 +- level_2/fll_status/c/status.c | 10 + level_3/controller/c/controller.c | 44 ++ level_3/controller/c/controller.h | 10 +- level_3/controller/c/private-common.h | 52 +- level_3/controller/c/private-controller.c | 84 +++ level_3/controller/c/private-controller.h | 54 ++ level_3/controller/c/private-rule.c | 575 ++++++++++++++++++--- level_3/controller/c/private-rule.h | 18 +- level_3/controller/data/build/defines | 2 +- level_3/controller/data/build/dependencies | 2 + level_3/controller/data/build/settings | 5 +- .../settings/example/rules/command/multiple.rule | 12 +- .../data/settings/rules/program/terminal.rule | 10 +- .../data/settings/rules/service/dbus.rule | 2 + .../data/settings/rules/service/logger.rule | 2 + .../data/settings/rules/service/mouse.rule | 2 + .../controller/data/settings/rules/task/clock.rule | 4 +- .../data/settings/rules/task/keyboard.rule | 2 + level_3/controller/documents/rule.txt | 26 +- level_3/controller/specifications/rule.txt | 13 +- level_3/fake/c/private-build.c | 27 + level_3/fake/data/build/defines | 1 + level_3/fake/data/build/dependencies | 1 + level_3/fake/data/build/settings | 5 +- level_3/firewall/data/build/defines | 1 + level_3/firewall/data/build/dependencies | 1 + level_3/firewall/data/build/settings | 6 +- 55 files changed, 2026 insertions(+), 170 deletions(-) create mode 100644 level_0/f_capability/c/capability-common.h create mode 100644 level_0/f_capability/c/capability.c create mode 100644 level_0/f_capability/c/capability.h create mode 100644 level_0/f_capability/data/build/defines create mode 100644 level_0/f_capability/data/build/dependencies create mode 100644 level_0/f_capability/data/build/settings diff --git a/build/level_0/settings b/build/level_0/settings index d4b781b..a59c5a7 100644 --- a/build/level_0/settings +++ b/build/level_0/settings @@ -18,11 +18,11 @@ modes_default level build_compiler gcc build_indexer ar build_language c -build_libraries -lc +build_libraries -lc -lcap build_libraries-level -build_sources_library account.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c private-iki.c memory.c path.c private-path.c pipe.c print.c private-print.c process.c serialize.c private-serialize.c signal.c socket.c utf.c private-utf.c +build_sources_library account.c capability.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c private-iki.c memory.c path.c private-path.c pipe.c print.c private-print.c process.c serialize.c private-serialize.c signal.c socket.c utf.c private-utf.c build_sources_program -build_sources_headers account.h account-common.h color.h console.h console-common.h conversion.h conversion-common.h directory.h directory_type.h directory-common.h environment.h environment-common.h execute.h execute-common.h file.h file-common.h fss.h fss-common.h fss_comment.h fss_delimit.h fss_named.h fss_nest.h fss_quote.h fss_set.h iki.h iki-common.h memory.h memory_structure.h path.h path-common.h pipe.h print.h process.h process-common.h serialize.h serialize-common.h signal.h signal-common.h socket.h socket-common.h status.h status_array.h string.h string-common.h string_dynamic.h string_map.h string_quantity.h string_range.h string_triple.h type.h type_array.h utf.h utf-common.h +build_sources_headers account.h account-common.h capability.h capability-common.h color.h console.h console-common.h conversion.h conversion-common.h directory.h directory_type.h directory-common.h environment.h environment-common.h execute.h execute-common.h file.h file-common.h fss.h fss-common.h fss_comment.h fss_delimit.h fss_named.h fss_nest.h fss_quote.h fss_set.h iki.h iki-common.h memory.h memory_structure.h path.h path-common.h pipe.h print.h process.h process-common.h serialize.h serialize-common.h signal.h signal-common.h socket.h socket-common.h status.h status_array.h string.h string-common.h string_dynamic.h string_map.h string_quantity.h string_range.h string_triple.h type.h type_array.h utf.h utf-common.h build_sources_script build_sources_setting build_script yes @@ -42,6 +42,7 @@ search_exclusive yes search_shared yes search_static yes +#defines_all -D_di_libcap_ defines_all defines_static defines_shared diff --git a/build/level_2/settings b/build/level_2/settings index 2a0b0c9..d63d28a 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -18,7 +18,7 @@ modes_default level build_compiler gcc build_indexer ar build_language c -build_libraries -lc +build_libraries -lc -lcap build_libraries-level -lfll_1 -lfll_0 build_sources_library environment.c error.c private-error.c execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c fss_status.c iki.c private-iki.c path.c program.c status.c build_sources_program @@ -42,6 +42,7 @@ search_exclusive yes search_shared yes search_static yes +#defines_all -D_di_libcap_ defines_all defines_static defines_shared diff --git a/build/monolithic/settings b/build/monolithic/settings index 3b2844f..44bb2c4 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -18,11 +18,11 @@ modes_default monolithic build_compiler gcc build_indexer ar build_language c -build_libraries -lc +build_libraries -lc -lcap build_libraries-monolithic -build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/private-print.c level_0/process.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_embedded_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/private-print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/type.c level_1/private-type.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/environment.c level_2/error.c level_2/private-error.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_embedded_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/program.c level_2/status.c +build_sources_library level_0/account.c level_0/capability.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/private-print.c level_0/process.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_embedded_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/private-print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/type.c level_1/private-type.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/environment.c level_2/error.c level_2/private-error.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_embedded_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/program.c level_2/status.c build_sources_program -build_sources_headers level_0/account.h level_0/account-common.h level_0/color.h level_0/console.h level_0/console-common.h level_0/conversion.h level_0/conversion-common.h level_0/directory.h level_0/directory_type.h level_0/directory-common.h level_0/environment.h level_0/environment-common.h level_0/execute.h level_0/execute-common.h level_0/file.h level_0/file-common.h level_0/fss.h level_0/fss-common.h level_0/fss_comment.h level_0/fss_delimit.h level_0/fss_named.h level_0/fss_nest.h level_0/fss_quote.h level_0/fss_set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory_structure.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/process.h level_0/process-common.h level_0/serialize.h level_0/serialize-common.h level_0/signal.h level_0/signal-common.h level_0/socket.h level_0/socket-common.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string-common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/string_triple.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/execute.h level_1/execute-common.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_embedded_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/type.h level_1/utf.h level_1/utf_file.h level_2/environment.h level_2/error.h level_2/error-common.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_embedded_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/iki.h level_2/path.h level_2/program.h level_2/status.h +build_sources_headers level_0/account.h level_0/account-common.h level_0/capability.h level_0/capability-common.h level_0/color.h level_0/console.h level_0/console-common.h level_0/conversion.h level_0/conversion-common.h level_0/directory.h level_0/directory_type.h level_0/directory-common.h level_0/environment.h level_0/environment-common.h level_0/execute.h level_0/execute-common.h level_0/file.h level_0/file-common.h level_0/fss.h level_0/fss-common.h level_0/fss_comment.h level_0/fss_delimit.h level_0/fss_named.h level_0/fss_nest.h level_0/fss_quote.h level_0/fss_set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory_structure.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/process.h level_0/process-common.h level_0/serialize.h level_0/serialize-common.h level_0/signal.h level_0/signal-common.h level_0/socket.h level_0/socket-common.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string-common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/string_triple.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/execute.h level_1/execute-common.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_embedded_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/type.h level_1/utf.h level_1/utf_file.h level_2/environment.h level_2/error.h level_2/error-common.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_embedded_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/iki.h level_2/path.h level_2/program.h level_2/status.h build_sources_script build_sources_setting build_script yes @@ -42,6 +42,7 @@ search_exclusive yes search_shared yes search_static yes +#defines_all -D_di_libcap_ defines_all defines_static defines_shared diff --git a/build/scripts/bootstrap-example.sh b/build/scripts/bootstrap-example.sh index 998e1f9..7d5593d 100644 --- a/build/scripts/bootstrap-example.sh +++ b/build/scripts/bootstrap-example.sh @@ -41,7 +41,7 @@ if [[ $1 == "individual" ]] ; then bash build/scripts/package.sh $verbose $color build -i if [[ $? -eq 0 ]] ; then - for i in f_type f_status f_memory f_string f_utf f_account f_color f_console f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_path f_pipe f_print f_process f_serialize f_signal f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_print fl_status fl_string fl_type fl_utf fl_utf_file fll_environment fll_error fll_execute fll_file fll_fss fll_iki fll_path fll_program fll_status ; do + for i in f_type f_status f_memory f_string f_utf f_account f_capability f_color f_console f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_path f_pipe f_print f_process f_serialize f_signal f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_print fl_status fl_string fl_type fl_utf fl_utf_file fll_environment fll_error fll_execute fll_file fll_fss fll_iki fll_path fll_program fll_status ; do echo && echo "Processing $i." && cd package/individual/$i-$2/ && diff --git a/build/scripts/bootstrap.sh b/build/scripts/bootstrap.sh index 792b43e..1b43ef7 100644 --- a/build/scripts/bootstrap.sh +++ b/build/scripts/bootstrap.sh @@ -623,7 +623,7 @@ bootstrap_operation_build() { if [[ $libraries == "" ]] ; then libraries=${variables[$(bootstrap_id build_libraries-$mode)]} else - libraries="$libraries ${variables[$(bootstrap_id build_libraries-$mode)]}" + libraries="${variables[$(bootstrap_id build_libraries-$mode)]} $libraries" fi if [[ $defines == "" ]] ; then diff --git a/level_0/f_account/c/account.c b/level_0/f_account/c/account.c index 88dd2bd..86149d1 100644 --- a/level_0/f_account/c/account.c +++ b/level_0/f_account/c/account.c @@ -6,6 +6,10 @@ extern "C" { #ifndef _di_f_account_id_group_by_name_ f_return_status f_account_id_group_by_name(const f_string_t name, gid_t *id) { + #ifndef _di_level_0_parameter_checking_ + if (!id) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + f_status_t status = F_none; const size_t length_max = sysconf(_SC_GETPW_R_SIZE_MAX); @@ -81,13 +85,17 @@ extern "C" { #ifndef _di_f_account_id_user_by_name_ f_return_status f_account_id_user_by_name(const f_string_t name, uid_t *id) { + #ifndef _di_level_0_parameter_checking_ + if (!id) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + f_status_t status = F_none; const size_t length_max = sysconf(_SC_GETPW_R_SIZE_MAX); // note: pointer seems pointless except that it is used to determine if the name was found. struct passwd password; - struct passwd *pointer; + struct passwd *pointer = 0; size_t length = length_max; diff --git a/level_0/f_account/c/account.h b/level_0/f_account/c/account.h index 7f8ba68..9be5caa 100644 --- a/level_0/f_account/c/account.h +++ b/level_0/f_account/c/account.h @@ -37,6 +37,7 @@ extern "C" { * * @param name * The group name. + * The name must be NULL terminated. * @param id * The id associated with the given name. * @@ -50,7 +51,7 @@ extern "C" { * F_interrupt (with error bit) when program received an interrupt signal, halting operation. * F_memory_not (with error bit) if out of memory. * F_parameter (with error bit) if a parameter is invalid. - * F_failure (with error bit) on any other failure. + * F_failure (with error bit) on any other error. * * @see getgrnam_r() */ @@ -63,6 +64,7 @@ extern "C" { * * @param name * The user name. + * The name must be NULL terminated. * @param id * The id associated with the given name. * @@ -76,7 +78,7 @@ extern "C" { * F_interrupt (with error bit) when program received an interrupt signal, halting operation. * F_memory_not (with error bit) if out of memory. * F_parameter (with error bit) if a parameter is invalid. - * F_failure (with error bit) on any other failure. + * F_failure (with error bit) on any other error. * * @see getpwnam_r() */ diff --git a/level_0/f_capability/c/capability-common.h b/level_0/f_capability/c/capability-common.h new file mode 100644 index 0000000..599ff22 --- /dev/null +++ b/level_0/f_capability/c/capability-common.h @@ -0,0 +1,58 @@ +/** + * FLL - Level 0 + * + * Project: Capability + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Defines common data to be used for/by capability related functionality. + * + * This is auto-included by account.h and should not need to be explicitly included. + */ +#ifndef _F_capability_common_h +#define _F_capability_common_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Provide a typedef of cap_t such that if _di_libcap_ is defined then a stub is used in its place. + */ +#ifndef _di_f_capability_t_ + + enum { + f_capability_value_type_effective = 0, + f_capability_value_type_permitted, + f_capability_value_type_inheritable, + }; + + enum { + f_capability_flag_type_clear = 0, + f_capability_flag_type_set, + }; + + // provide stubs in the event that libcap is disabled. + #ifdef _di_libcap_ + typedef void * cap_t; + typedef int cap_value_t; + typedef int cap_flag_t; + typedef int cap_flag_value_t; + #endif // _di_libcap_ + + typedef cap_t f_capability_t; + typedef cap_value_t f_capability_value_t; + typedef cap_flag_t f_capability_flag_t; + typedef cap_flag_value_t f_capability_flag_value_t; + + #define f_capability_t_initialize 0 + #define f_capability_value_t_initialize 0 + #define f_capability_flag_t_initialize 0 + #define f_capability_flag_value_t_initialize 0 +#endif // _di_f_capability_t_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_capability_common_h diff --git a/level_0/f_capability/c/capability.c b/level_0/f_capability/c/capability.c new file mode 100644 index 0000000..a222cf2 --- /dev/null +++ b/level_0/f_capability/c/capability.c @@ -0,0 +1,501 @@ +#include "capability.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _di_libcap_ + + #ifndef _di_f_capability_clear_ + f_return_status f_capability_clear(f_capability_t *capability) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_clear_ + + #ifndef _di_f_capability_clear_flag_ + f_return_status f_capability_clear_flag(const f_capability_flag_t flag, f_capability_t *capability) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_clear_flag_ + + #ifndef _di_f_capability_compare_ + f_return_status f_capability_compare(const f_capability_t capability1, const f_capability_t capability2, int *flags) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_compare_ + + #ifndef _di_f_capability_delete_ + f_return_status f_capability_delete(f_capability_t *capability) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_delete_ + + #ifndef _di_f_capability_duplicate_ + f_return_status f_capability_duplicate(const f_capability_t source, f_capability_t *destination) { + #ifndef _di_level_0_parameter_checking_ + if (!destination) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_duplicate_ + + #ifndef _di_f_capability_flag_get_ + f_return_status f_capability_flag_get(const f_capability_t capability, const f_capability_value_t code, const f_capability_flag_t flag, f_capability_flag_value_t *enabled) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_flag_get_ + + #ifndef _di_f_capability_flag_set_ + f_return_status f_capability_flag_set(const f_capability_flag_t flag, const f_capability_flag_value_t enabled, const f_int32s_t codes, f_capability_t *capability) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_flag_set_ + + #ifndef _di_f_capability_from_name_ + f_return_status f_capability_from_name(const f_string_t name, f_capability_value_t *code) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_from_name_ + + #ifndef _di_f_capability_from_text_ + f_return_status f_capability_from_text(const f_string_t text, f_capability_t *capability) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_from_text_ + + #ifndef _di_f_capability_process_bound_drop_ + f_return_status f_capability_process_bound_drop(f_capability_value_t code, int *bound) { + #ifndef _di_level_0_parameter_checking_ + if (!bound) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_process_bound_drop_ + + #ifndef _di_f_capability_process_bound_get_ + f_return_status f_capability_process_bound_get(f_capability_value_t code, int *bound) { + #ifndef _di_level_0_parameter_checking_ + if (!bound) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_process_bound_get_ + + #ifndef _di_f_capability_initialize_ + f_return_status f_capability_initialize(f_capability_t *capability) { + #ifndef _di_level_0_parameter_checking_ + if (!capability) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_initialize_ + + #ifndef _di_f_capability_process_get_ + f_return_status f_capability_process_get(f_capability_t *capability) { + #ifndef _di_level_0_parameter_checking_ + if (!capability) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_process_get_ + + #ifndef _di_f_capability_process_get_by_id_ + f_return_status f_capability_process_get_by_id(const pid_t id, f_capability_t *capability) { + #ifndef _di_level_0_parameter_checking_ + if (!capability) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_process_get_by_id_ + + #ifndef _di_f_capability_process_set_ + f_return_status f_capability_process_set(const f_capability_t capability) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_process_set_ + + #ifndef _di_f_capability_supported_ + bool f_capability_supported() { + return F_false; + } + #endif // _di_f_capability_supported_ + + #ifndef _di_f_capability_supported_code_ + bool f_capability_supported_code(const f_capability_value_t code) { + return F_false; + } + #endif // _di_f_capability_supported_code_ + + #ifndef _di_f_capability_to_name_ + f_return_status f_capability_to_name(const int code, f_string_dynamic_t *name) { + #ifndef _di_level_0_parameter_checking_ + if (!name) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_to_name_ + + #ifndef _di_f_capability_to_text_ + f_return_status f_capability_to_text(const f_capability_t capability, f_string_dynamic_t *text) { + return F_status_set_error(F_supported_not); + } + #endif // _di_f_capability_to_text_ + +#else // _di_libcap_ + + #ifndef _di_f_capability_clear_ + f_return_status f_capability_clear(f_capability_t *capability) { + + if (cap_clear(*capability) < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + + return F_status_set_error(F_failure); + } + + return F_none; + } + #endif // _di_f_capability_clear_ + + #ifndef _di_f_capability_clear_flag_ + f_return_status f_capability_clear_flag(const f_capability_flag_t flag, f_capability_t *capability) { + + if (cap_clear_flag(*capability, flag) < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + + return F_status_set_error(F_failure); + } + + return F_none; + } + #endif // _di_f_capability_clear_flag_ + + #ifndef _di_f_capability_compare_ + f_return_status f_capability_compare(const f_capability_t capability1, const f_capability_t capability2, int *flags) { + + if (*flags) { + *flags = 0; + } + + const int result = cap_compare(capability1, capability2); + + if (result < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + + return F_status_set_error(F_failure); + } + + if (result) { + if (*flags) { + *flags = result; + } + + return F_equal_to_not; + } + + return F_equal_to; + } + #endif // _di_f_capability_compare_ + + #ifndef _di_f_capability_delete_ + f_return_status f_capability_delete(f_capability_t *capability) { + + if (cap_free(*capability) < 0) { + return F_status_set_error(F_failure); + } + + *capability = 0; + + return F_none; + } + #endif // _di_f_capability_delete_ + + #ifndef _di_f_capability_duplicate_ + f_return_status f_capability_duplicate(const f_capability_t source, f_capability_t *destination) { + #ifndef _di_level_0_parameter_checking_ + if (!destination) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + *destination = cap_dup(source); + + if (*destination) { + return F_none; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_duplicate_ + + #ifndef _di_f_capability_flag_get_ + f_return_status f_capability_flag_get(const f_capability_t capability, const f_capability_value_t code, const f_capability_flag_t flag, f_capability_flag_value_t *enabled) { + #ifndef _di_level_0_parameter_checking_ + if (!enabled) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (cap_get_flag(capability, code, flag, enabled) < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + + return F_status_set_error(F_failure); + } + + return F_none; + } + #endif // _di_f_capability_flag_get_ + + #ifndef _di_f_capability_flag_set_ + f_return_status f_capability_flag_set(const f_capability_flag_t flag, const f_capability_flag_value_t enabled, const f_int32s_t codes, f_capability_t *capability) { + + if (cap_set_flag(*capability, flag, codes.used, codes.array, enabled) < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + + return F_status_set_error(F_failure); + } + + return F_none; + } + #endif // _di_f_capability_flag_set_ + + #ifndef _di_f_capability_from_name_ + f_return_status f_capability_from_name(const f_string_t name, f_capability_value_t *code) { + + if (cap_from_name(name, code) < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + + return F_none; + } + #endif // _di_f_capability_from_name_ + + #ifndef _di_f_capability_from_text_ + f_return_status f_capability_from_text(const f_string_t text, f_capability_t *capability) { + *capability = cap_from_text(text); + + if (*capability) { + return F_none; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_from_text_ + + #ifndef _di_f_capability_initialize_ + f_return_status f_capability_initialize(f_capability_t *capability) { + #ifndef _di_level_0_parameter_checking_ + if (!capability) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + *capability = cap_init(); + + if (*capability) { + return F_none; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_initialize_ + + #ifndef _di_f_capability_process_bound_drop_ + f_return_status f_capability_process_bound_drop(f_capability_value_t code, int *bound) { + + *bound = cap_drop_bound(code); + + if (*bound < 0) { + return F_known_not; + } + + if (*bound) { + return F_none; + } + + return F_supported_not; + } + #endif // _di_f_capability_process_bound_drop_ + + #ifndef _di_f_capability_process_bound_get_ + f_return_status f_capability_process_bound_get(f_capability_value_t code, int *bound) { + #ifndef _di_level_0_parameter_checking_ + if (!bound) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + *bound = cap_get_bound(code); + + if (*bound < 0) { + return F_known_not; + } + + if (*bound) { + return F_none; + } + + return F_supported_not; + } + #endif // _di_f_capability_process_bound_get_ + + #ifndef _di_f_capability_process_get_ + f_return_status f_capability_process_get(f_capability_t *capability) { + + *capability = cap_get_proc(); + + if (*capability) { + return F_none; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_process_get_ + + #ifndef _di_f_capability_process_get_by_id_ + f_return_status f_capability_process_get_by_id(const pid_t id, f_capability_t *capability) { + + *capability = cap_get_pid(id); + + if (*capability) { + return F_none; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_process_get_by_id_ + + #ifndef _di_f_capability_process_set_ + f_return_status f_capability_process_set(const f_capability_t capability) { + + if (cap_set_proc(capability) < 0) { + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + if (errno == EPERM) return F_status_set_error(F_prohibited); + + return F_status_set_error(F_failure); + } + + return F_none; + } + #endif // _di_f_capability_process_set_ + + #ifndef _di_f_capability_supported_ + bool f_capability_supported() { + return F_true; + } + #endif // _di_f_capability_supported_ + + #ifndef _di_f_capability_supported_code_ + bool f_capability_supported_code(const f_capability_value_t code) { + return CAP_IS_SUPPORTED(code); + } + #endif // _di_f_capability_supported_code_ + + #ifndef _di_f_capability_to_name_ + f_return_status f_capability_to_name(const int code, f_string_dynamic_t *name) { + #ifndef _di_level_0_parameter_checking_ + if (!name) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + char *result = cap_to_name(code); + + if (result) { + const f_string_length_t length = strlen(result); + + f_status_t status = F_none; + + if (name->used + length + 1 > name->size) { + if (name->used + length + 1 > f_string_length_t_size) { + return F_status_set_error(F_string_too_large); + } + + f_macro_string_dynamic_t_resize(status, (*name), name->used + length + 1); + + if (F_status_is_error(status)) { + cap_free(result); + + return status; + } + } + + memcpy(name->string + name->used, result, length); + name->used += length; + name->string[name->used] = 0; + + cap_free(result); + + return status; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_to_name_ + + #ifndef _di_f_capability_to_text_ + f_return_status f_capability_to_text(const f_capability_t capability, f_string_dynamic_t *text) { + #ifndef _di_level_0_parameter_checking_ + if (!text) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + f_string_length_t length = 0; + + char *result = cap_to_text(capability, &length); + + if (result) { + f_status_t status = F_none; + + if (text->used + length + 1> text->size) { + if (text->used + length + 1 > f_string_length_t_size) { + return F_status_set_error(F_string_too_large); + } + + f_macro_string_dynamic_t_resize(status, (*text), text->used + length + 1); + + if (F_status_is_error(status)) { + cap_free(result); + + return status; + } + } + + memcpy(text->string + text->used, result, length); + text->used += length; + text->string[text->used] = 0; + + cap_free(result); + + return status; + } + + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + + return F_status_set_error(F_failure); + } + #endif // _di_f_capability_to_text_ + +#endif // _di_libcap_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_capability/c/capability.h b/level_0/f_capability/c/capability.h new file mode 100644 index 0000000..a36c228 --- /dev/null +++ b/level_0/f_capability/c/capability.h @@ -0,0 +1,450 @@ +/** + * FLL - Level 0 + * + * Project: Capability + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Provides capability related functionality. + * + * Capabilities are POSIX compliant as of POSIX 1003.1e (as a draft). + * Because it is only in POSIX as a draft, they are available via libcap instead of libc. + * Special linking is necessary and this project provides a wrapper that makes capabilities easier to work with whether libcap (and therefore capabilities) is available or not. + * + * When _di_libcap_ is defined (-D_di_libcap_) then many of the structures and functions provided here are stubs. + * Compilations with _di_libcap_ will not be binary compatible with compilations without _di_libcap_. + */ +#ifndef _F_capability_h +#define _F_capability_h + +// libc includes +#include +#include + +#ifndef _di_libcap_ + #include +#endif // _di_libcap_ + +// fll-0 includes +#include +#include +#include +#include +#include + +// fll-0 capability includes +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Clear the capability structure. + * + * @param capability + * The capability to clear. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to duplicate. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_clear() + */ +#ifndef _di_f_capability_clear_ + extern f_return_status f_capability_clear(f_capability_t *capability); +#endif // _di_f_capability_clear_ + +/** + * Clear the capability flag. + * + * @param flag + * The flag to clear. + * @param capability + * The capability to clear the flag of. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to duplicate. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_clear_flag() + */ +#ifndef _di_f_capability_clear_flag_ + extern f_return_status f_capability_clear_flag(const f_capability_flag_t flag, f_capability_t *capability); +#endif // _di_f_capability_clear_flag_ + +/** + * Compare two capability structures. + * + * @param capability1 + * The first capability to compare. + * @param capability2 + * The second capability to compare. + * @param flags + * (optional) This represents which of the flags that differ on miss. + * Set to NULL to not use. + * + * @return + * F_equal_to on match. + * F_equal_to_not on miss. + * F_failure (with error bit) on failure to duplicate. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_compare() + */ +#ifndef _di_f_capability_compare_ + extern f_return_status f_capability_compare(const f_capability_t capability1, const f_capability_t capability2, int *flags); +#endif // _di_f_capability_compare_ + +/** + * Free the capability structure. + * + * @param capability + * The capability to delete. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to free memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_free() + */ +#ifndef _di_f_capability_delete_ + extern f_return_status f_capability_delete(f_capability_t *capability); +#endif // _di_f_capability_delete_ + +/** + * Duplicate (copy) the capability structure. + * + * Be sure to call f_capability_delete() when finished. + * + * @param source + * The capability to duplicate. + * @param destination + * The capability to copy to. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to duplicate. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_dup() + */ +#ifndef _di_f_capability_duplicate_ + extern f_return_status f_capability_duplicate(const f_capability_t source, f_capability_t *destination); +#endif // _di_f_capability_duplicate_ + +/** + * Get the value of a flag from the capability structure. + * + * @param capability + * The capability to get the code of. + * @param code + * The capability code to get the flag of. + * @param flag + * The flag of the capability code to get the value of. + * @param enabled + * The determined capability code flag value. + * This is TRUE when the flag is enabled and FALSE otherwise. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to free memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_get_flag() + */ +#ifndef _di_f_capability_flag_get_ + extern f_return_status f_capability_flag_get(const f_capability_t capability, const f_capability_value_t code, const f_capability_flag_t flag, f_capability_flag_value_t *enabled); +#endif // _di_f_capability_flag_get + +/** + * Set the value of a flags from the capability structure. + * + * @param flag + * The flag of the capability code to set the value of. + * @param enabled + * The capability code flag value to set. + * This is TRUE when the flag is enabled and FALSE otherwise. + * @param codes + * An array of codes to set the capability flag value of. + * @param capability + * The capability to set the flag of. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to free memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_set_flag() + */ +#ifndef _di_f_capability_flag_set_ + extern f_return_status f_capability_flag_set(const f_capability_flag_t flag, const f_capability_flag_value_t enabled, const f_int32s_t codes, f_capability_t *capability); +#endif // _di_f_capability_flag_set_ + +/** + * Get the capability code from the capability name. + * + * @param name + * The name of the capability (must be all lower case). + * @param code + * (optional) The determined code. + * Set to NULL to not use. + * + * @return + * F_none on success and name is known. + * F_known_not on success and name is unknown (and no code is provided). + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_from_name() + */ +#ifndef _di_f_capability_from_name_ + extern f_return_status f_capability_from_name(const f_string_t name, f_capability_value_t *code); +#endif // _di_f_capability_from_name_ + +/** + * Get the capability represented by the given string. + * + * @param text + * The human-readable NULL terminated string representing the capabilities (such as "cap_chown+ep"). + * @param capability + * The determined capabilities. + * This must be freed via f_capability_delete() when finished with it. + * + * @return + * F_none on success. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other failure. + * + * @see cap_from_text() + */ +#ifndef _di_f_capability_from_text_ + extern f_return_status f_capability_from_text(const f_string_t text, f_capability_t *capability); +#endif // _di_f_capability_from_text_ + +/** + * Initialize the capability structure. + * + * Be sure to call f_capability_delete() when finished. + * + * @param capability + * The capability to initialize. + * + * @return + * F_none on success. + * F_failure (with error bit) on failure to initialize. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * + * @see cap_init() + */ +#ifndef _di_f_capability_initialize_ + extern f_return_status f_capability_initialize(f_capability_t *capability); +#endif // _di_f_capability_initialize_ + +/** + * Drop the bound for the process. + * + * This will lower the specified bounding set capability if appropriate permission exist (the prevailing effective capability set must have a raised CAP_SETPCAP). + * + * @param code + * The capability code to get the bound for. + * @param bound + * The determined bound value. + * + * @return + * F_none on success. + * F_supported_not if the given code is not supported by the current system. + * F_known_not (with error bit) if the code is unknown. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other error. + * + * @see cap_drop_bound() + */ +#ifndef _di_f_capability_process_bound_drop_ + extern f_return_status f_capability_process_bound_drop(f_capability_value_t code, int *bound); +#endif // _di_f_capability_process_bound_drop_ + +/** + * Get the bound for the process. + * + * @param code + * The capability code to get the bound for. + * @param bound + * The determined bound value. + * + * @return + * F_none on success. + * F_supported_not if the given code is not supported by the current system. + * F_known_not (with error bit) if the code is unknown. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other error. + * + * @see cap_get_bound() + */ +#ifndef _di_f_capability_process_bound_get_ + extern f_return_status f_capability_process_bound_get(f_capability_value_t code, int *bound); +#endif // _di_f_capability_process_bound_get_ + +/** + * Get the capability for the current process. + * + * Be sure to call f_capability_delete() when finished. + * + * @param capability + * The determined capability. + * + * @return + * F_none on success. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other error. + * + * @see cap_get_proc() + */ +#ifndef _di_f_capability_process_get_ + extern f_return_status f_capability_process_get(f_capability_t *capability); +#endif // _di_f_capability_process_get_ + +/** + * Get the capability for the process represented by the given PID. + * + * Be sure to call f_capability_delete() when finished. + * + * @param id + * The process ID (pid) to get capabilities of. + * @param capability + * The determined capability. + * + * @return + * F_none on success. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other error. + * + * @see cap_get_pid() + */ +#ifndef _di_f_capability_process_get_by_id_ + extern f_return_status f_capability_process_get_by_id(const pid_t id, f_capability_t *capability); +#endif // _di_f_capability_process_get_by_id_ + +/** + * Set the capability for the current process. + * + * @param capability + * The capability to assign. + * + * @return + * F_none on success. + * F_memory_not (with error bit) if a out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_prohibited (with error bit) if system does not support a capability code specified. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other error. + * + * @see cap_set_proc() + */ +#ifndef _di_f_capability_process_set_ + extern f_return_status f_capability_process_set(const f_capability_t capability); +#endif // _di_f_capability_process_set_ + +/** + * Check if capabilities are supported. + * + * @return + * TRUE if supported. + * FALSE otherwise. + */ +#ifndef _di_f_capability_supported_ + extern bool f_capability_supported(); +#endif // _di_f_capability_supported_ + +/** + * Check if capabilities are supported. + * + * @param code + * The capability code. + * + * @return + * TRUE if the code is supported. + * FALSE otherwise. + * + * @see CAP_IS_SUPPORTED() + */ +#ifndef _di_f_capability_supported_code_ + extern bool f_capability_supported_code(f_capability_value_t code); +#endif // _di_f_capability_supported_code_ + +/** + * Convert the capability code to a name (string). + * + * @param code + * The capability code. + * @param name + * The determined name. + * The name is appended into this variable. + * This is not NULL terminated. + * + * @return + * F_none on success. + * F_parameter (with error bit) if a parameter is invalid. + * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other failure. + * + * @see cap_free() + * @see cap_to_name() + */ +#ifndef _di_f_capability_to_name_ + extern f_return_status f_capability_to_name(const f_capability_value_t code, f_string_dynamic_t *name); +#endif // _di_f_capability_to_name_ + +/** + * Convert the capability to a human-readable NULL terminated string. + * + * @param capability + * The capability code. + * @param text + * The determined human-readable NULL terminated string. + * + * @return + * F_none on success. + * F_parameter (with error bit) if a parameter is invalid. + * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. + * F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in). + * F_failure (with error bit) on any other failure. + * + * @see cap_free() + * @see cap_to_text() + */ +#ifndef _di_f_capability_to_text_ + extern f_return_status f_capability_to_text(const f_capability_t capability, f_string_dynamic_t *text); +#endif // _di_f_capability_to_text_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_capability_h diff --git a/level_0/f_capability/data/build/defines b/level_0/f_capability/data/build/defines new file mode 100644 index 0000000..0d51e58 --- /dev/null +++ b/level_0/f_capability/data/build/defines @@ -0,0 +1,3 @@ +# fss-0000 +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). + diff --git a/level_0/f_capability/data/build/dependencies b/level_0/f_capability/data/build/dependencies new file mode 100644 index 0000000..d798245 --- /dev/null +++ b/level_0/f_capability/data/build/dependencies @@ -0,0 +1,6 @@ +# fss-0000 + +f_type +f_status +f_memory +f_string diff --git a/level_0/f_capability/data/build/settings b/level_0/f_capability/data/build/settings new file mode 100644 index 0000000..f1dccd4 --- /dev/null +++ b/level_0/f_capability/data/build/settings @@ -0,0 +1,56 @@ +# fss-0001 + +project_name f_capability + +version_major 0 +version_minor 5 +version_micro 2 +version_target major + +environment + +process_pre +process_post + +modes individual +modes_default individual + +build_compiler gcc +build_indexer ar +build_language c +build_libraries -lc -lcap +build_libraries-individual -lf_memory +build_sources_library capability.c +build_sources_program +build_sources_headers capability.h capability-common.h +build_sources_script +build_sources_setting +build_script yes +build_shared yes +build_static yes + +path_headers level_0 +path_headers_preserve no +path_library_script script +path_library_shared shared +path_library_static static +path_program_script script +path_program_shared shared +path_program_static static +path_sources +path_standard yes + +search_exclusive yes +search_shared yes +search_static yes + +#defines_all -D_di_libcap_ +defines_all +defines_static +defines_shared + +flags_all -z now -g -fdiagnostics-color=always +flags_shared +flags_static +flags_library -fPIC +flags_program -fPIE diff --git a/level_0/f_status/c/status.h b/level_0/f_status/c/status.h index 7a9e7c6..a43b0d6 100644 --- a/level_0/f_status/c/status.h +++ b/level_0/f_status/c/status.h @@ -326,6 +326,8 @@ extern "C" { F_number_overflow, F_number_positive, F_number_positive_not, + F_number_too_large, + F_number_too_small, F_number_underflow, F_number_whole, F_number_whole_not, diff --git a/level_1/fl_conversion/c/conversion.c b/level_1/fl_conversion/c/conversion.c index 5f42a44..80d0aea 100644 --- a/level_1/fl_conversion/c/conversion.c +++ b/level_1/fl_conversion/c/conversion.c @@ -613,7 +613,11 @@ extern "C" { } if (string[i] == 0x30) { - j = i + 1; + + // skip past all NULLs. + for (j = i + 1; j <= range.stop; ++j) { + if (string[j]) break; + } // for // Immediate next value must be either a number, 'x', 'X', 'd', 'D', 'o', 'O', 'b', or 'B'. if (j > range.stop) { @@ -765,7 +769,11 @@ extern "C" { } if (string[i] == 0x30) { - j = i + 1; + + // skip past all NULLs. + for (j = i + 1; j <= range.stop; ++j) { + if (string[j]) break; + } // for // Immediate next value must be either a number, 'x', 'X', 'd', 'D', 'o', 'O', 'b', or 'B'. if (j > range.stop) { diff --git a/level_1/fl_execute/c/execute-common.h b/level_1/fl_execute/c/execute-common.h index 3a5610c..e6be62a 100644 --- a/level_1/fl_execute/c/execute-common.h +++ b/level_1/fl_execute/c/execute-common.h @@ -52,27 +52,6 @@ extern "C" { #endif // _di_fl_execute_parameter_t_ /** - * A structure representing an array of group ids. - * - * groups: a pointer to an array of groups. - * size: the length of the array of groups. - */ -#ifndef _di_fl_execute_groups_t_ - typedef struct { - gid_t *groups; - f_array_length_t size; - } fl_execute_groups_t; - - #define fl_execute_groups_t_initialize { 0, 0 } - - #define fl_macro_execute_groups_t_initialize(groups, size) { groups, size } - - #define fl_execute_groups_t_clear(structure) \ - structure.groups = 0; \ - structure.size = 0; -#endif // _di_fl_execute_groups_t_ - -/** * A structure representing a scheduler and its parameters for execution. * * policy: the scheduler policy. @@ -98,41 +77,41 @@ extern "C" { * * There are likely many more identity and access related things that can be done but this focuses on a small core set of those. * - * Note: Containers, or cgroups, exist here as a full file path in which the PID of a child process is to be written to. - * This may change as more is learned about using cgroups, but it is not known if there are any functions available like set_cgroup(..). + * Control Groups, or cgroups, exist here as a full file path in which the PID of a child process is to be written to. + * This may change as more is learned about using cgroups, but it is not known if there are any functions available like set_cgroup(..). * * nice: the niceness value to assign the child process to, set to 0 to not use. * id_user: the id of the user to assign the child process to, set to 0 to not use. * id_group: the id of the group to assign the child process to, set to 0 to not use. - * capability: all of the capabilities to assign the child process to, set to 0 to not use. - * ids_group: the ids of each supplemental group to assign the child process to, set to 0 to not use. + * capability: all of the capabilities to assign the child process to, set to 0 to not use (f_capability_t is a pointer). + * id_groups: the ids of each supplemental group to assign the child process to, set to 0 to not use. * scheduler: the scheduler to assign the child process to, set to 0 to not use. - * containers: an array of cgroups (container groups) to assign the child PID to, set to 0 to not use. + * controls: an array of cgroups (control groups) to assign the child PID to, set to 0 to not use. */ #ifndef _di_fl_execute_as_t_ typedef struct { - const int *nice; - const uid_t *id_user; - const gid_t *id_group; - //const cap_t *capability; // @todo - - const fl_execute_groups_t *ids_group; - const fl_execute_scheduler_t *scheduler; - const f_string_dynamics_t *containers; + int *nice; + uid_t *id_user; + gid_t *id_group; + f_capability_t capability; + + f_int32s_t *id_groups; + fl_execute_scheduler_t *scheduler; + f_string_dynamics_t *controls; } fl_execute_as_t; - #define fl_execute_as_t_initialize { 0, 0, 0, /*0,*/ fl_execute_groups_t_initialize, fl_execute_scheduler_t_initialize, f_string_dynamics_t_initialize } + #define fl_execute_as_t_initialize { 0, 0, 0, 0, 0, 0, 0 } - #define fl_macro_execute_as_t_initialize(nice, id_user, id_group, /*capability,*/ id_groups, scheduler, containers) { nice, id_user, id_group, /*capability,*/ id_groups, scheduler, containers } + #define fl_macro_execute_as_t_initialize(nice, id_user, id_group, capability, id_groups, scheduler, controls) { nice, id_user, id_group, capability, id_groups, scheduler, controls } #define fl_execute_as_t_clear(as) \ as.nice = 0; \ as.id_user = 0; \ as.id_group = 0; \ - /*as.capability = 0;*/ \ + as.capability = 0; \ as.id_groups = 0; \ as.scheduler = 0; \ - as.containers = 0; + as.controls = 0; #endif // _di_fl_execute_as_t_ #ifdef __cplusplus diff --git a/level_1/fl_execute/c/execute.h b/level_1/fl_execute/c/execute.h index cd5e08e..ab3ba2d 100644 --- a/level_1/fl_execute/c/execute.h +++ b/level_1/fl_execute/c/execute.h @@ -17,13 +17,13 @@ // libc includes #include #include -//#include // @todo // fll-0 includes #include #include #include #include +#include // fll-1 execute includes #include diff --git a/level_1/fl_execute/data/build/defines b/level_1/fl_execute/data/build/defines index 4f13080..903c38c 100644 --- a/level_1/fl_execute/data/build/defines +++ b/level_1/fl_execute/data/build/defines @@ -1 +1,2 @@ # fss-0000 +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). diff --git a/level_1/fl_execute/data/build/dependencies b/level_1/fl_execute/data/build/dependencies index ded2e76..7e33434 100644 --- a/level_1/fl_execute/data/build/dependencies +++ b/level_1/fl_execute/data/build/dependencies @@ -3,5 +3,6 @@ f_type f_status f_string +f_capability f_signal f_execute diff --git a/level_1/fl_execute/data/build/settings b/level_1/fl_execute/data/build/settings index 312de21..a13c57c 100644 --- a/level_1/fl_execute/data/build/settings +++ b/level_1/fl_execute/data/build/settings @@ -18,8 +18,8 @@ modes_default individual build_compiler gcc build_indexer ar build_language c -build_libraries -lc -build_libraries-individual -lf_memory -lf_signal +build_libraries -lc -lcap +build_libraries-individual -lf_capability -lf_memory -lf_signal build_sources_library build_sources_program build_sources_headers execute.h execute-common.h @@ -44,6 +44,7 @@ search_exclusive yes search_shared yes search_static yes +#defines_all -D_en_libcap_ defines_all defines_static defines_shared diff --git a/level_1/fl_status/c/status.c b/level_1/fl_status/c/status.c index 14bb0b3..0b311ca 100644 --- a/level_1/fl_status/c/status.c +++ b/level_1/fl_status/c/status.c @@ -737,6 +737,12 @@ extern "C" { case F_number_positive_not: *string = FL_status_string_number_positive_not; break; + case F_number_too_large: + *string = FL_status_string_number_too_large; + break; + case F_number_too_small: + *string = FL_status_string_number_too_small; + break; case F_number_underflow: *string = FL_status_string_number_underflow; break; diff --git a/level_1/fl_status/c/status.h b/level_1/fl_status/c/status.h index 4fb4c29..f11acf6 100644 --- a/level_1/fl_status/c/status.h +++ b/level_1/fl_status/c/status.h @@ -509,6 +509,8 @@ extern "C" { #define FL_status_string_number_overflow "F_number_overflow" #define FL_status_string_number_positive "F_number_positive" #define FL_status_string_number_positive_not "F_number_positive_not" + #define FL_status_string_number_too_large "F_number_too_large" + #define FL_status_string_number_too_small "F_number_too_small" #define FL_status_string_number_underflow "F_number_underflow" #define FL_status_string_number_whole "F_number_whole" #define FL_status_string_number_whole_not "F_number_whole_not" @@ -525,6 +527,8 @@ extern "C" { #define FL_status_string_number_overflow_length 17 #define FL_status_string_number_positive_length 17 #define FL_status_string_number_positive_not_length 21 + #define FL_status_string_number_too_large_length 18 + #define FL_status_string_number_too_small_length 18 #define FL_status_string_number_underflow_length 18 #define FL_status_string_number_whole_length 14 #define FL_status_string_number_whole_not_length 18 diff --git a/level_2/fll_execute/c/execute.h b/level_2/fll_execute/c/execute.h index ce34a3d..2ba0dfb 100644 --- a/level_2/fll_execute/c/execute.h +++ b/level_2/fll_execute/c/execute.h @@ -6,6 +6,9 @@ * Licenses: lgplv2.1 * * Provides program execution operations similar to system(). + * + * Some functions support capabilities, which are POSIX compliant as of POSIX 1003.1e (as a draft). + * Because it is only in POSIX as a draft, they are available via libcap instead of libc. */ #ifndef _FLL_execute_h #define _FLL_execute_h @@ -25,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -425,6 +429,7 @@ extern "C" { * F_schedule (with error bit) on failure to set scheduler in the child (only the child process returns this). * F_user (with error bit) on failure to set UID in the child (only the child process returns this). * + * Errors (with error bit) from: f_capability_process_set(). * Errors (with error bit) from: f_environment_get(). * Errors (with error bit) from: f_file_exists(). * Errors (with error bit) from: f_macro_string_dynamics_t_delete(). @@ -434,7 +439,6 @@ extern "C" { * Errors (with error bit) from: fl_string_dynamic_delete(). * Errors (with error bit) from: fl_string_dynamic_terminate(). * - * @see cap_set_proc() * @see close() * @see clearenv() * @see dup2() @@ -453,6 +457,7 @@ extern "C" { * @see strnlen() * @see waitpid() * + * @see f_capability_process_set() * @see f_environment_get() * @see f_file_exists() * @see f_signal_set_handle() diff --git a/level_2/fll_execute/c/private-execute.c b/level_2/fll_execute/c/private-execute.c index c3f8154..b424159 100644 --- a/level_2/fll_execute/c/private-execute.c +++ b/level_2/fll_execute/c/private-execute.c @@ -149,9 +149,10 @@ extern "C" { } } - /* @todo library dependencies, if this is not in libc, then this may not be supported. more investigation is needed. if (as.capability) { - if (cap_set_proc(*as.capability) == -1) { + const f_status_t status = f_capability_process_set(as.capability); + + if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) { *result = -1; if (parameter && parameter->option & fl_execute_parameter_option_exit) { @@ -161,10 +162,9 @@ extern "C" { return F_status_set_error(F_capability); } } - */ - if (as.ids_group) { - if (setgroups(as.ids_group->size, as.ids_group->groups) == -1) { + if (as.id_groups) { + if (setgroups(as.id_groups->used, as.id_groups->array) == -1) { *result = -1; if (parameter && parameter->option & fl_execute_parameter_option_exit) { diff --git a/level_2/fll_execute/c/private-execute.h b/level_2/fll_execute/c/private-execute.h index 6abd480..3e9a048 100644 --- a/level_2/fll_execute/c/private-execute.h +++ b/level_2/fll_execute/c/private-execute.h @@ -127,7 +127,6 @@ extern "C" { * F_schedule (with error bit) on failure to set scheduler. * F_user (with error bit) on failure to set UID. * - * @see cap_set_proc() * @see exit() * @see getpid() * @see nice() @@ -136,6 +135,7 @@ extern "C" { * @see setgroups() * @see setuid() * + * @see f_capability_process_set() * @see fll_execute_program() */ #if !defined(_di_fll_execute_program_) diff --git a/level_2/fll_execute/data/build/defines b/level_2/fll_execute/data/build/defines index c665317..903c38c 100644 --- a/level_2/fll_execute/data/build/defines +++ b/level_2/fll_execute/data/build/defines @@ -1,2 +1,2 @@ # fss-0000 - +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). diff --git a/level_2/fll_execute/data/build/dependencies b/level_2/fll_execute/data/build/dependencies index 44e3cdb..9f34036 100644 --- a/level_2/fll_execute/data/build/dependencies +++ b/level_2/fll_execute/data/build/dependencies @@ -4,6 +4,7 @@ f_type f_status f_memory f_string +f_capability f_environment f_execute f_file diff --git a/level_2/fll_execute/data/build/settings b/level_2/fll_execute/data/build/settings index aec0966..a789937 100644 --- a/level_2/fll_execute/data/build/settings +++ b/level_2/fll_execute/data/build/settings @@ -18,8 +18,8 @@ modes_default individual build_compiler gcc build_indexer ar build_language c -build_libraries -lc -build_libraries-individual -lfl_environment -lfl_string -lf_environment -lf_file -lf_memory -lf_path -lf_signal -lf_utf +build_libraries -lc -lcap +build_libraries-individual -lfl_environment -lfl_string -lf_capability -lf_environment -lf_file -lf_memory -lf_path -lf_signal -lf_utf build_sources_library execute.c private-execute.c build_sources_program build_sources_headers execute.h diff --git a/level_2/fll_status/c/status.c b/level_2/fll_status/c/status.c index 16aa35b..6d749f5 100644 --- a/level_2/fll_status/c/status.c +++ b/level_2/fll_status/c/status.c @@ -1219,6 +1219,16 @@ extern "C" { return F_none; } + if (fl_string_compare(string, FL_status_string_number_too_large, length, FL_status_string_number_too_large_length) == F_equal_to) { + *code = F_number_too_large; + return F_none; + } + + if (fl_string_compare(string, FL_status_string_number_too_small, length, FL_status_string_number_too_small_length) == F_equal_to) { + *code = F_number_too_small; + return F_none; + } + if (fl_string_compare(string, FL_status_string_number_underflow, length, FL_status_string_number_underflow_length) == F_equal_to) { *code = F_number_underflow; return F_none; diff --git a/level_3/controller/c/controller.c b/level_3/controller/c/controller.c index fc65983..88c1ab7 100644 --- a/level_3/controller/c/controller.c +++ b/level_3/controller/c/controller.c @@ -26,6 +26,7 @@ extern "C" { fprintf(output.stream, "%c", f_string_eol_s[0]); + fll_program_print_help_option(output, context, controller_short_control, controller_long_control, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom control group file path, such as '" controller_path_control "'."); fll_program_print_help_option(output, context, controller_short_daemon, controller_long_daemon, f_console_symbol_short_enable, f_console_symbol_long_enable, " Run in daemon only mode (do not process the entry)."); fll_program_print_help_option(output, context, controller_short_interruptable, controller_long_interruptable, f_console_symbol_short_enable, f_console_symbol_long_enable, "Designate that this program can be interrupted."); fll_program_print_help_option(output, context, controller_short_pid, controller_long_pid, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom pid file path, such as '" controller_path_pid controller_string_default controller_path_suffix "'."); @@ -252,6 +253,49 @@ extern "C" { } } + if (data->parameters[controller_parameter_control].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s); + fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_control, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[controller_parameter_control].locations.used) { + const f_array_length_t location = data->parameters[controller_parameter_control].values.array[data->parameters[controller_parameter_control].values.used - 1]; + + if (strnlen(arguments.argv[location], f_console_length_size)) { + status = fll_path_canonical(arguments.argv[location], &setting.path_control); + + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "fll_path_canonical", F_true); + } + } + } + else { + if (data->warning.verbosity == f_console_verbosity_debug) { + fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(data->warning.to.stream, "%s%sThe parameter '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s); + fprintf(data->warning.to.stream, "%s%s%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, f_console_symbol_long_enable, controller_long_control, data->warning.notable.after->string); + fprintf(data->warning.to.stream, "%s' must be a file directory path but instead is an empty string, falling back to the default.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]); + } + } + } + + // a control file path is required. + if (!setting.path_control.used) { + status = fl_string_append(controller_path_control, controller_path_control_length, &setting.path_control); + + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true); + } + } + } + if (data->parameters[controller_parameter_daemon].result == f_console_result_found) { if (data->parameters[controller_parameter_validate].result == f_console_result_found) { diff --git a/level_3/controller/c/controller.h b/level_3/controller/c/controller.h index 632a465..a59dafb 100644 --- a/level_3/controller/c/controller.h +++ b/level_3/controller/c/controller.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -83,14 +85,17 @@ extern "C" { #define controller_default_program_script "bash" + #define controller_path_control "/sys/fs/cgroup/unified" #define controller_path_pid "/var/run/controller/controller-" #define controller_path_settings "/etc/controller" #define controller_path_suffix ".pid" + #define controller_path_control_length 22 #define controller_path_pid_length 31 #define controller_path_settings_length 15 #define controller_path_suffix_length 4 + #define controller_short_control "c" #define controller_short_daemon "d" #define controller_short_interruptable "i" #define controller_short_pid "p" @@ -98,6 +103,7 @@ extern "C" { #define controller_short_test "t" #define controller_short_validate "v" + #define controller_long_control "control" #define controller_long_daemon "daemon" #define controller_long_interruptable "interruptable" #define controller_long_pid "pid" @@ -116,6 +122,7 @@ extern "C" { controller_parameter_verbosity_debug, controller_parameter_version, + controller_parameter_control, controller_parameter_daemon, controller_parameter_interruptable, controller_parameter_pid, @@ -135,6 +142,7 @@ extern "C" { f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 0, 0, f_console_type_inverse), \ f_console_parameter_t_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_console_type_inverse), \ f_console_parameter_t_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(controller_short_control, controller_long_control, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(controller_short_daemon, controller_long_daemon, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(controller_short_interruptable, controller_long_interruptable, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(controller_short_pid, controller_long_pid, 0, 1, f_console_type_normal), \ @@ -143,7 +151,7 @@ extern "C" { f_console_parameter_t_initialize(controller_short_validate, controller_long_validate, 0, 0, f_console_type_normal), \ } - #define controller_total_parameters 15 + #define controller_total_parameters 16 #endif // _di_controller_defines_ #ifndef _di_controller_data_t_ diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index dbe8fdc..ad9aba9 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -17,10 +17,11 @@ extern "C" { #define controller_string_actions "actions" #define controller_string_asynchronous "asynchronous" #define controller_string_bash "bash" + #define controller_string_capability "capability" #define controller_string_create "create" #define controller_string_command "command" #define controller_string_consider "consider" - #define controller_string_control_group "control_group" + #define controller_string_control "control" #define controller_string_default "default" #define controller_string_define "define" #define controller_string_entry "entry" @@ -29,6 +30,7 @@ extern "C" { #define controller_string_fail "fail" #define controller_string_failsafe "failsafe" #define controller_string_group "group" + #define controller_string_groups "groups" #define controller_string_how "how" #define controller_string_item "item" #define controller_string_kill "kill" @@ -36,6 +38,7 @@ extern "C" { #define controller_string_method "method" #define controller_string_name "name" #define controller_string_need "need" + #define controller_string_nice "nice" #define controller_string_no "no" #define controller_string_optional "optional" #define controller_string_parameter "parameter" @@ -49,6 +52,7 @@ extern "C" { #define controller_string_restart "restart" #define controller_string_rule "rule" #define controller_string_rules "rules" + #define controller_string_scheduler "scheduler" #define controller_string_script "script" #define controller_string_service "service" #define controller_string_setting "setting" @@ -69,10 +73,11 @@ extern "C" { #define controller_string_actions_length 7 #define controller_string_asynchronous_length 12 #define controller_string_bash_length 4 + #define controller_string_capability_length 10 #define controller_string_create_length 6 #define controller_string_command_length 7 #define controller_string_consider_length 8 - #define controller_string_control_group_length 13 + #define controller_string_control_length 7 #define controller_string_define_length 6 #define controller_string_default_length 7 #define controller_string_entry_length 5 @@ -88,6 +93,7 @@ extern "C" { #define controller_string_method_length 6 #define controller_string_name_length 4 #define controller_string_need_length 4 + #define controller_string_nice_length 4 #define controller_string_no_length 2 #define controller_string_optional_length 8 #define controller_string_parameter_length 9 @@ -101,6 +107,7 @@ extern "C" { #define controller_string_restart_length 7 #define controller_string_rule_length 4 #define controller_string_rules_length 5 + #define controller_string_scheduler_length 9 #define controller_string_script_length 6 #define controller_string_service_length 7 #define controller_string_setting_length 7 @@ -242,14 +249,19 @@ extern "C" { #ifndef _di_controller_rule_t_ enum { - controller_rule_setting_type_control_group = 1, + controller_rule_setting_type_capability = 1, + controller_rule_setting_type_control, controller_rule_setting_type_define, controller_rule_setting_type_environment, + controller_rule_setting_type_group, controller_rule_setting_type_name, controller_rule_setting_type_need, + controller_rule_setting_type_nice, controller_rule_setting_type_parameter, controller_rule_setting_type_path, + controller_rule_setting_type_scheduler, controller_rule_setting_type_script, + controller_rule_setting_type_user, controller_rule_setting_type_want, controller_rule_setting_type_wish, }; @@ -259,6 +271,11 @@ extern "C" { #define controller_rule_option_simulate 0x4 #define controller_rule_option_wait 0x8 + // bitwise codes representing properties on controller_rule_t that have been found in the rule file. + #define controller_rule_has_group 0x1 + #define controller_rule_has_nice 0x2 + #define controller_rule_has_user 0x4 + typedef struct { f_status_t status; f_number_signed_t process; // @todo: for background/threaded support (ideally should hold the process id, but remove if this ends up not being the strategy) (this can also be used by the parent/main process to check to see if the child no longer a child of this process). @@ -267,12 +284,18 @@ extern "C" { f_number_unsigned_t timeout_start; f_number_unsigned_t timeout_stop; + uint8_t has; + int nice; + uid_t user; + gid_t group; + f_time_spec_t timestamp; f_string_dynamic_t id; f_string_dynamic_t name; - f_string_dynamic_t control_group; + f_string_dynamic_t control; f_string_dynamic_t path; + f_string_dynamic_t scheduler; f_string_dynamic_t script; f_string_maps_t define; @@ -283,6 +306,9 @@ extern "C" { f_string_dynamics_t want; f_string_dynamics_t wish; + f_capability_t capability; + f_int32s_t groups; + controller_rule_items_t items; } controller_rule_t; @@ -293,26 +319,34 @@ extern "C" { 0, \ 0, \ 0, \ + 0, \ + 0, \ + 0, \ + 0, \ f_time_spec_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ f_string_maps_t_initialize, \ f_string_maps_t_initialize, \ f_string_dynamics_t_initialize, \ f_string_dynamics_t_initialize, \ f_string_dynamics_t_initialize, \ f_string_dynamics_t_initialize, \ + f_capability_t_initialize, \ + f_int32s_t_initialize, \ controller_rule_items_initialize, \ } #define controller_macro_rule_t_delete_simple(rule) \ fl_string_dynamic_delete(&rule.id); \ fl_string_dynamic_delete(&rule.name); \ - fl_string_dynamic_delete(&rule.control_group); \ + fl_string_dynamic_delete(&rule.control); \ fl_string_dynamic_delete(&rule.path); \ + fl_string_dynamic_delete(&rule.scheduler); \ fl_string_dynamic_delete(&rule.script); \ f_macro_string_maps_t_delete_simple(rule.define) \ f_macro_string_maps_t_delete_simple(rule.parameter) \ @@ -320,6 +354,8 @@ extern "C" { fl_string_dynamics_delete(&rule.need); \ fl_string_dynamics_delete(&rule.want); \ fl_string_dynamics_delete(&rule.wish); \ + f_capability_delete(&rule.capability); \ + fl_type_int32s_delete(&rule.groups); \ controller_macro_rule_items_t_delete_simple(rule.items) #endif // _di_controller_rule_t_ @@ -500,6 +536,7 @@ extern "C" { bool failsafe_enabled; f_array_length_t failsafe_rule_id; + f_string_dynamic_t path_control; f_string_dynamic_t path_pid; f_string_dynamic_t path_setting; @@ -519,11 +556,13 @@ extern "C" { 0, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ controller_entry_t_initialize, \ controller_rules_t_initialize, \ } #define controller_macro_setting_t_delete_simple(setting) \ + fl_string_dynamic_delete(&setting.path_control); \ fl_string_dynamic_delete(&setting.path_pid); \ fl_string_dynamic_delete(&setting.path_setting); \ controller_macro_entry_t_delete_simple(setting.entry) \ @@ -553,6 +592,7 @@ extern "C" { f_string_dynamic_t buffer_file; f_string_dynamic_t buffer_item; + f_string_dynamic_t buffer_other; f_string_dynamic_t buffer_path; f_string_dynamic_t name_action; @@ -581,6 +621,7 @@ extern "C" { f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ } #define controller_macro_cache_t_delete_simple(cache) \ @@ -595,6 +636,7 @@ extern "C" { f_macro_fss_objects_t_delete_simple(cache.object_items) \ fl_string_dynamic_delete(&cache.buffer_file); \ fl_string_dynamic_delete(&cache.buffer_item); \ + fl_string_dynamic_delete(&cache.buffer_other); \ fl_string_dynamic_delete(&cache.buffer_path); \ fl_string_dynamic_delete(&cache.name_action); \ fl_string_dynamic_delete(&cache.name_file); \ diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 198211f..6ba50be 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -218,6 +218,90 @@ extern "C" { } #endif // _di_controller_file_pid_delete_ +#ifndef _di_controller_get_id_user_ + f_return_status controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) { + f_number_unsigned_t number = 0; + + // @todo fix argument ordering in fl_conversion_string_to_number_unsigned(). + f_status_t status = fl_conversion_string_to_number_unsigned(buffer.string, &number, range); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_number) { + cache->buffer_other.used = 0; + + status = fl_string_dynamic_partial_append_nulless(buffer, range, &cache->buffer_other); + + if (F_status_is_error(status)) { + return F_status_set_error(status); + } + + status = f_account_id_user_by_name(cache->buffer_other.string, id); + + if (F_status_is_error(status)) { + return F_status_set_error(status); + } + else if (status == F_exist_not) { + return F_status_set_error(F_exist_not); + } + + return F_none; + } + + return F_status_set_error(status); + } + else if (number > f_type_size_32_unsigned) { + return F_status_set_error(F_number_too_large); + } + + *id = (uid_t) number; + return status; + } +#endif // _di_controller_get_id_user_ + +#ifndef _di_controller_get_id_group_ + f_return_status controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, gid_t *id) { + f_number_unsigned_t number = 0; + + // @todo fix argument ordering in fl_conversion_string_to_number_unsigned(). + f_status_t status = fl_conversion_string_to_number_unsigned(buffer.string, &number, range); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_number) { + cache->buffer_other.used = 0; + + status = fl_string_dynamic_partial_append_nulless(buffer, range, &cache->buffer_other); + + if (F_status_is_error(status)) { + return F_status_set_error(status); + } + + status = f_account_id_group_by_name(cache->buffer_other.string, id); + + if (F_status_is_error(status)) { + return F_status_set_error(status); + } + else if (status == F_exist_not) { + return F_status_set_error(F_exist_not); + } + + return F_none; + } + + return F_status_set_error(status); + } + else if (number > f_type_size_32_unsigned) { + return F_status_set_error(F_number_too_large); + } + + *id = (gid_t) number; + return status; + } +#endif // _di_controller_get_id_group_ + #ifndef _di_controller_perform_ready_ f_return_status controller_perform_ready(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) { f_status_t status = F_none; diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index d9c0d78..70f4402 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -159,6 +159,60 @@ extern "C" { #endif // _di_controller_file_pid_delete_ /** + * Convert the string from a string representation of an ID or a user name into the numeric representation of that ID or user name. + * + * @param buffer + * A string containing user name or ID. + * @param range + * The range within the buffer specifically containing the name or ID. + * @param cache + * The cache. + * @param id + * The determined user ID. + * + * @return + * F_none on success. + * F_exist_not (with error bit) if failed to match the name to an ID. + * F_number_too_large (with error bit) if the given ID is too large. + * + * Errors (with error bit) from: f_account_id_user_by_name(). + * Errors (with error bit) from: fl_conversion_string_to_number_unsigned(). + * + * @see f_account_id_user_by_name() + * @see fl_conversion_string_to_number_unsigned() + */ +#ifndef _di_controller_get_id_user_ + f_return_status controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) f_gcc_attribute_visibility_internal; +#endif // _di_controller_get_id_user_ + +/** + * Convert the string from a string representation of an ID or a group name into the numeric representation of that ID or group name. + * + * @param buffer + * A string containing group name or ID. + * @param range + * The range within the buffer specifically containing the name or ID. + * @param cache + * The cache. + * @param id + * The determined group ID. + * + * @return + * F_none on success. + * F_exist_not (with error bit) if failed to match the name to an ID. + * F_number_too_large (with error bit) if the given ID is too large. + * + * Errors (with error bit) from: f_account_id_group_by_name(). + * Errors (with error bit) from: fl_conversion_string_to_number_unsigned(). + * + * @see f_account_id_group_by_name() + * @see fl_conversion_string_to_number_unsigned() + */ +#ifndef _di_controller_get_id_group_ + f_return_status controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, gid_t *id) f_gcc_attribute_visibility_internal; +#endif // _di_controller_get_id_group_ + +/** * Perform all activities requiring the state to be "ready". * * This prints messages on errors. diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 23ac512..83198ca 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -458,6 +458,35 @@ extern "C" { const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize; fl_execute_parameter_t parameter = fl_macro_execute_parameter_t_initialize(0, &environment, &signals, 0); + fl_execute_as_t as = fl_execute_as_t_initialize; + + if (rule->has & controller_rule_has_nice) { + as.nice = &rule->nice; + } + + if (rule->has & controller_rule_has_user) { + as.id_user = &rule->user; + } + + if (rule->has & controller_rule_has_group) { + as.id_group = &rule->group; + + if (rule->groups.used) { + as.id_groups = &rule->groups; + } + } + + if (rule->capability) { + as.capability = rule->capability; + } + + if (rule->scheduler.used) { + // @todo: as.scheduler = + } + + if (rule->control.used) { + // @todo: as.controls = + } status = fll_environment_load_names(rule->environment, &environment); @@ -487,7 +516,11 @@ extern "C" { parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_foreground(item->type, *action, 0, action->parameters, 0, ¶meter, data); + status = controller_rule_execute_foreground(item->type, *action, 0, action->parameters, 0, ¶meter, &as, data); + + if (status == F_child) { + break; + } if (F_status_is_error(status)) { action->status = F_status_set_error(F_failure); @@ -503,7 +536,11 @@ extern "C" { parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_foreground(item->type, *action, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, ¶meter, data); + status = controller_rule_execute_foreground(item->type, *action, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, ¶meter, &as, data); + + if (status == F_child) { + break; + } if (F_status_is_error(status)) { action->status = F_status_set_error(F_failure); @@ -518,7 +555,7 @@ extern "C" { parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_pid_with(item->type, *action, 0, action->parameters, 0, ¶meter, data); + status = controller_rule_execute_pid_with(item->type, *action, 0, action->parameters, 0, ¶meter, &as, data); if (F_status_is_error(status)) { action->status = F_status_set_error(F_failure); @@ -553,6 +590,10 @@ extern "C" { fl_string_maps_delete(&environment); + if (status == F_child) { + return status; + } + if (F_status_is_error(status) || success == F_false) { rule->status = F_status_set_error(F_failure); } @@ -568,7 +609,7 @@ extern "C" { #endif // _di_controller_rule_execute_ #ifndef _di_controller_rule_execute_pid_with_ - f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) { + f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) { int result = 0; // @todo check to see if pid file exists. @@ -577,7 +618,18 @@ extern "C" { // in which case fll_execute_program() is called. // otherwise this needs to call an asynchronous execute process. // until then, this controller_rule_execute_pid_with() function is not correct and only represents a process that forks to the background. - f_status_t status = fll_execute_program(program, arguments, parameter, 0, &result); + f_status_t status = fll_execute_program(program, arguments, parameter, as, &result); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_child || status == F_capability || status == F_group || status == F_nice || status == F_schedule || status == F_user) { + status = F_child; + } + else { + status = F_status_set_error(status); + } + } if (status == F_child) { data->child = result; @@ -591,7 +643,7 @@ extern "C" { if (F_status_is_error(status)) { if (F_status_set_fine(status) == F_failure) { - controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program, result); + controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result); } else if (F_status_set_fine(status) == F_file_found_not) { controller_rule_error_print_execute_not_found(data->error, F_false, program); @@ -614,10 +666,21 @@ extern "C" { #endif // _di_controller_rule_execute_pid_with_ #ifndef _di_controller_rule_execute_foreground_ - f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) { + f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) { int result = 0; - f_status_t status = fll_execute_program(program, arguments, parameter, 0, &result); + f_status_t status = fll_execute_program(program, arguments, parameter, as, &result); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_child || status == F_capability || status == F_group || status == F_nice || status == F_schedule || status == F_user) { + status = F_child; + } + else { + status = F_status_set_error(status); + } + } if (status == F_child) { data->child = result; @@ -631,7 +694,7 @@ extern "C" { if (F_status_is_error(status)) { if (F_status_set_fine(status) == F_failure) { - controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program, result); + controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result); } else if (F_status_set_fine(status) == F_file_found_not) { controller_rule_error_print_execute_not_found(data->error, F_false, program); @@ -1078,7 +1141,7 @@ extern "C" { controller_rule_t *rule = &setting->rules.array[index]; if ((options & controller_rule_option_simulate) && data->parameters[controller_parameter_validate].result == f_console_result_found) { - controller_rule_simulate(*data, *cache, index, controller_rule_action_type_start, options, setting); + controller_rule_simulate(*data, index, controller_rule_action_type_start, options, cache, setting); } { @@ -1285,20 +1348,42 @@ extern "C" { bool for_item = F_true; rule->status = F_known_not; + rule->process = 0; + + // @todo: timeouts may be passed from entry, consider to or not to initialize in a more consistent manner. + //rule->timeout_kill = 2; + //rule->timeout_start = 2; + //rule->timeout_stop = 2; + + rule->has = 0; + rule->group = 0; + rule->user = 0; + rule->nice = 0; f_macro_time_spec_t_clear(rule->timestamp); rule->id.used = 0; rule->name.used = 0; + rule->control.used = 0; + rule->path.used = 0; + rule->scheduler.used = 0; + rule->script.used = 0; rule->define.used = 0; rule->parameter.used = 0; + if (rule->capability) { + f_capability_delete(&rule->capability); + } + + rule->capability = 0; rule->environment.used = 0; rule->need.used = 0; rule->want.used = 0; rule->wish.used = 0; + rule->groups.used = 0; + rule->items.used = 0; cache->line_item = 0; @@ -1465,7 +1550,7 @@ extern "C" { else { for_item = F_false; - status = controller_rule_setting_read(data, cache, rule); + status = controller_rule_setting_read(data, setting, cache, rule); if (F_status_is_error(status)) { if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) { @@ -1490,7 +1575,7 @@ extern "C" { #endif // _di_controller_rule_read_ #ifndef _di_controller_rule_setting_read_ - f_return_status controller_rule_setting_read(const controller_data_t data, controller_cache_t *cache, controller_rule_t *rule) { + f_return_status controller_rule_setting_read(const controller_data_t data, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) { f_status_t status = F_none; f_status_t status_return = F_none; @@ -1545,8 +1630,11 @@ extern "C" { continue; } - if (fl_string_dynamic_compare_string(controller_string_control_group, cache->name_item, controller_string_control_group_length) == F_equal_to) { - type = controller_rule_setting_type_control_group; + if (fl_string_dynamic_compare_string(controller_string_capability, cache->name_item, controller_string_capability_length) == F_equal_to) { + type = controller_rule_setting_type_capability; + } + else if (fl_string_dynamic_compare_string(controller_string_control, cache->name_item, controller_string_control_length) == F_equal_to) { + type = controller_rule_setting_type_control; } else if (fl_string_dynamic_compare_string(controller_string_define, cache->name_item, controller_string_define_length) == F_equal_to) { type = controller_rule_setting_type_define; @@ -1554,21 +1642,33 @@ extern "C" { else if (fl_string_dynamic_compare_string(controller_string_environment, cache->name_item, controller_string_environment_length) == F_equal_to) { type = controller_rule_setting_type_environment; } + else if (fl_string_dynamic_compare_string(controller_string_group, cache->name_item, controller_string_group_length) == F_equal_to) { + type = controller_rule_setting_type_group; + } else if (fl_string_dynamic_compare_string(controller_string_name, cache->name_item, controller_string_name_length) == F_equal_to) { type = controller_rule_setting_type_name; } else if (fl_string_dynamic_compare_string(controller_string_need, cache->name_item, controller_string_need_length) == F_equal_to) { type = controller_rule_setting_type_need; } + else if (fl_string_dynamic_compare_string(controller_string_nice, cache->name_item, controller_string_nice_length) == F_equal_to) { + type = controller_rule_setting_type_nice; + } else if (fl_string_dynamic_compare_string(controller_string_parameter, cache->name_item, controller_string_parameter_length) == F_equal_to) { type = controller_rule_setting_type_parameter; } else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) { type = controller_rule_setting_type_path; } + else if (fl_string_dynamic_compare_string(controller_string_scheduler, cache->name_item, controller_string_scheduler_length) == F_equal_to) { + type = controller_rule_setting_type_scheduler; + } else if (fl_string_dynamic_compare_string(controller_string_script, cache->name_item, controller_string_script_length) == F_equal_to) { type = controller_rule_setting_type_script; } + else if (fl_string_dynamic_compare_string(controller_string_user, cache->name_item, controller_string_user_length) == F_equal_to) { + type = controller_rule_setting_type_user; + } else if (fl_string_dynamic_compare_string(controller_string_want, cache->name_item, controller_string_want_length) == F_equal_to) { type = controller_rule_setting_type_want; } @@ -1637,10 +1737,13 @@ extern "C" { if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) { if (cache->content_actions.array[i].used != 2) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_false); + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } if (F_status_is_error_not(status_return)) { status_return = F_status_set_error(F_valid_not); @@ -1723,9 +1826,9 @@ extern "C" { continue; } - if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) { - if (type == controller_rule_setting_type_control_group) { - setting_value = &rule->control_group; + if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_scheduler || type == controller_rule_setting_type_script) { + if (type == controller_rule_setting_type_control) { + setting_value = &rule->control; } else if (type == controller_rule_setting_type_name) { setting_value = &rule->name; @@ -1733,15 +1836,21 @@ extern "C" { else if (type == controller_rule_setting_type_path) { setting_value = &rule->path; } + else if (type == controller_rule_setting_type_scheduler) { + setting_value = &rule->scheduler; + } else if (type == controller_rule_setting_type_script) { setting_value = &rule->script; } if (setting_value->used || cache->content_actions.array[i].used != 1) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_false); + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } if (F_status_is_error_not(status_return)) { status_return = F_status_set_error(F_valid_not); @@ -1750,9 +1859,7 @@ extern "C" { continue; } - setting_value->used = 0; - - if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) { + if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) { status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value); @@ -1771,37 +1878,47 @@ extern "C" { continue; } - status = controller_validate_has_graph(*setting_value); + if (type == controller_rule_setting_type_control) { + // @todo validate that this is a valid path. + // @todo append setting.path_control, then path_separator, and then this string. + // @todo the control path doesn't have to exist just yet, but print a warning if it doesn't and debug is visible. + } + else if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) { + status = controller_validate_has_graph(*setting_value); + + if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) { + if (status == F_false) { - if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) { - if (status == F_false) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); - fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); - f_print_dynamic(data.error.to.stream, *setting_value); - fprintf(data.error.to.stream, "%s", data.error.notable.after->string); - fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic(data.error.to.stream, *setting_value); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, *cache, F_false); + } - if (F_status_is_error_not(status_return)) { - status_return = F_status_set_error(F_valid_not); + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } } - } - else { + else { - // this function should only return F_complete_not_utf on error. - fll_error_print(data.error, F_complete_not_utf, "controller_validate_has_graph", F_true); + // this function should only return F_complete_not_utf on error. + fll_error_print(data.error, F_complete_not_utf, "controller_validate_has_graph", F_true); - if (F_status_is_error_not(status_return)) { - status_return = status; + if (F_status_is_error_not(status_return)) { + status_return = status; + } } - } - setting_value->used = 0; + setting_value->used = 0; - controller_rule_error_print(data.error, *cache, F_false); - continue; + controller_rule_error_print(data.error, *cache, F_false); + continue; + } } } else if (type == controller_rule_setting_type_path) { @@ -1833,6 +1950,281 @@ extern "C" { continue; } } + else if (type == controller_rule_setting_type_scheduler) { + // @todo + } + + continue; + } + + if (type == controller_rule_setting_type_capability || type == controller_rule_setting_type_nice || type == controller_rule_setting_type_user) { + + if (cache->content_actions.array[i].used != 1 || type == controller_rule_setting_type_capability && rule->capability || type == controller_rule_setting_type_group && (rule->has & controller_rule_has_group) || type == controller_rule_setting_type_nice && (rule->has & controller_rule_has_nice) || type == controller_rule_setting_type_user && (rule->has & controller_rule_has_user)) { + + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } + + continue; + } + + if (type == controller_rule_setting_type_capability) { + cache->buffer_other.used = 0; + + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->buffer_other); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); + + controller_rule_error_print(data.error, *cache, F_false); + + if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) { + return status; + } + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } + } + + status = fl_string_dynamic_terminate_after(&cache->buffer_other); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + + controller_rule_error_print(data.error, *cache, F_false); + + if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) { + return status; + } + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } + } + + status = f_capability_from_text(cache->buffer_other.string, &rule->capability); + + if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) { + + if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) { + fll_error_print(data.error, F_status_set_fine(status), "f_capability_from_text", F_true); + controller_rule_error_print(data.error, *cache, F_false); + + return status; + } + + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting failed to process the capabilities.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } + + continue; + } + } + else if (type == controller_rule_setting_type_nice) { + f_number_signed_t number = 0; + + status = fl_conversion_string_to_number_signed(cache->buffer_item.string, &number, cache->content_actions.array[i].array[0]); + + if (F_status_is_error(status) || number < -20 || number > 19) { + status = F_status_set_fine(status); + + if (number < -20 || number > 19 || status == F_data_not || status == F_number || status == F_number_overflow) { + + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid number '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s', only the whole numbers inclusively between ", data.error.context.before->string); + fprintf(data.error.to.stream, "%s%s-20%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s and ", data.error.context.before->string); + fprintf(data.error.to.stream, "%s%s19%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s are allowed.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } + } + else { + fll_error_print(data.error, status, "fl_conversion_string_to_number_signed", F_true); + status = F_status_set_error(status); + } + } + else { + rule->nice = number; + rule->has |= controller_rule_has_nice; + } + } + else if (type == controller_rule_setting_type_user) { + uid_t number = 0; + + status = controller_get_id_user(cache->buffer_item, cache->content_actions.array[i].array[0], cache, &number); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_exist_not) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid user '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' because no user was found by that name.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + } + else if (status == F_number_too_large) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid user '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' because the given ID is too large.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + } + else if (status == F_number) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid user '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' because the given ID is not a valid supported number.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + } + else { + fll_error_print(data.error, status, "f_account_id_user_by_name", F_true); + } + + controller_rule_error_print(data.error, *cache, F_false); + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(status); + } + } + else { + rule->user = number; + rule->has |= controller_rule_has_user; + } + } + + continue; + } + + if (type == controller_rule_setting_type_group) { + if (!cache->content_actions.array[i].used) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting requires one or more Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_valid_not); + } + + continue; + } + + gid_t number = 0; + + rule->groups.used = 0; + + for (j = 0; j < cache->content_actions.array[i].used; ++j) { + + status = fl_type_int32s_increase(&rule->groups); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_type_int32s_increase", F_true); + + if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) { + return status; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + controller_rule_error_print(data.error, *cache, F_false); + continue; + } + + status = controller_get_id_group(cache->buffer_item, cache->content_actions.array[i].array[j], cache, &number); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_exist_not) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid group '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' because no group was found by that name.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + } + else if (status == F_number_too_large) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid group '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' because the given ID is too large.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + } + else if (status == F_number) { + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid group '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); + f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]); + fprintf(data.error.to.stream, "%s", data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' because the given ID is not a valid supported number.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + } + else { + fll_error_print(data.error, status, "f_account_id_group_by_name", F_true); + } + + controller_rule_error_print(data.error, *cache, F_false); + + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(status); + } + } + else { + if (rule->has & controller_rule_has_group) { + rule->groups.array[rule->groups.used++] = number; + } + else { + rule->group = number; + rule->has |= controller_rule_has_group; + } + } + } // for continue; } @@ -1893,12 +2285,15 @@ extern "C" { if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) { if (status == F_false) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sRule setting has an invalid environment variable name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); - fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, data.error.notable.after->string); - fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_false); + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sRule setting has an invalid environment variable name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(data.error, *cache, F_false); + } if (F_status_is_error_not(status_return)) { status_return = F_status_set_error(F_valid_not); @@ -2035,7 +2430,7 @@ extern "C" { #endif // _di_controller_rule_setting_read_ #ifndef _di_controller_rule_simulate_ - void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) { + void controller_rule_simulate(const controller_data_t data, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_cache_t *cache, controller_setting_t *setting) { switch (action) { case controller_rule_action_type_kill: @@ -2053,7 +2448,7 @@ extern "C" { fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_rule_action_type_name(action).string, data.error.notable.after->string); fprintf(data.error.to.stream, "%s' while attempting to simulate rule execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, cache, F_true); + controller_rule_error_print(data.error, *cache, F_true); } return; @@ -2098,7 +2493,41 @@ extern "C" { fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_name, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]); fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_how, data.context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous, f_string_eol_s[0]); fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_wait, data.context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]); + + if (f_capability_supported()) { + fprintf(data.output.stream, " %s%s%s ", data.context.set.important.before->string, controller_string_capability, data.context.set.important.after->string); + + if (rule->capability) { + cache->buffer_other.used = 0; + + if (F_status_is_error_not(f_capability_to_text(rule->capability, &cache->buffer_other))) { + fprintf(data.output.stream, "%s", cache->buffer_other.string); + } + } + + fprintf(data.output.stream, "%c", f_string_eol_s[0]); + } + else { + fprintf(data.output.stream, " %s%s%s ", data.context.set.important.before->string, controller_string_capability, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data.output.stream, "%s(unsupported)%s%c", data.context.set.warning.before->string, data.context.set.warning.after->string, f_string_eol_s[0]); + } + + fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_control, data.context.set.important.after->string, rule->control.used ? rule->control.string : f_string_empty_s, f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_path, data.context.set.important.after->string, rule->path.used ? rule->path.string : f_string_empty_s, f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_scheduler, data.context.set.important.after->string, rule->scheduler.used ? rule->scheduler.string : f_string_empty_s, f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_script, data.context.set.important.after->string, rule->script.used ? rule->script.string : f_string_empty_s, f_string_eol_s[0]); + + fprintf(data.output.stream, " %s%s%s", data.context.set.important.before->string, controller_string_nice, data.context.set.important.after->string); + if (rule->has & controller_rule_has_nice) { + fprintf(data.output.stream, " %i", rule->nice); + } + fprintf(data.output.stream, "%c", f_string_eol_s[0]); + + fprintf(data.output.stream, " %s%s%s", data.context.set.important.before->string, controller_string_user, data.context.set.important.after->string); + if (rule->has & controller_rule_has_user) { + fprintf(data.output.stream, " %i", rule->user); + } + fprintf(data.output.stream, "%c", f_string_eol_s[0]); fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_define, data.context.set.important.after->string, f_string_eol_s[0]); @@ -2113,27 +2542,26 @@ extern "C" { fprintf(data.output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_environment, data.context.set.important.after->string, f_string_eol_s[0]); - if (rule->parameter.used) { - for (i = 0; i < rule->parameter.used; ++i) { + if (rule->environment.used) { + for (i = 0; i < rule->environment.used; ++i) { - if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) { - fprintf(data.output.stream, " %s %s=%s %s%c", rule->parameter.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]); + if (rule->environment.array[i].used) { + fprintf(data.output.stream, " %s%c", rule->environment.array[i].string, f_string_eol_s[0]); } } // for } fprintf(data.output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_environment, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_group, data.context.set.important.after->string, f_string_eol_s[0]); - if (rule->environment.used) { - for (i = 0; i < rule->environment.used; ++i) { + if (rule->has & controller_rule_has_group) { + fprintf(data.output.stream, " %i%c", rule->group, f_string_eol_s[0]); - if (rule->environment.array[i].used) { - fprintf(data.output.stream, " %s%c", rule->environment.array[i].string, f_string_eol_s[0]); - } + for (i = 0; i < rule->groups.used; ++i) { + fprintf(data.output.stream, " %i%c", rule->groups.array[i], f_string_eol_s[0]); } // for } @@ -2152,6 +2580,19 @@ extern "C" { fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter, data.context.set.important.after->string, f_string_eol_s[0]); + + if (rule->parameter.used) { + for (i = 0; i < rule->parameter.used; ++i) { + + if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) { + fprintf(data.output.stream, " %s %s=%s %s%c", rule->parameter.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]); + } + } // for + } + + fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_want, data.context.set.important.after->string, f_string_eol_s[0]); if (rule->want.used) { diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 81e4f6f..3f67e1c 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -261,6 +261,8 @@ extern "C" { * @todo this is not yet implemented. * @param parameter * The execute parameter settings. + * @param as + * The execute as settings. * @param data * The program data. * @@ -275,7 +277,7 @@ extern "C" { * @see fll_execute_program() */ #ifndef _di_controller_rule_execute_pid_with_ - extern f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) f_gcc_attribute_visibility_internal; + extern f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_pid_with_ /** @@ -302,6 +304,8 @@ extern "C" { * @todo this is not yet implemented. * @param parameter * The execute parameter settings. + * @param as + * The execute as settings. * @param data * The program data. * @@ -315,7 +319,7 @@ extern "C" { * @see fll_execute_program() */ #ifndef _di_controller_rule_execute_foreground_ - extern f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) f_gcc_attribute_visibility_internal; + extern f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_foreground_ /** @@ -552,6 +556,8 @@ extern "C" { * * @param data * The program data. + * @param setting + * The controller settings data. * @param cache * A structure for containing and caching relevant data. * @param rule @@ -576,7 +582,7 @@ extern "C" { * @see fll_path_canonical() */ #ifndef _di_controller_rule_setting_read_ - extern f_return_status controller_rule_setting_read(const controller_data_t data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern f_return_status controller_rule_setting_read(const controller_data_t data, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_setting_read_ /** @@ -588,10 +594,10 @@ extern "C" { * * @param data * The program data. - * @param cache - * A structure for containing and caching relevant data. * @param index * The position in the setting.rules array representing the rule to simulate. + * @param cache + * A structure for containing and caching relevant data. * @param action * The action to perform based on the action type codes. * @@ -610,7 +616,7 @@ extern "C" { * The controller settings data. */ #ifndef _di_controller_rule_simulate_ - extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) f_gcc_attribute_visibility_internal; + extern void controller_rule_simulate(const controller_data_t data, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_cache_t *cache, controller_setting_t *setting) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_simulate_ /** diff --git a/level_3/controller/data/build/defines b/level_3/controller/data/build/defines index c665317..903c38c 100644 --- a/level_3/controller/data/build/defines +++ b/level_3/controller/data/build/defines @@ -1,2 +1,2 @@ # fss-0000 - +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). diff --git a/level_3/controller/data/build/dependencies b/level_3/controller/data/build/dependencies index 0adc37e..5af11e3 100644 --- a/level_3/controller/data/build/dependencies +++ b/level_3/controller/data/build/dependencies @@ -5,6 +5,8 @@ f_status f_memory f_string f_utf +f_account +f_capability f_color f_console f_conversion diff --git a/level_3/controller/data/build/settings b/level_3/controller/data/build/settings index 20a49be..5e3ed2b 100644 --- a/level_3/controller/data/build/settings +++ b/level_3/controller/data/build/settings @@ -18,8 +18,8 @@ modes_default monolithic build_compiler gcc build_indexer ar build_language c -build_libraries -lc -build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf +build_libraries -lc -lcap +build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_account -lf_capability -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll build_sources_library controller.c private-control.c private-controller.c private-entry.c private-rule.c @@ -46,6 +46,7 @@ search_exclusive yes search_shared yes search_static yes +#defines_all -D_di_libcap_ defines_all defines_static defines_shared diff --git a/level_3/controller/data/settings/example/rules/command/multiple.rule b/level_3/controller/data/settings/example/rules/command/multiple.rule index dfc6144..b2a2bcb 100644 --- a/level_3/controller/data/settings/example/rules/command/multiple.rule +++ b/level_3/controller/data/settings/example/rules/command/multiple.rule @@ -1,7 +1,17 @@ # fss-000d setting: - name "Multiple Commands: whoami and date" + name "Multiple Commands: id, whoami, date, etc.." + capability "all=" + nice 15 + #user kevin + #group list 8 root + +command: + start { + id + sleep 20 + } command: start whoami diff --git a/level_3/controller/data/settings/rules/program/terminal.rule b/level_3/controller/data/settings/rules/program/terminal.rule index 25339ad..c4d3b6e 100644 --- a/level_3/controller/data/settings/rules/program/terminal.rule +++ b/level_3/controller/data/settings/rules/program/terminal.rule @@ -5,24 +5,24 @@ setting: name "System Terminal" + capability "all=" -service: +service: use /var/run/tty/tty1.pid start qingy tty1 -d -l -n -t - + service: use /var/run/tty/tty2.pid start qingy tty2 -d -l -n -t - + service: use /var/run/tty/tty3.pid start qingy tty3 -d -l -n -t - + service: use /var/run/tty/tty4.pid start qingy tty4 -d -l -n -t - diff --git a/level_3/controller/data/settings/rules/service/dbus.rule b/level_3/controller/data/settings/rules/service/dbus.rule index 5a551ab..ed434be 100644 --- a/level_3/controller/data/settings/rules/service/dbus.rule +++ b/level_3/controller/data/settings/rules/service/dbus.rule @@ -5,6 +5,8 @@ setting: name "D-BUS" + capability "all=" + nice 15 service: use /var/run/dbus/dbus.pid diff --git a/level_3/controller/data/settings/rules/service/logger.rule b/level_3/controller/data/settings/rules/service/logger.rule index 91c92de..4c65092 100644 --- a/level_3/controller/data/settings/rules/service/logger.rule +++ b/level_3/controller/data/settings/rules/service/logger.rule @@ -5,6 +5,8 @@ setting: name "System Logger" + capability "all=" + nice 19 service: # @todo consider adding support for IKI to make "/var/run/logger/logger.pid" a variable. diff --git a/level_3/controller/data/settings/rules/service/mouse.rule b/level_3/controller/data/settings/rules/service/mouse.rule index 7e759f1..f2e0061 100644 --- a/level_3/controller/data/settings/rules/service/mouse.rule +++ b/level_3/controller/data/settings/rules/service/mouse.rule @@ -5,6 +5,8 @@ setting: name "Console Mouse" + capability "all=" + nice 15 # @todo consider adding iki support. diff --git a/level_3/controller/data/settings/rules/task/clock.rule b/level_3/controller/data/settings/rules/task/clock.rule index a7014c6..f0c789d 100644 --- a/level_3/controller/data/settings/rules/task/clock.rule +++ b/level_3/controller/data/settings/rules/task/clock.rule @@ -5,6 +5,8 @@ setting: name "Setup Clock" + capability "all=" + nice 15 script: start { @@ -13,7 +15,7 @@ script: if [[ -f /etc/clock ]] ; then clock_mode=$(fss_basic_read -c 0 -n mode /etc/clock); fi - + if [[ $clock_mode == "local" ]] ; then hwclock --hctosys; elif [[ $clock_mode == "ntpdate" ]] ; then diff --git a/level_3/controller/data/settings/rules/task/keyboard.rule b/level_3/controller/data/settings/rules/task/keyboard.rule index 862f4c9..07edc8a 100644 --- a/level_3/controller/data/settings/rules/task/keyboard.rule +++ b/level_3/controller/data/settings/rules/task/keyboard.rule @@ -5,3 +5,5 @@ setting: name "System Keyboard" + capability "all=" + nice 15 diff --git a/level_3/controller/documents/rule.txt b/level_3/controller/documents/rule.txt index 4836c2f..9a1aa02 100644 --- a/level_3/controller/documents/rule.txt +++ b/level_3/controller/documents/rule.txt @@ -9,17 +9,29 @@ Rule Documentation: Multiple outer most list Objects may be specified and they are executed as provided, in a top-down manner. The "settings" Rule Type has the following FSS-0001 (Extended) Content\: - "control_group": Define a control group (cgroup) in which everything within this rule executes under. + "capability": Define a set of capabilities in which to use, using the capability "text" format (such as "= cap_chown+ep"). + "control": Define a control group (cgroup) in which everything within this rule executes under. "define": Define a custom environment variable with a given variable, and automatically expose it to processes executed within this rule. "environment": A set of environment variables to expose to the processes executed within this rule (PATH is always exposed). + "group": A set of group names or IDs to execute as with the first group being the primary group and all remaining being supplementary groups. "name": A name used to represent this rule, which is printed to the user, screen, logs, etc... "need": A single rule required to be executed (must exist and must succeed) before this rule starts. + "nice": A single niceness value to run all processes executed within this rule as (-20 gets to be greediest in CPU usage and 19 being the nicest in CPU usage). "parameter": A statically defined IKI name and its associated value for use in this rule file. "path": A single Content used to set a custom PATH environment variable value. "script": An executable name of a script, such as "bash", to use for the "script" Rule Type (which likely defaults to "bash" if not specified). + "scheduler": A valid name of a scheduler to use. + "user": A single user name or ID to execute as. "want": A single rule desired to be executed (may exist and must succeed) before this rule starts. "wish": A single rule desired to be executed (may exist and is not required to succeed) before this rule starts. + In the case of "capability", if the user the controller program is run as does not have the desired capabilities already, they cannot be added. + This essentially maintains or reduces the capabilities already available. + Due to capabilities only being a draft in the POSIX standard, one may expect "capabilities" support may not be available and in such a case this setting will do nothing. + If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project. + + In the case of "group" and "user", only users and groups that the user the controller program is being run as may be used. + In the case of "want" and "wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule. In the case of "path", when specified, the PATH environment variable is automatically added to the "environment" setting. @@ -55,10 +67,14 @@ Rule Documentation: When "reload", "start", or "stop" Content are not provided, then no respective action is performed. Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use. - The "group" inner Content, an associated "command", "service", or "script" are executed with that group ID or group name. - The "user" inner Content, an associated "command", "service", or "script" are executed with that user ID or user name. - The "group" and "user" can only be switched to if the user this controller program being operated under is allowed to switch to. - The "create" Content designates that this controller program to create the PID file after successfully starting the service. The "use" Content designates that the called program will provide the PID file after successfully starting the service. For both "create" and "program" the PID file is expected to only exist on success or failure and the existence thereof designates the success or failure rate. + + The following Content are the same as those specified in the Settings above except that they apply to a specific Rule Item instead of all Rule Items in the file\: + - "capability" + - "control" + - "group" + - "nice" + - "scheduler" + - "user" diff --git a/level_3/controller/specifications/rule.txt b/level_3/controller/specifications/rule.txt index 7de6cc0..a7ae7ae 100644 --- a/level_3/controller/specifications/rule.txt +++ b/level_3/controller/specifications/rule.txt @@ -28,38 +28,39 @@ Rule Specification: The other Rule Types are processed top-down. The "settings" Rule Type has the following FSS-0001 (Extended)\: - "control_group": One Content representing a valid control group (cgroup) name, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off). + "capability": One Content representing capabilities. + "control": One Content representing a valid control group (cgroup) name, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off). "define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits). "environment": Zero or more Content, each must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits). + "group": One or more Content representing group names or group ids. "name": One Content, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off). "need": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). + "nice": One Content, must be a valid number for process "niceness" (Any whole number inclusively between -20 to 19). "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value. "path": One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin"). + "scheduler": One Content representing a scheduler name. "script": One Content representing a valid program name or path (such as "bash" or "/bin/bash"). + "user": One Content representing a user name or user id. "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). "wish": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). The "service" Rule Type allows the following the FSS-0001 (Extended)\: "create": One Content representing the path to a PID file. - "group": One Content representing a group name or group id. "kill": One or more Content representing a program being executed and its arguments. "restart": One or more Content representing a program being executed and its arguments. "reload": One or more Content representing a program being executed and its arguments. "start": One or more Content representing a program being executed and its arguments. "stop": One or more Content representing a program being executed and its arguments. "use": One Content representing the path to a PID file. - "user": One Content representing a user name or user id. The "command" and "script" Rule Types allow the following the FSS-0001 (Extended)\: - "group": One Content representing a group name or group id. "kill": One or more Content representing a program being executed and its arguments. "restart": One or more Content representing a program being executed and its arguments. "reload": One or more Content representing a program being executed and its arguments. "start": One or more Content representing a program being executed and its arguments. "stop": One or more Content representing a program being executed and its arguments. - "user": One Content representing a user name or user id. - The "command", "script", and "service" Rule Types allow the following the FSS-0003 (Extended List)\: + The "command" and "service" Rule Types allow the following the FSS-0003 (Extended List)\: "kill": A list repesenting multiple programs and their respective arguments to execute. "restart": A list repesenting multiple programs and their respective arguments to execute. "reload": A list repesenting multiple programs and their respective arguments to execute. diff --git a/level_3/fake/c/private-build.c b/level_3/fake/c/private-build.c index cd0d643..036022b 100644 --- a/level_3/fake/c/private-build.c +++ b/level_3/fake/c/private-build.c @@ -25,6 +25,8 @@ extern "C" { memcpy(build_libraries + fake_build_parameter_library_link_path_length, data.path_build_libraries_static.string, data.path_build_libraries_static.used); } + build_libraries[build_libraries_length] = 0; + f_string_length_t build_includes_length = fake_build_parameter_library_include_length + data.path_build_includes.used; char build_includes[build_includes_length + 1]; @@ -1545,6 +1547,8 @@ extern "C" { *status = fll_fss_snatch_apart(buffer, objects, contents, settings_name, settings_length, fake_build_setting_total, settings_value, 0); if (*status == F_none) { + const int total_build_libraries = setting->build_libraries.used; + f_string_dynamic_t settings_mode_name_dynamic[fake_build_setting_total]; f_string_t settings_mode_names[fake_build_setting_total]; f_string_length_t setting_mode_lengths[fake_build_setting_total]; @@ -1623,6 +1627,29 @@ extern "C" { if (F_status_is_error(*status)) break; } // for + + // "build_libaries" is appended after all modes to help assist with static linker file issues (@todo there should likely be more options to have a postfix linker parameter that can be added here instead, such as "build_libraries_last"). + if (total_build_libraries) { + f_string_dynamic_t temporary[total_build_libraries]; + + for (i = 0; i < total_build_libraries; ++i) { + temporary[i].string = setting->build_libraries.array[i].string; + temporary[i].used = setting->build_libraries.array[i].used; + temporary[i].size = setting->build_libraries.array[i].size; + } // for + + for (i = 0, j = total_build_libraries; j < setting->build_libraries.used; ++i, ++j) { + setting->build_libraries.array[i].string = setting->build_libraries.array[j].string; + setting->build_libraries.array[i].used = setting->build_libraries.array[j].used; + setting->build_libraries.array[i].size = setting->build_libraries.array[j].size; + } // for + + for (i = setting->build_libraries.used - total_build_libraries, j = 0; j < total_build_libraries; ++i, ++j) { + setting->build_libraries.array[i].string = temporary[j].string; + setting->build_libraries.array[i].used = temporary[j].used; + setting->build_libraries.array[i].size = temporary[j].size; + } // for + } } if (F_status_is_error(*status)) { diff --git a/level_3/fake/data/build/defines b/level_3/fake/data/build/defines index 4f13080..903c38c 100644 --- a/level_3/fake/data/build/defines +++ b/level_3/fake/data/build/defines @@ -1 +1,2 @@ # fss-0000 +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). diff --git a/level_3/fake/data/build/dependencies b/level_3/fake/data/build/dependencies index 6719e57..015d579 100644 --- a/level_3/fake/data/build/dependencies +++ b/level_3/fake/data/build/dependencies @@ -6,6 +6,7 @@ f_memory f_string f_utf f_account +f_capability f_color f_console f_conversion diff --git a/level_3/fake/data/build/settings b/level_3/fake/data/build/settings index 9d9104c..4385448 100644 --- a/level_3/fake/data/build/settings +++ b/level_3/fake/data/build/settings @@ -18,8 +18,8 @@ modes_default monolithic build_compiler gcc build_indexer ar build_language c -build_libraries -lc -build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_utf -lf_account -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_print -lf_signal -lf_utf +build_libraries -lc -lcap +build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_utf -lf_account -lf_capability -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_print -lf_signal -lf_utf build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll build_sources_library fake.c private-fake.c private-clean.c private-build.c private-make.c private-print.c private-skeleton.c @@ -46,6 +46,7 @@ search_exclusive yes search_shared yes search_static yes +#defines_all -D_di_libcap_ defines_all defines_static defines_shared diff --git a/level_3/firewall/data/build/defines b/level_3/firewall/data/build/defines index 4f13080..903c38c 100644 --- a/level_3/firewall/data/build/defines +++ b/level_3/firewall/data/build/defines @@ -1 +1,2 @@ # fss-0000 +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). diff --git a/level_3/firewall/data/build/dependencies b/level_3/firewall/data/build/dependencies index f58c5d8..10b680a 100644 --- a/level_3/firewall/data/build/dependencies +++ b/level_3/firewall/data/build/dependencies @@ -5,6 +5,7 @@ f_status f_memory f_string f_utf +f_capability f_color f_console f_directory diff --git a/level_3/firewall/data/build/settings b/level_3/firewall/data/build/settings index 12603ca..185fb93 100644 --- a/level_3/firewall/data/build/settings +++ b/level_3/firewall/data/build/settings @@ -18,8 +18,8 @@ modes_default monolithic build_compiler gcc build_indexer ar build_language c -build_libraries -lc -build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_status -lfl_string -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf +build_libraries -lc -lcap +build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_status -lfl_string -lf_capability -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll build_sources_library firewall.c private-firewall.c @@ -46,7 +46,7 @@ search_exclusive yes search_shared yes search_static yes -defines_all -D_en_firewall_debug_ +defines_all defines_static defines_shared -- 1.8.3.1