From b09b4b3acccaa005e97738978488b72d5c69d787 Mon Sep 17 00:00:00 2001 From: obarun <eric@obarun.org> Date: Mon, 1 Nov 2021 17:08:36 +1100 Subject: [PATCH] pass 66-tree to ssexec_t struct, add the seed file feature --- src/66/66-tree.c | 782 +----------------------------------- src/include/66/ssexec.h | 9 +- src/lib66/ssexec_help.c | 25 ++ src/lib66/ssexec_tree.c | 864 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 904 insertions(+), 776 deletions(-) create mode 100644 src/lib66/ssexec_tree.c diff --git a/src/66/66-tree.c b/src/66/66-tree.c index 84f5226e..4b7d9867 100644 --- a/src/66/66-tree.c +++ b/src/66/66-tree.c @@ -12,789 +12,21 @@ * except according to the terms contained in the LICENSE file./ */ -#include <66/tree.h> - -#include <string.h> -#include <stdint.h>//uintx_t -#include <sys/stat.h> -#include <stdio.h>//rename - -#include <oblibs/obgetopt.h> #include <oblibs/log.h> -#include <oblibs/types.h> -#include <oblibs/directory.h> -#include <oblibs/files.h> -#include <oblibs/string.h> -#include <oblibs/sastr.h> - -#include <skalibs/stralloc.h> -#include <skalibs/djbunix.h> -#include <skalibs/bytestr.h>//byte_count -#include <skalibs/posixplz.h>//unlink_void - -#include <66/config.h> -#include <66/utils.h> -#include <66/constants.h> -#include <66/db.h> -#include <66/enum.h> -#include <66/state.h> -#include <66/resolve.h> - -#include <s6/supervise.h> -#include <s6-rc/s6rc-servicedir.h> -#include <s6-rc/s6rc-constants.h> - -#define USAGE "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -n|R ] [ -a|d ] [ -c ] [ -S after_tree ] [ -E|D ] [ -C clone ] tree" - -static char const *cleantree = 0 ; - -static inline void info_help (void) -{ - DEFAULT_MSG = 0 ; - - static char const *help = -"\n" -"options :\n" -" -h: print this help\n" -" -z: use color\n" -" -v: increase/decrease verbosity\n" -" -n: create a new empty tree\n" -" -a: allow user(s) at tree\n" -" -d: deny user(s) at tree\n" -" -c: set tree as default\n" -" -S: start the tree after after_tree\n" -" -E: enable the tree\n" -" -D: disable the tree\n" -" -R: remove the tree\n" -" -C: clone the tree\n" -; - - log_info(USAGE,"\n",help) ; -} - -static void cleanup(void) -{ - log_flow() ; - - if (cleantree) - { - log_trace("removing: ",cleantree,"...") ; - rm_rf(cleantree) ; - } -} - -static void auto_string(char *strings,char const *str,size_t baselen) -{ - log_flow() ; - - size_t slen = strlen(str) ; - memcpy(strings + baselen,str,slen) ; - strings[baselen+slen] = 0 ; -} - -static void auto_dir(char const *dst,mode_t mode) -{ - log_flow() ; - - log_trace("create directory: ",dst) ; - if (!dir_create_parent(dst,mode)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create directory: ",dst) ; -} -static void auto_create(char *strings,char const *str,size_t baselen,mode_t mode) -{ - log_flow() ; - - auto_string(strings,str,baselen) ; - auto_dir(strings,mode) ; -} - -static void auto_check(char *dst,char const *str,size_t baselen,mode_t mode) -{ - log_flow() ; - - auto_string(dst,str,baselen) ; - if (!scan_mode(dst,mode)) auto_dir(dst,0755) ; -} - -static void auto_check_one(char *dst,mode_t mode) -{ - log_flow() ; - - if (!scan_mode(dst,mode)) auto_dir(dst,0755) ; -} - -static void inline auto_stralloc(stralloc *sa,char const *str) -{ - log_flow() ; - - if (!stralloc_cats(sa,str)) log_die_nomem("stralloc") ; -} - -static void inline auto_stralloc0(stralloc *sa) -{ - log_flow() ; - - if (!stralloc_0(sa)) log_die_nomem("stralloc") ; - sa->len-- ; -} - -static void inline auto_stralloc_0(stralloc *sa,char const *str) -{ - log_flow() ; - - auto_stralloc(sa,str) ; - auto_stralloc0(sa) ; -} - -int sanitize_tree(stralloc *dstree, char const *base, char const *tree,uid_t owner) -{ - log_flow() ; - - ssize_t r ; - size_t baselen = strlen(base) ; - size_t treelen = strlen(tree) ; - char dst[baselen + SS_SYSTEM_LEN + 1 + treelen + 1] ; - auto_string(dst,base,0) ; - - /** base is /var/lib/66 or $HOME/.66*/ - /** this verification is made in case of - * first use of 66-*** tools */ - auto_check(dst,SS_SYSTEM,baselen,0755) ; - /** create extra directory for service part */ - if (!owner) - { - auto_check_one(SS_LOGGER_SYSDIR,0755) ; - auto_check_one(SS_SERVICE_SYSDIR,0755) ; - auto_check_one(SS_SERVICE_ADMDIR,0755) ; - auto_check_one(SS_SERVICE_ADMCONFDIR,0755) ; - auto_check_one(SS_MODULE_SYSDIR,0755) ; - auto_check_one(SS_MODULE_ADMDIR,0755) ; - auto_check_one(SS_SCRIPT_SYSDIR,0755) ; - } - else - { - size_t extralen ; - stralloc extra = STRALLOC_ZERO ; - if (!set_ownerhome(&extra,owner)) - log_dieusys(LOG_EXIT_SYS,"set home directory") ; - - extralen = extra.len ; - auto_stralloc(&extra,SS_USER_DIR) ; - auto_stralloc_0(&extra,SS_SYSTEM) ; - auto_check_one(extra.s,0755) ; - extra.len = extralen ; - auto_stralloc_0(&extra,SS_LOGGER_USERDIR) ; - auto_check_one(extra.s,0755) ; - extra.len = extralen ; - auto_stralloc_0(&extra,SS_SERVICE_USERDIR) ; - auto_check_one(extra.s,0755) ; - extra.len = extralen ; - auto_stralloc_0(&extra,SS_SERVICE_USERCONFDIR) ; - auto_check_one(extra.s,0755) ; - extra.len = extralen ; - auto_stralloc_0(&extra,SS_MODULE_USERDIR) ; - auto_check_one(extra.s,0755) ; - extra.len = extralen ; - auto_stralloc_0(&extra,SS_SCRIPT_USERDIR) ; - auto_check_one(extra.s,0755) ; - stralloc_free(&extra) ; - } - - auto_check(dst,SS_TREE_CURRENT,baselen,0755) ; - auto_string(dst,SS_SYSTEM,baselen) ; - auto_check(dst,SS_BACKUP,baselen + SS_SYSTEM_LEN,0755) ; - auto_string(dst,SS_STATE,baselen + SS_SYSTEM_LEN) ; - if (!scan_mode(dst,S_IFREG)) - { - auto_string(dst,SS_SYSTEM,baselen) ; - if(!file_create_empty(dst,SS_STATE + 1,0644)) - log_dieusys(LOG_EXIT_SYS,"create ",dst,SS_STATE) ; - } - auto_string(dst,"/",baselen + SS_SYSTEM_LEN) ; - auto_string(dst,tree,baselen + SS_SYSTEM_LEN + 1) ; - r = scan_mode(dst,S_IFDIR) ; - if (r == -1) log_die(LOG_EXIT_SYS,"invalid directory: ",dst) ; - /** we have one, keep it*/ - if (!stralloc_cats(dstree,dst)) log_die_nomem("stralloc") ; - if (!stralloc_0(dstree)) log_die_nomem("stralloc") ; - - if (!r) return 0 ; - - return 1 ; -} - -void create_tree(char const *tree,char const *treename) -{ - log_flow() ; - - size_t newlen = 0 ; - size_t treelen = strlen(tree) ; - - char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ; - ss_resolve_t res = RESOLVE_ZERO ; - ss_resolve_init(&res) ; - - memcpy(dst, tree, treelen) ; - newlen = treelen ; - dst[newlen] = 0 ; - - res.name = ss_resolve_add_string(&res,SS_MASTER+1) ; - res.description = ss_resolve_add_string(&res,"inner bundle - do not use it") ; - res.tree = ss_resolve_add_string(&res,dst) ; - res.treename = ss_resolve_add_string(&res,treename) ; - res.type = TYPE_BUNDLE ; - res.disen = 1 ; - - auto_create(dst,SS_SVDIRS,newlen,0755) ; - auto_create(dst,SS_RULES,newlen,0755) ; - auto_string(dst,SS_SVDIRS,newlen) ; - newlen = newlen + SS_SVDIRS_LEN ; - auto_create(dst,SS_DB,newlen,0755) ; - auto_create(dst,SS_SVC,newlen,0755) ; - auto_create(dst,SS_RESOLVE,newlen,0755) ; - dst[newlen] = 0 ; - log_trace("write resolve file of inner bundle") ; - if (!ss_resolve_write(&res,dst,SS_MASTER+1)) - { - ss_resolve_free(&res) ; - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ; - } - ss_resolve_free(&res) ; - - char sym[newlen + 1 + SS_SYM_SVC_LEN + 1] ; - char dstsym[newlen + SS_SVC_LEN + 1] ; - - auto_string(sym,dst,0) ; - auto_string(sym,"/",newlen) ; - auto_string(sym,SS_SYM_SVC,newlen + 1) ; - - auto_string(dstsym,dst,0) ; - auto_string(dstsym,SS_SVC,newlen) ; - log_trace("point symlink: ",sym," to ",dstsym) ; - if (symlink(dstsym,sym) < 0) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; - - auto_string(sym,SS_SYM_DB,newlen + 1) ; - auto_string(dstsym,SS_DB,newlen) ; - log_trace("point symlink: ",sym," to ",dstsym) ; - if (symlink(dstsym,sym) < 0) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; - - auto_string(dst,SS_DB,newlen) ; - newlen = newlen + SS_DB_LEN ; - auto_create(dst,SS_SRC,newlen,0755) ; - auto_string(dst,SS_SRC,newlen) ; - newlen = newlen + SS_SRC_LEN ; - auto_create(dst,SS_MASTER,newlen,0755) ; - auto_string(dst,SS_MASTER,newlen) ; - newlen = newlen + SS_MASTER_LEN ; - log_trace("create file: ",dst,"/contents") ; - if (!file_create_empty(dst,"contents",0644)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create: ",dst,"/contents") ; - - auto_string(dst,"/type",newlen) ; - log_trace("create file: ",dst) ; - if(!openwritenclose_unsafe(dst,"bundle\n",7)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write: ",dst) ; - - -} - -void create_backupdir(char const *base, char const *treename) -{ - log_flow() ; - - int r ; - - size_t baselen = strlen(base) - 1 ;//remove the last slash - size_t treenamelen = strlen(treename) ; - - char treetmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ; - - auto_string(treetmp,base,0) ; - auto_string(treetmp,"/",baselen) ; - auto_string(treetmp,SS_SYSTEM,baselen + 1) ; - auto_string(treetmp,SS_BACKUP,baselen + 1 + SS_SYSTEM_LEN) ; - auto_string(treetmp,"/",baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN) ; - auto_string(treetmp,treename,baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1) ; - - r = scan_mode(treetmp,S_IFDIR) ; - if (r || (r == -1)) - { - log_trace("remove existing backup: ",treetmp) ; - if (rm_rf(treetmp) < 0) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove: ",treetmp) ; - } - if (!r) auto_dir(treetmp,0755) ; -} - -/** @what -> 0 deny - * @what -> 1 allow */ -void set_rules(char const *tree,uid_t *uids, size_t uidn,uint8_t what) -{ - log_flow() ; - - log_trace("set ", !what ? "denied" : "allowed"," user for tree: ",tree,"..." ) ; - - int r ; - size_t treelen = strlen(tree) ; - - char pack[256] ; - char tmp[treelen + SS_RULES_LEN + 1] ; - - auto_string(tmp,tree,0) ; - auto_string(tmp,SS_RULES,treelen) ; - - if (!uidn && what) - { - uids[0] = 1 ; - uids[1] = MYUID ; - uidn++ ; - } - if (what) //allow - { - for (size_t i = 0 ; i < uidn ; i++) - { - uint32_pack(pack,uids[i+1]) ; - pack[uint_fmt(pack,uids[i+1])] = 0 ; - log_trace("create file: ",pack," at ",tmp) ; - if(!file_create_empty(tmp,pack,0644) && errno != EEXIST) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; - - log_trace("user: ",pack," is allowed for tree: ",tree) ; - } - return ; - } - //else deny - for (size_t i = 0 ; i < uidn ; i++) - { - if (MYUID == uids[i+1]) continue ; - uint32_pack(pack,uids[i+1]) ; - pack[uint_fmt(pack,uids[i+1])] = 0 ; - char ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[i+1]) + 1] ; - memcpy(ut,tmp,treelen + SS_RULES_LEN) ; - memcpy(ut + treelen + SS_RULES_LEN,"/",1) ; - memcpy(ut + treelen + SS_RULES_LEN + 1,pack,uint_fmt(pack,uids[i+1])) ; - ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[i + 1])] = 0 ; - r = scan_mode(tmp,S_IFREG) ; - if (r == 1) - { - log_trace("unlink: ",ut) ; - r = unlink(ut) ; - if (r == -1) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; - } - log_trace("user: ",pack," is denied for tree: ",tree) ; - } -} - -/** @action -> 0 disable - * @action -> 1 enable */ -void tree_enable_disable(char const *base, char const *dst, char const *tree,uint8_t action) -{ - log_flow() ; - - int r ; - log_trace(!action ? "disable " : "enable ",dst,"...") ; - r = tree_cmd_state(VERBOSITY,!action ? "-d" : "-a", tree) ; - if (!r) log_dieusys(LOG_EXIT_SYS,!action ? "disable: " : "enable: ",dst," at: ",base,SS_SYSTEM,SS_STATE) ; - else if (r == 1) - { - log_info(!action ? "Disabled" : "Enabled"," successfully tree: ",tree) ; - } - else log_info("Already ",!action ? "disabled" : "enabled"," tree: ",tree) ; - -} - -void tree_modify_resolve(ss_resolve_t *res,ss_resolve_enum_t field,char const *regex,char const *by) -{ - log_flow() ; - - stralloc sa = STRALLOC_ZERO ; - ss_resolve_t modif = RESOLVE_ZERO ; - - log_trace("modify field: ",ss_resolve_field_table[field].field," of service: ",res->sa.s + res->name) ; - - if (!ss_resolve_copy(&modif,res)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ", res->sa.s + res->name) ; - - if (!ss_resolve_put_field_to_sa(&sa,&modif, field)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get copy field: ",ss_resolve_field_table[field].field) ; - - if (sa.len) { - if (!sastr_replace(&sa,regex,by)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"replace field: ",ss_resolve_field_table[field].field) ; - - if (!stralloc_0(&sa)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ; - - sa.len-- ; - } - - if (!ss_resolve_modify_field(&modif,field,sa.s)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"modify field: ",ss_resolve_field_table[field].field) ; - - if (!ss_resolve_copy(res,&modif)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ",res->sa.s + res->name) ; - - stralloc_free(&sa) ; - - ss_resolve_free(&modif) ; -} - -void tree_remove(char const *base,char const *dst,char const *tree) -{ - log_flow() ; - - log_trace("delete: ",dst,"..." ) ; - - int r ; - - if (rm_rf(dst) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ", dst) ; - - size_t treelen = strlen(tree) ; - size_t baselen = strlen(base) ; - char treetmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treelen + 1] ; - auto_string(treetmp,base,0) ; - auto_string(treetmp,SS_SYSTEM,baselen) ; - auto_string(treetmp,SS_BACKUP,baselen + SS_SYSTEM_LEN) ; - auto_string(treetmp,"/",baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN) ; - auto_string(treetmp,tree,baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1) ; - - r = scan_mode(treetmp,S_IFDIR) ; - if (r || (r < 0)) - { - log_trace("delete backup of tree: ",treetmp,"...") ; - if (rm_rf(treetmp) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ",treetmp) ; - } - - tree_enable_disable(base,dst,tree,0) ; - - log_info("Deleted successfully: ",tree) ; -} +#include <66/ssexec.h> int main(int argc, char const *const *argv,char const *const *envp) { - int r, current, create, allow, deny, enable, disable, remove, snap ; - - uid_t owner ; - - size_t auidn = 0 ; - uid_t auids[256] = { 0 } ; - - size_t duidn = 0 ; - uid_t duids[256] = { 0 } ; - - char const *tree = 0 ; - char const *after_tree = 0 ; - - stralloc base = STRALLOC_ZERO ; - stralloc dstree = STRALLOC_ZERO ; - stralloc clone = STRALLOC_ZERO ; - - log_color = &log_color_disable ; - - current = create = allow = deny = enable = disable = remove = snap = 0 ; - PROG = "66-tree" ; - { - subgetopt l = SUBGETOPT_ZERO ; - - for (;;) - { - int opt = getopt_args(argc,argv, "hv:na:d:cS:EDRC:z", &l) ; - if (opt == -1) break ; - if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; - switch (opt) - { - case 'h' : info_help(); return 0 ; - case 'v' : if (!uint0_scan(l.arg, &VERBOSITY)) log_usage(USAGE) ; break ; - case 'n' : create = 1 ; break ; - case 'a' : if (!scan_uidlist_wdelim(l.arg,auids,',')) log_usage(USAGE) ; - auidn = auids[0] ; - allow = 1 ; - break ; - case 'd' : if (!scan_uidlist_wdelim(l.arg,duids,',')) log_usage(USAGE) ; - duidn = duids[0] ; - deny = 1 ; - break ; - case 'c' : current = 1 ; break ; - case 'S' : after_tree = l.arg ; break ; - case 'E' : enable = 1 ; if (disable) log_usage(USAGE) ; break ; - case 'D' : disable = 1 ; if (enable) log_usage (USAGE) ; break ; - case 'R' : remove = 1 ; if (create) log_usage(USAGE) ; break ; - case 'C' : if (remove) log_usage(USAGE) ; - if (!stralloc_cats(&clone,l.arg)) log_die_nomem("stralloc") ; - if (!stralloc_0(&clone)) log_die_nomem("stralloc") ; - snap = 1 ; - break ; - case 'z' : log_color = !isatty(1) ? &log_color_disable : &log_color_enable ; break ; - default : log_usage(USAGE) ; - } - } - argc -= l.ind ; argv += l.ind ; - } - - if (argc != 1) log_usage(USAGE) ; - - tree = argv[0] ; - owner = MYUID ; - - if (!set_ownersysdir(&base, owner)) log_dieusys(LOG_EXIT_SYS,"set owner directory") ; - - log_trace("sanitize ",tree,"..." ) ; - r = sanitize_tree(&dstree,base.s,tree,owner) ; - - if(!r && create) - { - /** set cleanup */ - cleantree = dstree.s ; - log_trace("creating: ",dstree.s,"..." ) ; - create_tree(dstree.s,tree) ; - - log_trace("creating backup directory for: ", tree,"...") ; - create_backupdir(base.s,tree) ; - /** unset cleanup */ - cleantree = 0 ; - - log_trace("set permissions rules for: ",dstree.s,"..." ) ; - set_rules(dstree.s,auids,auidn,1) ; - - size_t dblen = dstree.len - 1 ; - char newdb[dblen + SS_SVDIRS_LEN + 1] ; - auto_string(newdb,dstree.s,0) ; - auto_string(newdb,SS_SVDIRS,dblen) ; - - log_trace("compile: ",newdb,"/db/",tree,"..." ) ; - if (!db_compile(newdb,dstree.s,tree,envp)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"compile ",newdb,"/db/",tree) ; - - r = 1 ; - create = 0 ; - log_info("Created successfully tree: ",tree) ; - } - - if ((!r && !create) || (!r && enable)) log_dieusys(LOG_EXIT_SYS,"find tree: ",dstree.s) ; - if (r && create) log_dieu(LOG_EXIT_USER,"create: ",dstree.s,": already exist") ; - - if (enable) - tree_enable_disable(base.s,dstree.s,tree,1) ; - - if (disable) - tree_enable_disable(base.s,dstree.s,tree,0) ; - - if (auidn) - set_rules(dstree.s,auids,auidn,1) ; - - if (duidn) - set_rules(dstree.s,duids,duidn,0) ; - - if(current) - { - log_trace("make: ",dstree.s," as default ..." ) ; - if (!tree_switch_current(base.s,tree)) log_dieusys(LOG_EXIT_SYS,"set: ",dstree.s," as default") ; - log_info("Set successfully: ",tree," as default") ; - } - - if (remove) - tree_remove(base.s,dstree.s,tree) ; - - if (snap) - { - stralloc salist = STRALLOC_ZERO ; - ss_resolve_t res = RESOLVE_ZERO ; - - size_t syslen = base.len + SS_SYSTEM_LEN ; - size_t treelen = strlen(tree) ; - size_t pos = 0 ; - - char system[syslen + 1] ; - auto_strings(system,base.s,SS_SYSTEM) ; - - size_t clone_target_len = syslen + 1 + clone.len ; - char clone_target[clone_target_len + 1] ; - auto_strings(clone_target,system,"/",clone.s) ; - - r = scan_mode(clone_target,S_IFDIR) ; - if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ; - - // clone main directory - log_trace("clone: ",tree," as: ",clone.s,"..." ) ; - if (!hiercopy(dstree.s,clone_target)) - log_dieusys(LOG_EXIT_SYS,"copy: ",dstree.s," to: ",clone_target) ; - - // clone backup directory - size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clone.len ; - char clone_backup[clone_backup_len + 1] ; - auto_strings(clone_backup,system,SS_BACKUP,"/",clone.s) ; - - char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ; - auto_strings(tree_backup,system,SS_BACKUP,"/",tree) ; - - /* make cleantree pointing to the clone to be able to remove it - * in case of crach */ - cleantree = clone_target ; - - log_trace("clone backup of: ",tree," as: ",clone.s,"..." ) ; - if (!hiercopy(tree_backup,clone_backup)) - log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ; - - // modify the resolve file to match the new name - // main directory first - char src_resolve[clone_target_len + SS_SVDIRS_LEN + SS_RESOLVE_LEN + 1] ; - auto_strings(src_resolve,clone_target,SS_SVDIRS,SS_RESOLVE) ; - - if (!sastr_dir_get(&salist,src_resolve,"",S_IFREG)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ; - - char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ; - auto_strings(clone_res,clone_target,SS_SVDIRS) ; - - for (;pos < salist.len ; pos += strlen(salist.s + pos) + 1) - { - char *name = salist.s + pos ; - - if (!ss_resolve_read(&res,clone_res,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ; - - tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ; - tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ; - tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ; - tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ; - - if (!ss_resolve_write(&res,clone_res,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; - } - - // rename db - char clone_db_old[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + treelen + 1] ; - auto_strings(clone_db_old,clone_target,SS_SVDIRS,SS_DB,"/",tree) ; - - char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clone.len + 1] ; - auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone.s) ; - - log_trace("rename tree db: ",tree," as: ",clone.s,"..." ) ; - if (rename(clone_db_old,clone_db_new) == -1) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_old," to: ",clone_db_new) ; - - // backup directory - char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ; - auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ; - - salist.len = 0 ; - - /** main and backup can be different,so rebuild the list - * Also, a backup directory can be empty, check it first */ - r = scan_mode(src_resolve_backup,S_IFDIR) ; - if (r == 1) - { - if (!sastr_dir_get(&salist,src_resolve_backup,"",S_IFREG)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ; - - for (pos = 0 ; pos < salist.len ; pos += strlen(salist.s + pos) + 1) - { - char *name = salist.s + pos ; - - if (!ss_resolve_read(&res,clone_backup,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ; - - tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ; - tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ; - tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ; - tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ; - - if (!ss_resolve_write(&res,clone_backup,name)) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; - } - // rename db - char clone_db_backup_old[clone_backup_len + SS_DB_LEN + 1 + treelen + 1] ; - auto_strings(clone_db_backup_old,clone_backup,SS_DB,"/",tree) ; - - char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clone.len + 1] ; - auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone.s) ; - - log_trace("rename tree backup db: ",tree," as: ",clone.s,"..." ) ; - if (rename(clone_db_backup_old,clone_db_backup_new) == -1) - log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_backup_old," to: ",clone_db_backup_new) ; - } - - stralloc_free(&salist) ; - ss_resolve_free(&res) ; - - log_info("Cloned successfully: ",tree," to ",clone.s) ; - } - - if (after_tree) - { - stralloc contents = STRALLOC_ZERO ; - stralloc tmp = STRALLOC_ZERO ; - int befirst = obstr_equal(tree,after_tree) ; - size_t baselen = base.len, pos = 0 ; - char ste[baselen + SS_SYSTEM_LEN + 1] ; - auto_strings(ste,base.s,SS_SYSTEM) ; - - int enabled = tree_cmd_state(VERBOSITY,"-s",tree) ; - if (enabled != 1) - log_die(LOG_EXIT_USER,"tree: ",tree," is not enabled") ; - - enabled = tree_cmd_state(VERBOSITY,"-s",after_tree) ; - if (enabled != 1) - log_die(LOG_EXIT_USER,"tree: ",after_tree," is not enabled") ; - - r = tree_cmd_state(VERBOSITY,"-d",tree) ; - if (!r) log_dieusys(LOG_EXIT_SYS,"disable: ",tree," at: ",ste,SS_STATE) ; - - r = file_readputsa(&tmp,ste,SS_STATE + 1) ; - if(!r) log_dieusys(LOG_EXIT_SYS,"open: ", ste,SS_STATE) ; - - /** if you have only one tree enabled, the state file will be - * empty because we disable it before reading the file(see line 803). - * This will make a crash at sastr_? call. - * So write directly the name of the tree at state file. */ - - if (tmp.len) - { - if (!sastr_rebuild_in_oneline(&tmp) || - !sastr_clean_element(&tmp)) - log_dieu(LOG_EXIT_SYS,"rebuild state list") ; - - for (pos = 0 ;pos < tmp.len; pos += strlen(tmp.s + pos) + 1) - { - char *name = tmp.s + pos ; - - /* e.g 66-tree -S root root -> meaning root need to - * be the first to start */ - if ((befirst) && (pos == 0)) - { - if (!auto_stra(&contents,tree,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; - } - if (!auto_stra(&contents,name,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; - - if (obstr_equal(name,after_tree)) - { - if (!auto_stra(&contents,tree,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; - } - } - } - else - { - if (!auto_stra(&contents,tree,"\n")) - log_dieusys(LOG_EXIT_SYS,"stralloc") ; - } - if (!file_write_unsafe(ste,SS_STATE + 1,contents.s,contents.len)) - log_dieusys(LOG_EXIT_ZERO,"write: ",ste,SS_STATE) ; + ssexec_t info = SSEXEC_ZERO ; - log_info("Ordered successfully: ",tree," starts after tree: ",after_tree) ; - } + info.prog = PROG ; + info.help = help_tree ; + info.usage = usage_tree ; - stralloc_free(&base) ; - stralloc_free(&dstree) ; - stralloc_free(&clone) ; + info.skip_opt_tree = 1 ; - return 0 ; + return ssexec_main(argc,argv,envp,&ssexec_tree,&info) ; } diff --git a/src/include/66/ssexec.h b/src/include/66/ssexec.h index 0bb4c401..41fd8e85 100644 --- a/src/include/66/ssexec.h +++ b/src/include/66/ssexec.h @@ -40,7 +40,7 @@ struct ssexec_s uint8_t opt_timeout ; uint8_t opt_color ; // skip option definition 0->no,1-yes - uint8_t skip_opt_tree ; // tree,treename, treeallow and the permissions for the tree will be not set + uint8_t skip_opt_tree ; // tree,treename, treeallow will not be set. Also, trees permissions is not checked. } ; #define SSEXEC_ZERO { .base = STRALLOC_ZERO , \ @@ -78,6 +78,7 @@ extern ssexec_func_t ssexec_svctl ; extern ssexec_func_t ssexec_dbctl ; extern ssexec_func_t ssexec_env ; extern ssexec_func_t ssexec_all ; +extern ssexec_func_t ssexec_tree ; extern char const *usage_enable ; extern char const *help_enable ; @@ -97,6 +98,8 @@ extern char const *usage_env ; extern char const *help_env ; extern char const *usage_all ; extern char const *help_all ; +extern char const *usage_tree ; +extern char const *help_tree ; #define OPTS_INIT "cdb" #define OPTS_INIT_LEN (sizeof OPTS_INIT - 1) @@ -116,7 +119,11 @@ extern char const *help_all ; #define OPTS_ENV_LEN (sizeof OPTS_ENV - 1) #define OPTS_ALL "f" #define OPTS_ALL_LEN (sizeof OPTS_ALL - 1) +#define OPTS_TREE "na:d:cS:EDRC:" +#define OPTS_TREE_LEN (sizeof OPTS_TREE - 1) extern int ssexec_main(int argc, char const *const *argv, char const *const *envp,ssexec_func_t *func,ssexec_t *info) ; +extern void ssexec_set_info(ssexec_t *info) ; +extern int ssexec_set_treeinfo(ssexec_t *info) ; #endif diff --git a/src/lib66/ssexec_help.c b/src/lib66/ssexec_help.c index 3cca0ddd..1b806111 100644 --- a/src/lib66/ssexec_help.c +++ b/src/lib66/ssexec_help.c @@ -154,3 +154,28 @@ char const *help_all = " -t: tree to use\n" " -f: fork the process\n" ; + +char const *usage_tree = "66-tree [ -h ] [ -z ] [ -v verbosity ] [ -n|R ] [ -a|d ] [ -c ] [ -o depends=:requiredby= ] [ -E|D ] [ -C clone ] tree" ; + +char const *help_tree = +"\n" +"options :\n" +" -h: print this help\n" +" -z: use color\n" +" -v: increase/decrease verbosity\n" +" -n: create a new empty tree\n" +" -R: remove the tree\n" +" -a: allow user(s) at tree\n" +" -d: deny user(s) at tree\n" +" -c: set tree as default\n" +" -o: colon separated list of dependencies\n" +" -E: enable the tree\n" +" -D: disable the tree\n" +" -C: clone the tree\n" + +"\n" +"valid fields for -o options are:\n" +"\n" +" depends=: comma separated list of dependencies for tree\n" +" requiredby=: comma separated list of trees required by tree\n" +; diff --git a/src/lib66/ssexec_tree.c b/src/lib66/ssexec_tree.c new file mode 100644 index 00000000..07fe56e2 --- /dev/null +++ b/src/lib66/ssexec_tree.c @@ -0,0 +1,864 @@ +/* + * ssexec_tree.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 <string.h> +#include <stdint.h>//uintx_t +#include <sys/stat.h> +#include <stdio.h>//rename +#include <pwd.h> + +#include <oblibs/obgetopt.h> +#include <oblibs/log.h> +#include <oblibs/types.h> +#include <oblibs/directory.h> +#include <oblibs/files.h> +#include <oblibs/string.h> +#include <oblibs/sastr.h> + +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/bytestr.h>//byte_count +#include <skalibs/posixplz.h>//unlink_void + +#include <66/config.h> +#include <66/utils.h> +#include <66/constants.h> +#include <66/db.h> +#include <66/enum.h> +#include <66/state.h> +#include <66/resolve.h> + +#include <s6/supervise.h> +#include <s6-rc/s6rc-servicedir.h> +#include <s6-rc/s6rc-constants.h> + + +/** + * + * + * + * + * create > option by default + * + * -o depends=boot,system:requiredby=graphics + * + * depends/requiredby automatically enable the trees found at field except for boot + * + * -S options dissappear but it kept as it with a warn to user for the compatibility. + * + * -G for groups + * + * + * -a user,root. Actuellement user n'est pas compris.faire comme dans le parser_utils. + * + * */ + +static char const *cleantree = 0 ; + +static void cleanup(void) +{ + log_flow() ; + + if (cleantree) { + + log_trace("removing: ",cleantree,"...") ; + rm_rf(cleantree) ; + } +} + +static void auto_dir(char const *dst,mode_t mode) +{ + log_flow() ; + + log_trace("create directory: ",dst) ; + if (!dir_create_parent(dst,mode)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create directory: ",dst) ; +} + +static void auto_create(char *strings,char const *str, size_t len) +{ + log_flow() ; + + auto_strings(strings + len, str) ; + auto_dir(strings,0755) ; +} + +static void auto_check(char *dst) +{ + log_flow() ; + + int r = scan_mode(dst,S_IFDIR) ; + + if (r == -1) + log_diesys_nclean(LOG_EXIT_SYS, &cleanup, "conflicting format for: ", dst) ; + + if (!r) + auto_dir(dst,0755) ; +} + +static void inline auto_stralloc(stralloc *sa,char const *str) +{ + log_flow() ; + + if (!auto_stra(sa,str)) + log_die_nomem("stralloc") ; +} + +//int sanitize_tree(stralloc *dstree, char const *base, char const *tree,uid_t owner) +int sanitize_tree(ssexec_t *info, char const *tree) +{ + log_flow() ; + + ssize_t r ; + size_t baselen = info->base.len ; + size_t treelen = strlen(tree) ; + uid_t log_uid ; + gid_t log_gid ; + char dst[baselen + SS_SYSTEM_LEN + 1 + treelen + 1] ; + auto_strings(dst,info->base.s, SS_SYSTEM) ; + + /** base is /var/lib/66 or $HOME/.66*/ + /** this verification is made in case of + * first use of 66-*** tools */ + auto_check(dst) ; + /** create extra directory for service part */ + if (!info->owner) { + + auto_check(SS_LOGGER_SYSDIR) ; + + if (!youruid(&log_uid,SS_LOGGER_RUNNER) || + !yourgid(&log_gid,log_uid)) + log_dieusys(LOG_EXIT_SYS,"get uid and gid of: ",SS_LOGGER_RUNNER) ; + + if (chown(SS_LOGGER_SYSDIR,log_uid,log_gid) == -1) + log_dieusys(LOG_EXIT_SYS,"chown: ",SS_LOGGER_RUNNER) ; + + auto_check(SS_SERVICE_SYSDIR) ; + auto_check(SS_SERVICE_ADMDIR) ; + auto_check(SS_SERVICE_ADMCONFDIR) ; + auto_check(SS_MODULE_SYSDIR) ; + auto_check(SS_MODULE_ADMDIR) ; + auto_check(SS_SCRIPT_SYSDIR) ; + auto_check(SS_SEED_ADMDIR) ; + auto_check(SS_SEED_SYSDIR) ; + + } else { + + size_t extralen ; + stralloc extra = STRALLOC_ZERO ; + if (!set_ownerhome(&extra,info->owner)) + log_dieusys(LOG_EXIT_SYS,"set home directory") ; + + extralen = extra.len ; + if (!auto_stra(&extra, SS_USER_DIR, SS_SYSTEM)) + log_die_nomem("stralloc") ; + auto_check(extra.s) ; + + extra.len = extralen ; + auto_stralloc(&extra,SS_LOGGER_USERDIR) ; + auto_check(extra.s) ; + + extra.len = extralen ; + auto_stralloc(&extra,SS_SERVICE_USERDIR) ; + auto_check(extra.s) ; + + extra.len = extralen ; + auto_stralloc(&extra,SS_SERVICE_USERCONFDIR) ; + auto_check(extra.s) ; + + extra.len = extralen ; + auto_stralloc(&extra,SS_MODULE_USERDIR) ; + auto_check(extra.s) ; + + extra.len = extralen ; + auto_stralloc(&extra,SS_SCRIPT_USERDIR) ; + auto_check(extra.s) ; + + extra.len = extralen ; + auto_stralloc(&extra,SS_SEED_USERDIR) ; + auto_check(extra.s) ; + + stralloc_free(&extra) ; + } + + auto_strings(dst + baselen, SS_TREE_CURRENT) ; + auto_check(dst) ; + auto_strings(dst + baselen,SS_SYSTEM, SS_BACKUP) ; + auto_check(dst) ; + auto_strings(dst + baselen + SS_SYSTEM_LEN, SS_STATE) ; + + if (!scan_mode(dst,S_IFREG)) { + + auto_strings(dst + baselen,SS_SYSTEM) ; + if(!file_create_empty(dst,SS_STATE + 1,0644)) + log_dieusys(LOG_EXIT_SYS,"create ",dst,SS_STATE) ; + } + + auto_strings(dst + baselen + SS_SYSTEM_LEN,"/",tree) ; + r = scan_mode(dst,S_IFDIR) ; + if (r == -1) log_die(LOG_EXIT_SYS,"invalid directory: ",dst) ; + /** we have one, keep it*/ + info->tree.len = 0 ; + if (!auto_stra(&info->tree,dst)) + log_die_nomem("stralloc") ; + + if (!r) return 0 ; + + return 1 ; +} + +void create_tree(ssexec_t *info) +{ + log_flow() ; + + size_t newlen = 0 ; + size_t treelen = info->tree.len ; + + char const *tree = info->tree.s, *treename = info->treename.s ; + + char dst[treelen + SS_SVDIRS_LEN + SS_DB_LEN + SS_SRC_LEN + 16 + 1] ; + ss_resolve_t res = RESOLVE_ZERO ; + ss_resolve_init(&res) ; + + auto_strings(dst, tree) ; + newlen = treelen ; + + res.name = ss_resolve_add_string(&res,SS_MASTER+1) ; + res.description = ss_resolve_add_string(&res,"inner bundle - do not use it") ; + res.tree = ss_resolve_add_string(&res,dst) ; + res.treename = ss_resolve_add_string(&res,treename) ; + res.type = TYPE_BUNDLE ; + res.disen = 1 ; + + auto_create(dst, SS_SVDIRS, newlen) ; + auto_create(dst, SS_RULES, newlen) ; + auto_strings(dst + newlen, SS_SVDIRS) ; + newlen = newlen + SS_SVDIRS_LEN ; + auto_create(dst, SS_DB, newlen) ; + auto_create(dst, SS_SVC, newlen) ; + auto_create(dst, SS_RESOLVE, newlen) ; + dst[newlen] = 0 ; + log_trace("write resolve file of inner bundle") ; + if (!ss_resolve_write(&res,dst,SS_MASTER+1)) { + + ss_resolve_free(&res) ; + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of inner bundle") ; + } + ss_resolve_free(&res) ; + + char sym[newlen + 1 + SS_SYM_SVC_LEN + 1] ; + char dstsym[newlen + SS_SVC_LEN + 1] ; + + auto_strings(sym,dst, "/", SS_SYM_SVC) ; + auto_strings(dstsym, dst, SS_SVC) ; + + log_trace("point symlink: ",sym," to ",dstsym) ; + if (symlink(dstsym,sym) < 0) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; + + auto_strings(sym + newlen + 1, SS_SYM_DB) ; + auto_strings(dstsym + newlen, SS_DB) ; + + log_trace("point symlink: ",sym," to ",dstsym) ; + if (symlink(dstsym,sym) < 0) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"symlink: ", sym) ; + + auto_strings(dst + newlen, SS_DB) ; + newlen = newlen + SS_DB_LEN ; + auto_create(dst, SS_SRC, newlen) ; + auto_strings(dst + newlen, SS_SRC) ; + newlen = newlen + SS_SRC_LEN ; + auto_create(dst, SS_MASTER, newlen) ; + auto_strings(dst + newlen, SS_MASTER) ; + newlen = newlen + SS_MASTER_LEN ; + + log_trace("create file: ",dst,"/contents") ; + if (!file_create_empty(dst,"contents",0644)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"create: ",dst,"/contents") ; + + auto_strings(dst + newlen,"/type") ; + + log_trace("create file: ",dst) ; + if(!openwritenclose_unsafe(dst,"bundle\n",7)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write: ",dst) ; + +} + +void create_backupdir(ssexec_t *info) +{ + log_flow() ; + + int r ; + + size_t baselen = info->base.len ; + size_t treenamelen = info->treename.len ; + + char const *base = info->base.s, *treename = info->treename.s ; + + char treetmp[baselen + 1 + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treenamelen + 1] ; + + auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", treename) ; + + r = scan_mode(treetmp,S_IFDIR) ; + if (r || (r == -1)) { + + log_trace("remove existing backup: ",treetmp) ; + if (rm_rf(treetmp) < 0) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"remove: ",treetmp) ; + } + + if (!r) + auto_dir(treetmp,0755) ; +} + +void parse_uild_list(uid_t *uids, char const *str) +{ + size_t pos = 0 ; + stralloc sa = STRALLOC_ZERO ; + + if (!sastr_clean_string_wdelim(&sa, str, ',')) + log_dieu(LOG_EXIT_SYS,"parse uid list") ; + + uid_t owner = MYUID ; + /** special case, we don't know which user want to use + * the service, we need a general name to allow all user + * the term "user" is took here to allow the current user*/ + ssize_t p = sastr_cmp(&sa,"user") ; + + FOREACH_SASTR(&sa, pos) { + + if (pos == (size_t)p) { + + struct passwd *pw = getpwuid(owner); + + if (!pw) { + + if (!errno) errno = ESRCH ; + log_dieu(LOG_EXIT_ZERO,"get user name") ; + } + + if (!scan_uidlist(pw->pw_name, uids)) + log_dieu(LOG_EXIT_USER,"scan account: ",pw->pw_name) ; + + continue ; + } + + if (!scan_uidlist(sa.s + pos, uids)) + log_dieu(LOG_EXIT_USER,"scan account: ",sa.s + pos) ; + + } +} + +/** @what -> 0 deny + * @what -> 1 allow */ +void set_rules(char const *tree, uid_t *uids, uint8_t what) +{ + log_flow() ; + + log_trace("set ", !what ? "denied" : "allowed"," user for tree: ",tree,"..." ) ; + + int r ; + size_t treelen = strlen(tree), uidn = uids[0], pos = 0 ; + uid_t owner = MYUID ; + char pack[256] ; + char tmp[treelen + SS_RULES_LEN + 1] ; + + auto_strings(tmp, tree, SS_RULES) ; + + if (!uidn && what) { + + uids[0] = 1 ; + uids[1] = owner ; + uidn++ ; + } + + //allow + if (what) { + + for (; pos < uidn ; pos++) { + + uint32_pack(pack,uids[pos+1]) ; + pack[uint_fmt(pack,uids[pos+1])] = 0 ; + log_trace("create file: ",pack," at ",tmp) ; + if(!file_create_empty(tmp,pack,0644) && errno != EEXIST) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; + + log_trace("user: ",pack," is allowed for tree: ",tree) ; + } + goto announce ; + } + //else deny + for (pos = 0 ; pos < uidn ; pos++) { + + if (owner == uids[pos+1]) continue ; + uint32_pack(pack,uids[pos+1]) ; + pack[uint_fmt(pack,uids[pos+1])] = 0 ; + char ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos+1]) + 1] ; + memcpy(ut,tmp,treelen + SS_RULES_LEN) ; + memcpy(ut + treelen + SS_RULES_LEN,"/",1) ; + memcpy(ut + treelen + SS_RULES_LEN + 1,pack,uint_fmt(pack,uids[pos+1])) ; + ut[treelen + SS_RULES_LEN + 1 + uint_fmt(pack,uids[pos + 1])] = 0 ; + r = scan_mode(ut,S_IFREG) ; + if (r == 1) { + + log_trace("unlink: ",ut) ; + r = unlink(ut) ; + if (r == -1) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"set permissions access") ; + } + + log_trace("user: ",pack," is denied for tree: ",tree) ; + } + announce: + log_info("Permissions rules set successfully for tree: ",tree) ; +} + +/** @action -> 0 disable + * @action -> 1 enable */ +void tree_enable_disable(ssexec_t *info, uint8_t action) +{ + log_flow() ; + + int r ; + char const *base = info->base.s, *dst = info->tree.s , *tree = info->treename.s ; + + log_trace(!action ? "disable " : "enable ",dst,"...") ; + r = tree_cmd_state(VERBOSITY,!action ? "-d" : "-a", tree) ; + if (!r) + + log_dieusys(LOG_EXIT_SYS,!action ? "disable: " : "enable: ",dst," at: ",base,SS_SYSTEM,SS_STATE) ; + + else if (r == 1) { + + log_info(!action ? "Disabled" : "Enabled"," successfully tree: ",tree) ; + + } + + else log_info("Already ",!action ? "disabled" : "enabled"," tree: ",tree) ; + +} + +void tree_modify_resolve(ss_resolve_t *res,ss_resolve_enum_t field,char const *regex,char const *by) +{ + log_flow() ; + + stralloc sa = STRALLOC_ZERO ; + ss_resolve_t modif = RESOLVE_ZERO ; + + log_trace("modify field: ",ss_resolve_field_table[field].field," of service: ",res->sa.s + res->name) ; + + if (!ss_resolve_copy(&modif,res)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ", res->sa.s + res->name) ; + + if (!ss_resolve_put_field_to_sa(&sa,&modif, field)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get copy of field: ",ss_resolve_field_table[field].field) ; + + if (sa.len) { + if (!sastr_replace(&sa,regex,by)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"replace field: ",ss_resolve_field_table[field].field) ; + + if (!stralloc_0(&sa)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"stralloc") ; + + sa.len-- ; + } + + if (!ss_resolve_modify_field(&modif,field,sa.s)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"modify field: ",ss_resolve_field_table[field].field) ; + + if (!ss_resolve_copy(res,&modif)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy resolve file of: ",res->sa.s + res->name) ; + + stralloc_free(&sa) ; + + ss_resolve_free(&modif) ; +} + +void tree_remove(ssexec_t *info) +{ + log_flow() ; + + char const *base = info->base.s, *dst = info->tree.s, *tree = info->treename.s ; + int r ; + + log_trace("delete: ",dst,"..." ) ; + + if (rm_rf(dst) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ", dst) ; + + size_t treelen = strlen(tree) ; + size_t baselen = strlen(base) ; + char treetmp[baselen + SS_SYSTEM_LEN + SS_BACKUP_LEN + 1 + treelen + 1] ; + + auto_strings(treetmp, base, SS_SYSTEM, SS_BACKUP, "/", tree) ; + + r = scan_mode(treetmp,S_IFDIR) ; + if (r || (r < 0)) { + + log_trace("delete backup of tree: ",treetmp,"...") ; + if (rm_rf(treetmp) < 0) log_dieusys(LOG_EXIT_SYS,"delete: ",treetmp) ; + + } + + tree_enable_disable(info,0) ; + + log_info("Deleted successfully: ",tree) ; +} + + +#include <stdio.h> + + +int ssexec_tree(int argc, char const *const *argv,char const *const *envp,ssexec_t *info) +{ + int r, current, create, allow, deny, enable, disable, remove, snap ; + + uid_t auids[256] = { 0 }, duids[256] = { 0 } ; + + char const *tree, *after_tree = 0 ; + + stralloc clone = STRALLOC_ZERO ; + + current = create = allow = deny = enable = disable = remove = snap = 0 ; + + { + subgetopt l = SUBGETOPT_ZERO ; + + for (;;) + { + int opt = getopt_args(argc,argv, ">" OPTS_TREE, &l) ; + if (opt == -1) break ; + if (opt == -2) log_die(LOG_EXIT_USER,"options must be set first") ; + switch (opt) + { + + case 'n' : create = 1 ; break ; + case 'a' : parse_uild_list(auids, l.arg) ; + allow = 1 ; + break ; + case 'd' : parse_uild_list(duids, l.arg) ; + deny = 1 ; + break ; + case 'c' : current = 1 ; break ; + case 'S' : after_tree = l.arg ; break ; + case 'E' : enable = 1 ; if (disable) log_usage(usage_tree) ; break ; + case 'D' : disable = 1 ; if (enable) log_usage(usage_tree) ; break ; + case 'R' : remove = 1 ; if (create) log_usage(usage_tree) ; break ; + case 'C' : if (remove) log_usage(usage_tree) ; + if (!auto_stra(&clone,l.arg)) log_die_nomem("stralloc") ; + snap = 1 ; + break ; + default : log_usage(usage_tree) ; + } + } + argc -= l.ind ; argv += l.ind ; + } + + if (argc < 1) log_usage(usage_tree) ; + + // make create the default option + if (!current && !create && !allow && !deny && !enable && !disable && !remove && !snap) + create = 1 ; + + info->treename.len = 0 ; + if (!auto_stra(&info->treename, argv[0])) + log_die_nomem("stralloc") ; + + tree = info->treename.s ; + + log_trace("sanitize ",tree,"..." ) ; + r = sanitize_tree(info,tree) ; + + if(!r && create) { + + ss_tree_seed_t seed = TREE_SEED_ZERO ; + /** set cleanup */ + cleantree = info->tree.s ; + log_trace("checking seed file: ",tree,"..." ) ; + + if (tree_seed_isvalid(tree)) { + + if (!tree_seed_setseed(&seed, tree, 0)) + log_dieu_nclean(LOG_EXIT_SYS, &cleanup, "parse seed file: ", tree) ; + + if (seed.enabled) + enable = 1 ; + + if (seed.current) + current = 1 ; + + if (seed.allow > 0) { + + parse_uild_list(auids, saseed.s + seed.allow) ; + + allow = 1 ; + } + + if (seed.deny > 0) { + + parse_uild_list(duids, saseed.s + seed.deny) ; + + deny = 1 ; + } + } + tree_seed_free(); + + log_trace("creating: ",info->tree.s,"..." ) ; + create_tree(info) ; + + log_trace("creating backup directory for: ", tree,"...") ; + create_backupdir(info) ; + /** unset cleanup */ + cleantree = 0 ; + + // set permissions + allow = 1 ; + + size_t dblen = info->tree.len ; + char newdb[dblen + SS_SVDIRS_LEN + 1] ; + auto_strings(newdb, info->tree.s, SS_SVDIRS) ; + + log_trace("compile: ",newdb,"/db/",tree,"..." ) ; + if (!db_compile(newdb,info->tree.s,tree,envp)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"compile ",newdb,"/db/",tree) ; + + r = 1 ; + create = 0 ; + log_info("Created successfully tree: ",tree) ; + } + + if ((!r && !create) || (!r && enable)) log_dieusys(LOG_EXIT_SYS,"find tree: ",info->tree.s) ; + if (r && create) log_dieu(LOG_EXIT_USER,"create: ",info->tree.s,": already exist") ; + + if (enable) + tree_enable_disable(info,1) ; + + if (disable) + tree_enable_disable(info,0) ; + + if (allow) + set_rules(info->tree.s,auids,1) ; + + if (deny) + set_rules(info->tree.s,duids,0) ; + + if(current) { + + log_trace("make: ",info->tree.s," as default ..." ) ; + if (!tree_switch_current(info->base.s,tree)) log_dieusys(LOG_EXIT_SYS,"set: ",info->tree.s," as default") ; + log_info("Set successfully: ",tree," as default") ; + } + + if (remove) + tree_remove(info) ; + + if (snap) { + + stralloc salist = STRALLOC_ZERO ; + ss_resolve_t res = RESOLVE_ZERO ; + + size_t syslen = info->base.len + SS_SYSTEM_LEN ; + size_t treelen = info->treename.len ; + size_t pos = 0 ; + + char system[syslen + 1] ; + auto_strings(system,info->base.s,SS_SYSTEM) ; + + size_t clone_target_len = syslen + 1 + clone.len ; + char clone_target[clone_target_len + 1] ; + auto_strings(clone_target,system,"/",clone.s) ; + + r = scan_mode(clone_target,S_IFDIR) ; + if ((r < 0) || r) log_die(LOG_EXIT_SYS,clone_target,": already exist") ; + + // clone main directory + log_trace("clone: ",tree," as: ",clone.s,"..." ) ; + if (!hiercopy(info->tree.s,clone_target)) + log_dieusys(LOG_EXIT_SYS,"copy: ",info->tree.s," to: ",clone_target) ; + + // clone backup directory + size_t clone_backup_len = syslen + SS_BACKUP_LEN + 1 + clone.len ; + char clone_backup[clone_backup_len + 1] ; + auto_strings(clone_backup,system,SS_BACKUP,"/",clone.s) ; + + char tree_backup[syslen + SS_BACKUP_LEN + 1 + treelen + 1] ; + auto_strings(tree_backup,system,SS_BACKUP,"/",tree) ; + + /* make cleantree pointing to the clone to be able to remove it + * in case of crach */ + cleantree = clone_target ; + + log_trace("clone backup of: ",tree," as: ",clone.s,"..." ) ; + if (!hiercopy(tree_backup,clone_backup)) + log_dieu_nclean(LOG_EXIT_SYS,&cleanup,"copy: ",tree_backup," to: ",clone_backup) ; + + // modify the resolve file to match the new name + // main directory first + char src_resolve[clone_target_len + SS_SVDIRS_LEN + SS_RESOLVE_LEN + 1] ; + auto_strings(src_resolve,clone_target,SS_SVDIRS,SS_RESOLVE) ; + + if (!sastr_dir_get(&salist,src_resolve,"",S_IFREG)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve) ; + + char clone_res[clone_target_len + SS_SVDIRS_LEN + 1] ; + auto_strings(clone_res,clone_target,SS_SVDIRS) ; + + FOREACH_SASTR(&salist, pos) { + + char *name = salist.s + pos ; + + if (!ss_resolve_read(&res,clone_res,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve,"/",name) ; + + tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ; + tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ; + tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ; + tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ; + + if (!ss_resolve_write(&res,clone_res,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; + } + + // rename db + char clone_db_old[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + treelen + 1] ; + auto_strings(clone_db_old,clone_target,SS_SVDIRS,SS_DB,"/",tree) ; + + char clone_db_new[clone_target_len + SS_SVDIRS_LEN + SS_DB_LEN + 1 + clone.len + 1] ; + auto_strings(clone_db_new,clone_target,SS_SVDIRS,SS_DB,"/",clone.s) ; + + log_trace("rename tree db: ",tree," as: ",clone.s,"..." ) ; + if (rename(clone_db_old,clone_db_new) == -1) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_old," to: ",clone_db_new) ; + + // backup directory + char src_resolve_backup[clone_backup_len + SS_RESOLVE_LEN + 1] ; + auto_strings(src_resolve_backup,clone_backup,SS_RESOLVE) ; + + salist.len = 0 ; + + /** main and backup can be different,so rebuild the list + * Also, a backup directory can be empty, check it first */ + r = scan_mode(src_resolve_backup,S_IFDIR) ; + if (r == 1) { + + if (!sastr_dir_get(&salist,src_resolve_backup,"",S_IFREG)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"get resolve file at: ",src_resolve_backup) ; + + pos = 0 ; + FOREACH_SASTR(&salist, pos) { + + char *name = salist.s + pos ; + + if (!ss_resolve_read(&res,clone_backup,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"read resolve file of: ",src_resolve_backup,"/",name) ; + + tree_modify_resolve(&res,SS_RESOLVE_ENUM_RUNAT,tree,clone.s) ; + tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREENAME,tree,clone.s) ; + tree_modify_resolve(&res,SS_RESOLVE_ENUM_TREE,tree,clone.s) ; + tree_modify_resolve(&res,SS_RESOLVE_ENUM_STATE,tree,clone.s) ; + + if (!ss_resolve_write(&res,clone_backup,name)) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"write resolve file of: ",src_resolve,"/",name) ; + } + // rename db + char clone_db_backup_old[clone_backup_len + SS_DB_LEN + 1 + treelen + 1] ; + auto_strings(clone_db_backup_old,clone_backup,SS_DB,"/",tree) ; + + char clone_db_backup_new[clone_backup_len + SS_DB_LEN + 1 + clone.len + 1] ; + auto_strings(clone_db_backup_new,clone_backup,SS_DB,"/",clone.s) ; + + log_trace("rename tree backup db: ",tree," as: ",clone.s,"..." ) ; + if (rename(clone_db_backup_old,clone_db_backup_new) == -1) + log_dieusys_nclean(LOG_EXIT_SYS,&cleanup,"rename: ",clone_db_backup_old," to: ",clone_db_backup_new) ; + } + + stralloc_free(&salist) ; + ss_resolve_free(&res) ; + + log_info("Cloned successfully: ",tree," to ",clone.s) ; + } + + if (after_tree) { + + stralloc contents = STRALLOC_ZERO ; + stralloc tmp = STRALLOC_ZERO ; + int befirst = obstr_equal(tree,after_tree) ; + size_t baselen = info->base.len, pos = 0 ; + char ste[baselen + SS_SYSTEM_LEN + 1] ; + auto_strings(ste,info->base.s,SS_SYSTEM) ; + + int enabled = tree_cmd_state(VERBOSITY,"-s",tree) ; + if (enabled != 1) + log_die(LOG_EXIT_USER,"tree: ",tree," is not enabled") ; + + enabled = tree_cmd_state(VERBOSITY,"-s",after_tree) ; + if (enabled != 1) + log_die(LOG_EXIT_USER,"tree: ",after_tree," is not enabled") ; + + r = tree_cmd_state(VERBOSITY,"-d",tree) ; + if (!r) log_dieusys(LOG_EXIT_SYS,"disable: ",tree," at: ",ste,SS_STATE) ; + + r = file_readputsa(&tmp,ste,SS_STATE + 1) ; + if(!r) log_dieusys(LOG_EXIT_SYS,"open: ", ste,SS_STATE) ; + + /** if you have only one tree enabled, the state file will be + * empty because we disable it before reading the file(see line 803). + * This will make a crash at sastr_? call. + * So write directly the name of the tree at state file. */ + + if (tmp.len) { + + if (!sastr_rebuild_in_oneline(&tmp) || + !sastr_clean_element(&tmp)) + log_dieu(LOG_EXIT_SYS,"rebuild state list") ; + + pos = 0 ; + FOREACH_SASTR(&tmp, pos) { + + char *name = tmp.s + pos ; + + /* e.g 66-tree -S root root -> meaning root need to + * be the first to start */ + if ((befirst) && (pos == 0)) + { + if (!auto_stra(&contents,tree,"\n")) + log_dieusys(LOG_EXIT_SYS,"stralloc") ; + } + if (!auto_stra(&contents,name,"\n")) + log_dieusys(LOG_EXIT_SYS,"stralloc") ; + + if (obstr_equal(name,after_tree)) + { + if (!auto_stra(&contents,tree,"\n")) + log_dieusys(LOG_EXIT_SYS,"stralloc") ; + } + } + + } else { + + if (!auto_stra(&contents,tree,"\n")) + log_dieusys(LOG_EXIT_SYS,"stralloc") ; + } + + if (!file_write_unsafe(ste,SS_STATE + 1,contents.s,contents.len)) + log_dieusys(LOG_EXIT_ZERO,"write: ",ste,SS_STATE) ; + + log_info("Ordered successfully: ",tree," starts after tree: ",after_tree) ; + } + + stralloc_free(&clone) ; + + return 0 ; +} -- GitLab