From a5da7c835fff693f07ad31e4739b0110ca83a5f8 Mon Sep 17 00:00:00 2001 From: obarun <eric@obarun.org> Date: Mon, 1 Nov 2021 16:58:15 +1100 Subject: [PATCH] add @intree feature --- doc/frontend.md | 53 +++--- src/include/66/enum.h | 27 ++- src/lib66/parser_utils.c | 45 ++++- src/lib66/ss_get_enum.c | 25 +++ src/lib66/tree_seed.c | 400 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 511 insertions(+), 39 deletions(-) create mode 100644 src/lib66/tree_seed.c diff --git a/doc/frontend.md b/doc/frontend.md index 0a8b77cd..b952644c 100644 --- a/doc/frontend.md +++ b/doc/frontend.md @@ -275,36 +275,6 @@ This section is *mandatory*. (!) --- -- @name - - *Corresponds to the name of the service directory of [s6](https://skarnet.org/software/s6) and [s6-rc](https://skarnet.org/software/s6-rc) programs*. - - Name of the service. - - mandatory : no - - syntax : inline - - valid values : - - * This field has no effect except for instantiated services. In such case the name must contain the complete name of the frontend service file. - - For example, the following is valid: - - ```` - @name = tty@mine-@I - ```` - - where: - - ```` - @name = mine-@I - ```` - - is not for a frontend service file named tty@. - - --- - - @version *Without equivalent, this key is unique to 66 tools*. @@ -657,6 +627,24 @@ This section is *mandatory*. (!) **Note** : 66 version must be higher than 0.3.0.1. +- @intree + + *Without equivalent, this key is unique to 66 tools*. + + mandatory : no + + syntax : inline + + valid values : + + * Any valid seed file name. + + The service will automatically be activated at the tree name set in the *@intree* key value. + + **Note** : The corresponding seed file *must* exist on your system to be effective. + + --- + --- ## Section: [start] @@ -1082,7 +1070,9 @@ This prototype contain all valid section with all valid `key=value` pair. ``` [main] - + @type = classic,longrun,bundle,module + @description = "" + @version = 0.0.0 @depends = () @optsdepends = () @extdepends = () @@ -1098,6 +1088,7 @@ This prototype contain all valid section with all valid `key=value` pair. @maxdeath = @down-signal = @hiercopy = () + @intree = [start] @build = auto,custom diff --git a/src/include/66/enum.h b/src/include/66/enum.h index dae8ea7c..3bcabd4d 100644 --- a/src/include/66/enum.h +++ b/src/include/66/enum.h @@ -35,6 +35,7 @@ enum enum_main_e ENUM_MANDATORY , ENUM_TIME , ENUM_LOGOPTS , + ENUM_SEED , ENUM_ENDOFKEY } ; @@ -73,6 +74,7 @@ enum enum_key_section_main_e KEY_MAIN_HIERCOPY , KEY_MAIN_SIGNAL , KEY_MAIN_FLAGS , + KEY_MAIN_INTREE , KEY_MAIN_ENDOFKEY } ; @@ -242,6 +244,22 @@ enum enum_logopts_e extern char const *enum_str_logopts[] ; +typedef enum enum_seed_e enum_seed_t, *enum_seed_t_ref ; +enum enum_seed_e +{ + + SEED_DEPENDS = 0 , + SEED_REQUIREDBY , + SEED_ENABLE , + SEED_ALLOW , + SEED_DENY , + SEED_CURRENT , + SEED_GROUP , + SEED_SERVICES , + SEED_ENDOFKEY + +} ; + typedef struct enum_all_enum_s enum_all_enum_t, *enum_all_enum_t_ref ; struct enum_all_enum_s @@ -250,6 +268,8 @@ struct enum_all_enum_s char const **str ; } ; + + extern ssize_t get_enum_by_key_one(char const *str, int const e) ; extern ssize_t get_enum_by_key(char const *str) ; extern char const *get_key_by_enum(int const e, int const key) ; @@ -291,12 +311,11 @@ static key_description_t const main_section_list[] = { .name = &enum_str_key_section_main[KEY_MAIN_TYPE], .id = KEY_MAIN_TYPE, .expected = EXPECT_LINE }, { .name = &enum_str_key_section_main[KEY_MAIN_VERSION], .id = KEY_MAIN_VERSION, .expected = EXPECT_LINE }, { .name = &enum_str_key_section_main[KEY_MAIN_DESCRIPTION], .id = KEY_MAIN_DESCRIPTION, .expected = EXPECT_QUOTE }, + { .name = &enum_str_key_section_main[KEY_MAIN_CONTENTS], .id = KEY_MAIN_CONTENTS, .expected = EXPECT_BRACKET }, { .name = &enum_str_key_section_main[KEY_MAIN_DEPENDS], .id = KEY_MAIN_DEPENDS, .expected = EXPECT_BRACKET }, { .name = &enum_str_key_section_main[KEY_MAIN_OPTSDEPS], .id = KEY_MAIN_OPTSDEPS, .expected = EXPECT_BRACKET }, { .name = &enum_str_key_section_main[KEY_MAIN_EXTDEPS], .id = KEY_MAIN_EXTDEPS, .expected = EXPECT_BRACKET }, - { .name = &enum_str_key_section_main[KEY_MAIN_CONTENTS], .id = KEY_MAIN_CONTENTS, .expected = EXPECT_BRACKET }, { .name = &enum_str_key_section_main[KEY_MAIN_OPTIONS], .id = KEY_MAIN_OPTIONS, .expected = EXPECT_BRACKET }, - { .name = &enum_str_key_section_main[KEY_MAIN_FLAGS], .id = KEY_MAIN_FLAGS, .expected = EXPECT_BRACKET }, { .name = &enum_str_key_section_main[KEY_MAIN_NOTIFY], .id = KEY_MAIN_NOTIFY, .expected = EXPECT_UINT }, { .name = &enum_str_key_section_main[KEY_MAIN_USER], .id = KEY_MAIN_USER, .expected = EXPECT_BRACKET }, { .name = &enum_str_key_section_main[KEY_MAIN_T_FINISH], .id = KEY_MAIN_T_FINISH, .expected = EXPECT_UINT }, @@ -304,8 +323,10 @@ static key_description_t const main_section_list[] = { .name = &enum_str_key_section_main[KEY_MAIN_T_UP], .id = KEY_MAIN_T_UP, .expected = EXPECT_UINT }, { .name = &enum_str_key_section_main[KEY_MAIN_T_DOWN], .id = KEY_MAIN_T_DOWN, .expected = EXPECT_UINT }, { .name = &enum_str_key_section_main[KEY_MAIN_DEATH], .id = KEY_MAIN_DEATH, .expected = EXPECT_UINT }, - { .name = &enum_str_key_section_main[KEY_MAIN_SIGNAL], .id = KEY_MAIN_SIGNAL, .expected = EXPECT_UINT }, { .name = &enum_str_key_section_main[KEY_MAIN_HIERCOPY], .id = KEY_MAIN_HIERCOPY, .expected = EXPECT_BRACKET }, + { .name = &enum_str_key_section_main[KEY_MAIN_SIGNAL], .id = KEY_MAIN_SIGNAL, .expected = EXPECT_UINT }, + { .name = &enum_str_key_section_main[KEY_MAIN_FLAGS], .id = KEY_MAIN_FLAGS, .expected = EXPECT_BRACKET }, + { .name = &enum_str_key_section_main[KEY_MAIN_INTREE], .id = KEY_MAIN_INTREE, .expected = EXPECT_LINE }, { .name = &enum_str_key_section_main[KEY_MAIN_ENDOFKEY] } } ; diff --git a/src/lib66/parser_utils.c b/src/lib66/parser_utils.c index b988bced..6d6377e9 100644 --- a/src/lib66/parser_utils.c +++ b/src/lib66/parser_utils.c @@ -496,7 +496,6 @@ int nocheck_toservice(keynocheck *nocheck,int svtype, sv_alltype *service) return 1 ; } - /********************************** * store * *******************************/ @@ -615,9 +614,12 @@ int keep_common(sv_alltype *service,keynocheck *nocheck,int svtype) if (p == -1 && owner) { int e = 0 ; - for (int i = 1; i < nb+1; i++) - if (service->user[i] == owner) e = 1 ; - + for (int i = 1; i < nb+1; i++) { + if (service->user[i] == owner) { + e = 1 ; + break ; + } + } if (!e) log_warnu_return(LOG_EXIT_ZERO,"use the service -- permission denied") ; } @@ -725,6 +727,11 @@ int keep_common(sv_alltype *service,keynocheck *nocheck,int svtype) return 0 ; } break ; + case KEY_MAIN_INTREE: + service->cname.intree = keep.len ; + if (!stralloc_catb(&keep,chval,*chlen + 1)) + log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; + break ; default: log_warn_return(LOG_EXIT_ZERO,"unknown key: ",get_key_by_enum(ENUM_KEY_SECTION_MAIN,nocheck->idkey)) ; } @@ -1231,7 +1238,6 @@ int check_valid_runas(keynocheck *ch) return 1 ; } - void parse_err(int ierr,keynocheck *check) { log_flow() ; @@ -1327,3 +1333,32 @@ int get_svtype_from_file(char const *file) stralloc_free(&tmp) ; return svtype ; } + +int get_svintree(sv_alltype *sv_before, char const *contents) +{ + log_flow() ; + + int r ; + stralloc sa = STRALLOC_ZERO ; + + if (!auto_stra(&sa,contents)) goto err ; + + /** @intree may not exist */ + r = sastr_find(&sa,get_key_by_enum(ENUM_KEY_SECTION_MAIN,KEY_MAIN_INTREE)) ; + if (r == -1) { sv_before->cname.intree == -1 ; goto freed ; } + + if (!environ_get_val_of_key(&sa,get_key_by_enum(ENUM_KEY_SECTION_MAIN,KEY_MAIN_INTREE))) goto err ; + + if (!sastr_clean_element(&sa)) goto err ; + + sv_before->cname.intree = keep.len ; + if (!sastr_add_string(&keep, sa.s)) + goto err ; + + freed: + stralloc_free(&sa) ; + return 1 ; + err: + stralloc_free(&sa) ; + return 0 ; +} diff --git a/src/lib66/ss_get_enum.c b/src/lib66/ss_get_enum.c index 3434108a..67e7275e 100644 --- a/src/lib66/ss_get_enum.c +++ b/src/lib66/ss_get_enum.c @@ -49,6 +49,7 @@ char const *enum_str_key_section_main[] = { "@hiercopy" , "@down-signal" , "@flags" , + "@intree" , 0 } ; @@ -145,11 +146,34 @@ char const *enum_str_time[] = { char const *enum_str_logopts[] = { "producer-for" , + "consumer-for" , "pipeline-name" , 0 } ; +char const *enum_str_seed[] = { + + "depends" , + "requiredby" , + "enable" , + "allow" , + "deny" , + "current" , + "group" , + "services" , + /** + * + * + * rajouter owner qui correspond detenteur de la commande lancer + * cela permet de faire la difference entre allow et deny list + * et le vrai propriétaire de l'arbre + * + * + * */ + 0 +} ; + enum_all_enum_t enum_all[] = { [ENUM_SECTION] = { .enum_all = SECTION_ENDOFKEY - ENUM_START, .str = enum_str_section } , @@ -166,6 +190,7 @@ enum_all_enum_t enum_all[] = { [ENUM_MANDATORY] = { .enum_all = MANDATORY_ENDOFKEY - ENUM_START , .str = enum_str_mandatory } , [ENUM_TIME] = { .enum_all = TIME_ENDOFKEY - ENUM_START , .str = enum_str_time } , [ENUM_LOGOPTS] = { .enum_all = LOGOPTS_ENDOFKEY - ENUM_START , .str = enum_str_logopts } , + [ENUM_SEED] = { .enum_all = SEED_ENDOFKEY - ENUM_START , .str = enum_str_seed } , [ENUM_ENDOFKEY] = { 0 } } ; diff --git a/src/lib66/tree_seed.c b/src/lib66/tree_seed.c new file mode 100644 index 00000000..2c8c49bd --- /dev/null +++ b/src/lib66/tree_seed.c @@ -0,0 +1,400 @@ +/* + * tree_seed.c + * + * Copyright (c) 2018-2021 Eric Vidal <eric@obarun.org> + * + * All rights reserved. + * + * This file is part of Obarun. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution. + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file./ + */ + + +#include <66/tree.h> + +#include <sys/types.h> +#include <string.h> +#include <unistd.h>//getuid + +#include <oblibs/string.h> +#include <oblibs/files.h> +#include <oblibs/log.h> +#include <oblibs/environ.h> +#include <oblibs/sastr.h> +#include <oblibs/types.h> + +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> + +#include <66/enum.h> +#include <66/utils.h> +#include <66/config.h> + +stralloc saseed = STRALLOC_ZERO ; + +void tree_seed_free(void) +{ + + stralloc_free(&saseed) ; + +} + +static ssize_t tree_seed_get_key(char *table,char const *str) +{ + ssize_t pos = -1 ; + + pos = get_len_until(str,'=') ; + + if (pos == -1) + return -1 ; + + auto_strings(table,str) ; + + table[pos] = 0 ; + + pos++ ; // remove '=' + + return pos ; +} + +int tree_seed_parse_file(ss_tree_seed_t *seed, char const *seedpath) +{ + log_flow() ; + + int r ; + + stralloc sa = STRALLOC_ZERO ; + size_t pos = 0 ; + + size_t filesize=file_get_size(seedpath) ; + if (!filesize) { + + log_warn(seedpath," is empty") ; + goto err ; + } + + r = openreadfileclose(seedpath, &sa, filesize) ; + if(!r) { + + log_warnusys("open ", seedpath) ; + goto err ; + } + + /** ensure that we have an empty line at the end of the string*/ + if (!auto_stra(&sa,"\n")) + log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; + + if (!environ_get_clean_env(&sa)) { + + log_warnu("clean seed file: ", seedpath) ; + goto err ; + } + + if (!sastr_split_string_in_nline(&sa)) + goto err ; + + FOREACH_SASTR(&sa, pos) { + + + char *line = sa.s + pos, *key = 0, *val = 0 ; + size_t len = strlen(line) ; + + char tmp[len + 1] ; + + r = tree_seed_get_key(tmp, line) ; + + /** should never happens */ + if (r == -1) { + log_warn("invalid format of key: ",line," -- please make a bug report") ; + goto err ; + } + + key = tmp ; + val = line + r ; + + ssize_t e = get_enum_by_key(key) ; + + switch (e) { + + case SEED_DEPENDS : + + seed->depends = saseed.len ; + if (!sastr_add_string(&saseed, val)) + goto err ; + + seed->nopts++ ; + + break ; + + case SEED_REQUIREDBY : + + seed->requiredby = saseed.len ; + if (!sastr_add_string(&saseed, val)) + goto err ; + + seed->nopts++ ; + + break ; + + case SEED_ENABLE : + + if (!strcmp(val,"true") || !strcmp(val,"True")) + seed->enabled = 1 ; + + seed->nopts++ ; + + break ; + + case SEED_ALLOW : + + seed->allow = saseed.len ; + if (!sastr_add_string(&saseed, val)) + goto err ; + + seed->nopts++ ; + + break ; + + case SEED_DENY : + + seed->deny = saseed.len ; + if (!sastr_add_string(&saseed, val)) + goto err ; + + seed->nopts++ ; + + break ; + + case SEED_CURRENT : + + if (!strcmp(val,"true") || !strcmp(val,"True")) + seed->current = 1 ; + + seed->nopts++ ; + + break ; + + case SEED_GROUP : + + if (strcmp(val,"boot") && strcmp(val,"admin") && strcmp(val,"user")) { + + log_warn("invalid group: ", val) ; + goto err ; + } + + seed->group = saseed.len ; + if (!sastr_add_string(&saseed, val)) + goto err ; + + seed->nopts++ ; + + break ; + + case SEED_SERVICES : + { + stralloc sv = STRALLOC_ZERO ; + + if (!sastr_clean_string_wdelim(&sv, val, ',') || + !sastr_rebuild_in_oneline(&sv)) { + + log_warnu("clean service list") ; + goto err ; + } + + seed->services = saseed.len ; + if (!sastr_add_string(&saseed, sv.s)) + goto err ; + + seed->nopts++ ; + + break ; + } + + default : + + log_warn("unknown key: ", key, " -- ignoring") ; + break ; + } + + } + + stralloc_free(&sa) ; + return 1 ; + err: + stralloc_free(&sa) ; + return 0 ; +} + +/** @Return -1 bad format e.g want REG get DIR + * @Return 0 fail + * @Return success */ +static int tree_seed_file_isvalid(char const *seedpath, char const *treename) +{ + log_flow() ; + int r ; + size_t slen = strlen(seedpath), tlen = strlen(treename) ; + char seed[slen + tlen + 1] ; + auto_strings(seed, seedpath, treename) ; + + r = scan_mode(seed, S_IFREG) ; + + return r ; +} + +int tree_seed_resolve_path(stralloc *sa, char const *seed) +{ + log_flow() ; + + int r ; + + char *src = 0 ; + uid_t uid = getuid() ; + if (!uid) { + + src = SS_SEED_ADMDIR ; + + } else { + + if (!set_ownerhome(sa, uid)) + log_warnusys_return(LOG_EXIT_ZERO, "set home directory") ; + + if (!auto_stra(sa, SS_SEED_USERDIR)) + log_warnsys_return(LOG_EXIT_ZERO, "stralloc") ; + + src = sa->s ; + } + + r = tree_seed_file_isvalid(src, seed) ; + if (r == -1) + return 0 ; + + if (!r) { + + /** yeah double check because we can come from !uid */ + src = SS_SEED_ADMDIR ; + r = tree_seed_file_isvalid(src, seed) ; + if (r == -1) + return 0 ; + + if (!r) { + + src = SS_SEED_SYSDIR ; + r = tree_seed_file_isvalid(src, seed) ; + if (r != 1) + return 0 ; + + } + } + + sa->len = 0 ; + if (!auto_stra(sa,src, seed)) + log_warnsys_return(LOG_EXIT_ZERO, "stralloc") ; + + return 1 ; + +} + +int tree_seed_isvalid(char const *seed) +{ + int e = 1 ; + stralloc src = STRALLOC_ZERO ; + + if (!tree_seed_resolve_path(&src, seed)) + e = 0 ; + + stralloc_free(&src) ; + + return e ; +} + +int tree_seed_ismandatory(ss_tree_seed_t *seed, uint8_t check_service) +{ + log_flow() ; + + uid_t uid = getuid() ; + size_t pos = 0 ; + stralloc sv = STRALLOC_ZERO ; + + char *group = saseed.s + seed->group ; + char *service = saseed.s + seed->services ; + + if (!uid && (!strcmp(group, "user"))) { + + log_warn("Only regular user can use this seed") ; + goto err ; + + } else if (uid && (!strcmp(group, "root"))) { + + log_warn("Only root user can use this seed") ; + goto err ; + } + + if (!strcmp(saseed.s + seed->name , "boot") && seed->enabled) { + + log_warn("enable was asked for a tree on group boot -- ignoring enable request") ; + seed->enabled = 0 ; + } + + if (check_service) { + + stralloc sasrc = STRALLOC_ZERO ; + + if (!stralloc_cats(&sv, service) || + !sastr_clean_element(&sv)) { + + log_warnu("clean service list") ; + stralloc_free(&sasrc) ; + goto err ; + } + + FOREACH_SASTR(&sv, pos) { + + char *s = sv.s + pos ; + + /** ss_resolve_src already warn user */ + if (!ss_resolve_src_path(&sasrc,s, uid, 0)) { + + stralloc_free(&sasrc) ; + goto err ; + } + } + + stralloc_free(&sasrc) ; + } + + stralloc_free(&sv) ; + return 1 ; + err: + stralloc_free(&sv) ; + return 0 ; +} + +/** Return 0 on fail + * Return 1 if tree need to be created + * Return 2 if tree already exist */ +int tree_seed_setseed(ss_tree_seed_t *seed, char const *treename, uint8_t check_service) +{ + log_flow() ; + + stralloc src = STRALLOC_ZERO ; + + if (!tree_seed_resolve_path(&src, treename)) + goto err ; + + seed->name = saseed.len ; + if (!sastr_add_string(&saseed, treename)) + goto err ; + + if (!tree_seed_parse_file(seed, src.s) || + !tree_seed_ismandatory(seed, check_service)) + goto err ; + + stralloc_free(&src) ; + return 1 ; + err: + stralloc_free(&src) ; + return 0 ; +} -- GitLab