Newer
Older
*
* 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>

Eric Vidal
committed
#include <stdlib.h>//free
#include <oblibs/log.h>
#include <oblibs/types.h>
#include <oblibs/directory.h>
#include <oblibs/files.h>
#include <oblibs/string.h>
#include <oblibs/sastr.h>

Eric Vidal
committed
#include <oblibs/graph.h>
#include <skalibs/sgetopt.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/enum.h>
#include <66/state.h>
#include <66/resolve.h>

Eric Vidal
committed
#include <66/graph.h>
#include <66/sanitize.h>
#include <s6/supervise.h>

Eric Vidal
committed
#define TREE_COLON_DELIM ':'
#define TREE_COMMA_DELIM ','

Eric Vidal
committed
#define TREE_MAXOPTS 9

Eric Vidal
committed
#define tree_checkopts(n) if (n >= TREE_MAXOPTS) log_die(LOG_EXIT_USER, "too many -o options")

Eric Vidal
committed
typedef struct tree_opts_map_s tree_opts_map_t ;
struct tree_opts_map_s
{
char const *str ;
int const id ;
} ;
typedef enum enum_tree_opts_e enum_tree_opts_t, *enum_tree_opts_t_ref ;
enum enum_ns_opts_e
{
TREE_OPTS_DEPENDS = 0,
TREE_OPTS_REQUIREDBY,
TREE_OPTS_RENAME,

Eric Vidal
committed
TREE_OPTS_GROUPS,
TREE_OPTS_NOSEED,
TREE_OPTS_ALLOW,
TREE_OPTS_DENY,
TREE_OPTS_CLONE,

Eric Vidal
committed
TREE_OPTS_ENDOFKEY
} ;
tree_opts_map_t const tree_opts_table[] =
{

Eric Vidal
committed
{ .str = "depends", .id = TREE_OPTS_DEPENDS },
{ .str = "requiredby", .id = TREE_OPTS_REQUIREDBY },
{ .str = "rename", .id = TREE_OPTS_RENAME },
{ .str = "groups", .id = TREE_OPTS_GROUPS },
{ .str = "noseed", .id = TREE_OPTS_NOSEED },
{ .str = "allow", .id = TREE_OPTS_ALLOW },
{ .str = "deny", .id = TREE_OPTS_DENY },
{ .str = "clone", .id = TREE_OPTS_CLONE },

Eric Vidal
committed
{ .str = 0 }
} ;

Eric Vidal
committed
typedef struct tree_what_s tree_what_t, *tree_what_t_ref ;
struct tree_what_s

Eric Vidal
committed
{

Eric Vidal
committed
uint8_t create ;
uint8_t depends ;
uint8_t requiredby ;
uint8_t allow ;
uint8_t deny ;
uint8_t enable ;
uint8_t disable ;
uint8_t remove ;
uint8_t clone ;
uint8_t groups ;
uint8_t current ;
uint8_t rename ;
uint8_t noseed ;
char gr[6] ;
char sclone[100] ;
uid_t auids[256] ;
uid_t duids[256] ;
uint8_t ndepends ; // only used if the term none is passed as dependencies
uint8_t nrequiredby ; // only used if the term none is passed as dependencies
uint8_t nopts ;

Eric Vidal
committed
} ;

Eric Vidal
committed
#define TREE_WHAT_ZERO { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, { 0 }, 1, 1, 0 }
tree_what_t what_init(void)
{
log_flow() ;
tree_what_t what = TREE_WHAT_ZERO ;

Eric Vidal
committed
memset(what.auids, 0, 256 * sizeof(uid_t));
memset(what.duids, 0, 256 * sizeof(uid_t)) ;
return what ;
}
void tree_enable_disable(graph_t *g, char const *base, char const *treename, uint8_t action) ;

Eric Vidal
committed
static void check_identifier(char const *name)
{
if (!memcmp(name, SS_MASTER + 1, 6))
log_die(LOG_EXIT_USER,"tree name: ",name,": starts with reserved prefix Master") ;
char str[UINT_FMT] ;
str[uint_fmt(str, SS_MAX_TREENAME)] = 0 ;
if (strlen(name) > SS_MAX_TREENAME)
log_die(LOG_EXIT_USER,"tree name is too long -- it can not exceed ", str) ;

Eric Vidal
committed
}

Eric Vidal
committed
static ssize_t tree_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 ;
}

Eric Vidal
committed
static void tree_parse_options_groups(char *store, char const *str)
{
log_flow() ;

Eric Vidal
committed
uid_t uid = getuid() ;

Eric Vidal
committed
if (strcmp(str, TREE_GROUPS_BOOT) &&
strcmp(str, TREE_GROUPS_ADM) &&
strcmp(str, TREE_GROUPS_USER) &&
strcmp(str, "none"))
log_die(LOG_EXIT_SYS, "invalid group: ", str) ;

Eric Vidal
committed
if (!uid && (!strcmp(str, TREE_GROUPS_USER)))
log_die(LOG_EXIT_SYS, "Only regular user can use this group") ;

Eric Vidal
committed
else if (uid && (!strcmp(str, TREE_GROUPS_ADM) || !strcmp(str, TREE_GROUPS_BOOT)))
log_die(LOG_EXIT_SYS, "Only root user can use this group") ;

Eric Vidal
committed
auto_strings(store, str) ;

Eric Vidal
committed
void tree_parse_uid_list(uid_t *uids, char const *str)
{
log_flow() ;
size_t pos = 0 ;
stralloc sa = STRALLOC_ZERO ;

Eric Vidal
committed
if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM))
log_dieu(LOG_EXIT_SYS,"parse uid list") ;

Eric Vidal
committed
uid_t owner = getuid() ;
/** special case, we don't know which user want to use

Eric Vidal
committed
* the tree, we need a general name to allow all users.
* 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 ;

Eric Vidal
committed
log_dieu(LOG_EXIT_SYS,"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) ;
}

Eric Vidal
committed
stralloc_free(&sa) ;

Eric Vidal
committed
static void tree_parse_options_depends(graph_t *g, ssexec_t *info, char const *str, uint8_t requiredby, tree_what_t *what)
{
log_flow() ;

Eric Vidal
committed
size_t pos = 0 ;
char *name = 0 ;
stralloc sa = STRALLOC_ZERO ;

Eric Vidal
committed
if (!sastr_clean_string_wdelim(&sa, str, TREE_COMMA_DELIM))
log_dieu(LOG_EXIT_SYS,"clean sub options") ;

Eric Vidal
committed
if (sastr_cmp(&sa, "none") >= 0) {
if (!requiredby)
what->ndepends = 0 ;
else
what->nrequiredby = 0 ;

Eric Vidal
committed
stralloc_free(&sa) ;
return ;

Eric Vidal
committed
FOREACH_SASTR(&sa, pos) {

Eric Vidal
committed
name = sa.s + pos ;
r = tree_isvalid(info->base.s, name) ;
if (r < 0)
log_diesys(LOG_EXIT_SYS, "invalid treename") ;

Eric Vidal
committed
/** We only creates trees declared as dependency.
* TreeA depends on TreeB, we create TreeB
* if it doesn't exist yet */
if (!r && !requiredby) {
ssexec_t newinfo = SSEXEC_ZERO ;
if (!auto_stra(&newinfo.base, info->base.s) ||
!auto_stra(&newinfo.treename, name))
log_die_nomem("stralloc") ;
newinfo.owner = info->owner ;
newinfo.prog = info->prog ;
newinfo.help = info->help ;
newinfo.usage = info->usage ;
newinfo.opt_color = info->opt_color ;

Eric Vidal
committed
int nwhat = what->noseed ? 2 : 0 ;
int nargc = 3 + nwhat ;

Eric Vidal
committed
char const *newargv[nargc] ;
uint8_t m = 0 ;

Eric Vidal
committed
if (nwhat) {
newargv[m++] = "-o" ;
newargv[m++] = "noseed" ;
}

Eric Vidal
committed
newargv[m++] = name ;
newargv[m++] = 0 ;
if (ssexec_tree_admin(nargc, newargv, &newinfo))

Eric Vidal
committed
log_dieusys(LOG_EXIT_SYS, "create tree: ", name) ;

Eric Vidal
committed
ssexec_free(&newinfo) ;

Eric Vidal
committed
r = 1 ;

Eric Vidal
committed
}

Eric Vidal
committed
if (!requiredby) {

Eric Vidal
committed
if (!graph_vertex_add_with_edge(g, info->treename.s, name))
log_die(LOG_EXIT_SYS,"add edge: ", name, " to vertex: ", info->treename.s) ;

Eric Vidal
committed
} else if (r) {
/** if TreeA is requiredby TreeB, we don't want to create TreeB.
* We only manages it if it exist yet */
if (!graph_vertex_add_with_requiredby(g, info->treename.s, name))
log_die(LOG_EXIT_SYS,"add requiredby: ", name, " to: ", info->treename.s) ;
}

Eric Vidal
committed
stralloc_free(&sa) ;
}

Eric Vidal
committed
static void tree_parse_options(graph_t *g, char const *str, ssexec_t *info, tree_what_t *what)

Eric Vidal
committed
{

Eric Vidal
committed
log_flow() ;

Eric Vidal
committed
return ;

Eric Vidal
committed
size_t pos = 0, len = 0 ;
ssize_t r ;
char *line = 0, *key = 0, *val = 0 ;
stralloc sa = STRALLOC_ZERO ;

Eric Vidal
committed
tree_opts_map_t const *t ;

Eric Vidal
committed

Eric Vidal
committed
if (!sastr_clean_string_wdelim(&sa, str, TREE_COLON_DELIM))

Eric Vidal
committed
log_dieu(LOG_EXIT_SYS,"clean options") ;
unsigned int n = sastr_len(&sa), nopts = 0 , old ;
tree_checkopts(n) ;
FOREACH_SASTR(&sa, pos) {
line = sa.s + pos ;
t = tree_opts_table ;
old = nopts ;
for (; t->str ; t++) {
len = strlen(line) ;
char tmp[len + 1] ;
r = tree_get_key(tmp,line) ;

Eric Vidal
committed
if (r == -1 && strcmp(line, "noseed"))

Eric Vidal
committed
log_die(LOG_EXIT_USER,"invalid key: ", line) ;

Eric Vidal
committed
if (!strcmp(line, "noseed")) {
key = line ;
} else {
key = tmp ;
val = line + r ;
}

Eric Vidal
committed
if (!strcmp(key, t->str)) {
switch(t->id) {
case TREE_OPTS_DEPENDS :

Eric Vidal
committed
tree_parse_options_depends(g, info, val, 0, what) ;
what->depends = 1 ;
break ;

Eric Vidal
committed

Eric Vidal
committed
case TREE_OPTS_REQUIREDBY :

Eric Vidal
committed

Eric Vidal
committed
tree_parse_options_depends(g, info, val, 1, what) ;
what->requiredby = 1 ;
break ;

Eric Vidal
committed

Eric Vidal
committed
case TREE_OPTS_RENAME:
what->rename = 1 ;
break ;

Eric Vidal
committed

Eric Vidal
committed
case TREE_OPTS_GROUPS:

Eric Vidal
committed

Eric Vidal
committed
tree_parse_options_groups(what->gr, val) ;
what->groups = 1 ;

Eric Vidal
committed
break ;

Eric Vidal
committed
case TREE_OPTS_NOSEED:

Eric Vidal
committed

Eric Vidal
committed
what->noseed = 1 ;
break ;
case TREE_OPTS_ALLOW:
tree_parse_uid_list(what->auids, val) ;
what->allow = 1 ;
break ;
case TREE_OPTS_DENY:
tree_parse_uid_list(what->duids, val) ;
what->deny = 1 ;
break ;
case TREE_OPTS_CLONE:

Eric Vidal
committed

Eric Vidal
committed
if (strlen(val) > 99)
log_die(LOG_EXIT_USER, "clone name cannot exceed 100 characters") ;
auto_strings(what->sclone, val) ;
what->clone = 1 ;

Eric Vidal
committed
break ;
default :
break ;
}
nopts++ ;
}
}
if (old == nopts)
log_die(LOG_EXIT_SYS,"invalid option: ",line) ;
}

Eric Vidal
committed

Eric Vidal
committed
stralloc_free(&sa) ;
}

Eric Vidal
committed
void tree_parse_seed(char const *treename, tree_seed_t *seed, tree_what_t *what)

Eric Vidal
committed
log_flow() ;

Eric Vidal
committed
log_trace("checking seed file: ", treename, "..." ) ;

Eric Vidal
committed
if (tree_seed_isvalid(treename)) {
if (!tree_seed_setseed(seed, treename))
log_dieu(LOG_EXIT_SYS, "parse seed file: ", treename) ;

Eric Vidal
committed
if (seed->depends)
what->depends = 1 ;

Eric Vidal
committed
if (seed->requiredby)
what->requiredby = 1 ;

Eric Vidal
committed
if (seed->disen)
what->enable = 1 ;

Eric Vidal
committed
if (seed->allow > 0) {
tree_parse_uid_list(what->auids, seed->sa.s + seed->allow) ;
what->allow = 1 ;

Eric Vidal
committed
if (seed->deny > 0) {

Eric Vidal
committed
tree_parse_uid_list(what->duids, seed->sa.s + seed->deny) ;
what->deny = 1 ;
}

Eric Vidal
committed
if (seed->current)
what->current = 1 ;

Eric Vidal
committed
if (seed->groups) {

Eric Vidal
committed
tree_parse_options_groups(what->gr, seed->sa.s + seed->groups) ;
what->groups = 1 ;
}
}
}
void tree_groups(graph_t *graph, char const *base, char const *treename, char const *value)

Eric Vidal
committed
{
log_flow() ;

Eric Vidal
committed
resolve_tree_t tres = RESOLVE_TREE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;

Eric Vidal
committed
char pack[UINT_FMT] ;
char const *val ;

Eric Vidal
committed
log_trace("set: ", treename," to group ..." ) ;

Eric Vidal
committed
if (!strcmp(value, "none")) {

Eric Vidal
committed
goto write ;
} else if (!strcmp(value, "boot")) {
/** a tree on groups boot cannot be enabled */
tree_enable_disable(graph, base, treename, 0) ;
}

Eric Vidal
committed
nb = 1 ;
val = value ;
write:
uint_pack(pack, nb) ;
pack[uint_fmt(pack, nb)] = 0 ;
if (resolve_read_g(wres, base, treename) <= 0)
log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", treename) ;

Eric Vidal
committed
if (!resolve_modify_field(wres, E_RESOLVE_TREE_GROUPS, val) ||
!resolve_modify_field(wres, E_RESOLVE_TREE_NGROUPS, pack))

Eric Vidal
committed
log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ;
if (!resolve_write_g(wres, base, treename))
log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", treename) ;

Eric Vidal
committed
resolve_free(wres) ;
log_info("Set successfully: ", treename, " to group: ", value) ;
}
void tree_master_modify_contents(char const *base)
stralloc sa = STRALLOC_ZERO ;
resolve_tree_master_t mres = RESOLVE_TREE_MASTER_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE_MASTER, &mres) ;
size_t baselen = strlen(base) ;
char solve[baselen + SS_SYSTEM_LEN + SS_RESOLVE_LEN + 1] ;
char const *exclude[2] = { SS_MASTER + 1, 0 } ;
log_trace("modify field contents of resolve Master file of trees") ;
auto_strings(solve, base, SS_SYSTEM, SS_RESOLVE) ;
if (!sastr_dir_get(&sa, solve, exclude, S_IFREG))
log_dieu(LOG_EXIT_SYS, "get resolve files of trees") ;
size_t ncontents = sa.len ? sastr_nelement(&sa) : 0 ;
if (ncontents)
if (!sastr_rebuild_in_oneline(&sa))
log_dieu(LOG_EXIT_SYS, "rebuild stralloc") ;
if (resolve_read_g(wres, base, SS_MASTER + 1) <= 0)
log_dieusys(LOG_EXIT_SYS, "read resolve Master file of trees") ;
mres.ncontents = (uint32_t)ncontents ;
if (ncontents)
mres.contents = resolve_add_string(wres, sa.s) ;
else
mres.contents = resolve_add_string(wres, "") ;
if (!resolve_write_g(wres, base, SS_MASTER + 1))
log_dieusys(LOG_EXIT_SYS, "write resolve Master file of trees") ;
stralloc_free(&sa) ;
resolve_free(wres) ;
}
void tree_create(graph_t *g, ssexec_t *info, tree_what_t *what)

Eric Vidal
committed
{
log_flow() ;
resolve_tree_t tres = RESOLVE_TREE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
tree_seed_t seed = TREE_SEED_ZERO ;
resolve_init(wres) ;
/** check seed file */
if (!what->noseed)
tree_parse_seed(info->treename.s, &seed, what) ;
log_trace("creating: ", info->treename.s, "..." ) ;

Eric Vidal
committed
// set permissions
what->allow = 1 ;
tres.name = resolve_add_string(wres, info->treename.s) ;
tres.groups = resolve_add_string(wres, info->owner ? TREE_GROUPS_USER : TREE_GROUPS_ADM) ;
tres.ngroups = 1 ;
log_trace("write resolve file of: ", info->treename.s) ;
if (!resolve_write_g(wres, info->base.s, info->treename.s))
log_dieu(LOG_EXIT_SYS, "write resolve file of: ", info->treename.s) ;

Eric Vidal
committed
/** Check the length of seed.sa.len: If the seed file is not parsed at this point,
* seed.sa.s + seed.depends is empty, which can lead to a segmentation fault
* when the -o option is passed at the command line. However, we have already gone
* through the tree_parse_options_depends in such cases. */
if (what->depends && seed.sa.len)

Eric Vidal
committed
tree_parse_options_depends(g, info, seed.sa.s + seed.depends, 0, what) ;
if (what->requiredby && seed.sa.len)

Eric Vidal
committed
tree_parse_options_depends(g, info, seed.sa.s + seed.requiredby, 1, what) ;
tree_master_modify_contents(info->base.s) ;

Eric Vidal
committed
resolve_free(wres) ;
tree_seed_free(&seed) ;
log_info("Created successfully tree: ", info->treename.s) ;
}
void tree_enable_disable_deps(graph_t *g,char const *base, char const *treename, uint8_t action)
{
log_flow() ;

Eric Vidal
committed
stralloc sa = STRALLOC_ZERO ;
if (graph_matrix_get_edge_g_sa(&sa, g, treename, action ? 0 : 1, 0) < 0)

Eric Vidal
committed
log_dieu(LOG_EXIT_SYS, "get ", action ? "dependencies" : "required by" ," of: ", treename) ;
size_t len = sastr_nelement(&sa) ;
memset(v, 0, (len + 1) * sizeof(unsigned int)) ;

Eric Vidal
committed
if (sa.len) {
FOREACH_SASTR(&sa, pos) {

Eric Vidal
committed
char *name = sa.s + pos ;
tree_enable_disable(g, base, name, action) ;

Eric Vidal
committed
}

Eric Vidal
committed
}
}
stralloc_free(&sa) ;
}
/** @action -> 0 disable
* @action -> 1 enable */
void tree_enable_disable(graph_t *g, char const *base, char const *treename, uint8_t action)
{
log_flow() ;
resolve_tree_t tres = RESOLVE_TREE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
if (resolve_read_g(wres, base, treename) <= 0)
log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", treename) ;
uint8_t disen = tres.enabled ;

Eric Vidal
committed

Eric Vidal
committed
if ((disen && !action) || (!disen && action)){
log_trace(!action ? "disable " : "enable ", treename, "...") ;

Eric Vidal
committed
if (tree_ongroups(base, treename, TREE_GROUPS_BOOT) && action) {
log_1_warn(treename," is a part of group ", TREE_GROUPS_BOOT," -- ignoring enable request") ;
return ;

Eric Vidal
committed
tres.enabled = action ;
if (!resolve_write_g(wres, base, treename))
log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", treename) ;

Eric Vidal
committed
tree_enable_disable_deps(g, base, treename, action) ;

Eric Vidal
committed
log_info(!action ? "Disabled" : "Enabled"," successfully tree: ", treename) ;

Eric Vidal
committed
} else {

Eric Vidal
committed
log_info("Already ",!action ? "disabled" : "enabled"," tree: ",treename) ;

Eric Vidal
committed
resolve_free(wres) ;
}

Eric Vidal
committed
/* !deps -> add
* deps -> remove */
void tree_depends_requiredby(graph_t *g, char const *base, char const *treename, uint8_t requiredby, uint8_t none, char const *deps)
{
log_flow() ;
resolve_tree_t tres = RESOLVE_TREE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
size_t pos = 0, len = 0, nb = 0, element = 0 ;
uint8_t ewhat = !requiredby ? E_RESOLVE_TREE_DEPENDS : E_RESOLVE_TREE_REQUIREDBY ;
uint8_t nwhat = !requiredby ? E_RESOLVE_TREE_NDEPENDS : E_RESOLVE_TREE_NREQUIREDBY ;

Eric Vidal
committed
stralloc sa = STRALLOC_ZERO ;
char pack[UINT_FMT] ;
log_trace("manage ", !requiredby ? "dependencies" : "required by", " for tree: ", treename, "..." ) ;
if (graph_matrix_get_edge_g_sorted_sa(&sa, g, treename, requiredby, 0) < 0)

Eric Vidal
committed
log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", treename) ;
size_t vlen = sastr_nelement(&sa) ;

Eric Vidal
committed
memset(v, 0, (vlen + 1) * sizeof(unsigned int)) ;

Eric Vidal
committed
len = sa.len ;
{
char t[len + 1] ;
sastr_to_char(t, &sa) ;
sa.len = 0 ;

Eric Vidal
committed
for(; pos < len ; pos += strlen(t + pos) + 1, element++) {

Eric Vidal
committed

Eric Vidal
committed

Eric Vidal
committed
char *name = t + pos ;

Eric Vidal
committed

Eric Vidal
committed
if (!none) {

Eric Vidal
committed

Eric Vidal
committed
if (!graph_edge_remove_g(g, treename, name))
log_dieu(LOG_EXIT_SYS,"remove edge: ", name, " from vertex: ", treename);

Eric Vidal
committed

Eric Vidal
committed
} else {

Eric Vidal
committed

Eric Vidal
committed
if (deps) {
if (!strcmp(name, deps)) {

Eric Vidal
committed
continue ;
}
}

Eric Vidal
committed

Eric Vidal
committed
if (!auto_stra(&sa, name, " "))
log_die_nomem("stralloc") ;

Eric Vidal
committed
nb++ ;
}

Eric Vidal
committed
}
}

Eric Vidal
committed
}

Eric Vidal
committed
if (sa.len)
sa.len-- ; //remove last " "
if (!stralloc_0(&sa))
log_die_nomem("stralloc") ;

Eric Vidal
committed

Eric Vidal
committed
uint_pack(pack, nb) ;
pack[uint_fmt(pack, nb)] = 0 ;
if (resolve_read_g(wres, base, treename) <= 0)
log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", treename) ;

Eric Vidal
committed
if (!resolve_modify_field(wres, ewhat, sa.s) ||
!resolve_modify_field(wres, nwhat, pack))
log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ;
if (!resolve_write_g(wres, base, treename))
log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", treename) ;

Eric Vidal
committed
if (!none) {

Eric Vidal
committed

Eric Vidal
committed
graph_free_matrix(g) ;
graph_free_sort(g) ;
if (!graph_matrix_build(g))
log_die(LOG_EXIT_SYS, "build the graph") ;
if (!graph_matrix_analyze_cycle(g))
log_die(LOG_EXIT_SYS, "found cycle") ;
if (!graph_matrix_sort(g))
log_die(LOG_EXIT_SYS, "sort the graph") ;

Eric Vidal
committed

Eric Vidal
committed
stralloc_free(&sa) ;
resolve_free(wres) ;

Eric Vidal
committed
log_info(requiredby ? "Required by " : "Dependencies ", "successfully managed for tree: ", treename) ;
}

Eric Vidal
committed
void tree_depends_requiredby_deps(graph_t *g, char const *base, char const *treename, uint8_t requiredby, uint8_t none, char const *deps)
{
log_flow() ;
size_t baselen = strlen(base), pos = 0, len = 0, element = 0 ;

Eric Vidal
committed
stralloc sa = STRALLOC_ZERO ;
char solve[baselen + SS_SYSTEM_LEN + 1] ;
if (graph_matrix_get_edge_g_sorted_sa(&sa, g, treename, requiredby, 0) < 0)

Eric Vidal
committed
log_dieu(LOG_EXIT_SYS,"get sorted ", requiredby ? "required by" : "dependency", " list of tree: ", treename) ;

Eric Vidal
committed
size_t vlen = sastr_nelement(&sa) ;
memset(v, 0, (vlen + 1) * sizeof(unsigned int)) ;

Eric Vidal
committed
auto_strings(solve, base, SS_SYSTEM) ;

Eric Vidal
committed
len = sa.len ;
char t[len + 1] ;

Eric Vidal
committed
sastr_to_char(t, &sa) ;
for(; pos < len ; pos += strlen(t + pos) + 1, element++) {

Eric Vidal
committed
char *name = t + pos ;

Eric Vidal
committed
tree_depends_requiredby(g, base, name, !requiredby, none, deps) ;

Eric Vidal
committed
}
}

Eric Vidal
committed
stralloc_free(&sa) ;
}

Eric Vidal
committed
/** @what -> 0 deny
* @what -> 1 allow */
void tree_rules(char const *base, char const *treename, uid_t *uids, uint8_t what)
{
log_flow() ;

Eric Vidal
committed
int r ;
size_t uidn = uids[0], pos = 0 ;

Eric Vidal
committed
uid_t owner = MYUID ;
char pack[256] ;
stralloc sa = STRALLOC_ZERO ;
resolve_tree_t tres = RESOLVE_TREE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;

Eric Vidal
committed
log_trace("set ", !what ? "denied" : "allowed", " user for tree: ", treename, "..." ) ;
if (resolve_read_g(wres, base, treename) <= 0)
log_dieusys(LOG_EXIT_SYS, "read resolve file of: ", treename) ;

Eric Vidal
committed
if (tres.nallow)
if (!sastr_clean_string(&sa, tres.sa.s + tres.allow))
log_dieu(LOG_EXIT_SYS, "clean string") ;
/** fresh creation of the tree */
if (!tres.nallow) {
if (!uids[0]) {
uids[0] = 1 ;
uids[1] = owner ;
} else {
/** command can be 66 tree -a <account> <tree>

Eric Vidal
committed
* where <tree> doesn't exist yet.
* Keep the -a option value and append the owner
* of the process at the end of the list. */
uids[0]++ ;
uids[uidn + 1] = owner ;

Eric Vidal
committed
uidn++ ;
}
uint32_pack(pack,uids[pos+1]) ;
pack[uint_fmt(pack,uids[pos+1])] = 0 ;
if (!sastr_add_string(&sa, pack))
log_die_nomem("stralloc") ;

Eric Vidal
committed
log_trace("user: ", pack, " is allowed for tree: ", treename) ;

Eric Vidal
committed
if (owner == uids[pos+1]) {
log_1_warn("you cannot deny yourself -- ignoring request") ;

Eric Vidal
committed
continue ;
if (!sastr_remove_element(&sa, pack))
log_dieu(LOG_EXIT_SYS, "remove: ", pack, " from list") ;

Eric Vidal
committed

Eric Vidal
committed
log_trace("user: ", pack, " is denied for tree: ", treename) ;

Eric Vidal
committed
}
if (!sastr_rebuild_in_oneline(&sa))
log_dieu(LOG_EXIT_SYS, "rebuild string") ;

Eric Vidal
committed
if (!resolve_modify_field(wres, E_RESOLVE_TREE_ALLOW, sa.s))

Eric Vidal
committed
log_dieusys(LOG_EXIT_SYS, "modify resolve file of: ", treename) ;
if (!resolve_write_g(wres, base, treename))

Eric Vidal
committed
log_dieusys(LOG_EXIT_SYS, "write resolve file of: ", treename) ;
stralloc_free(&sa) ;
resolve_free(wres) ;
log_info("Permissions rules set successfully for tree: ", treename) ;
}
static void tree_service_switch_contents(char const *base, char const *treesrc, char const *treedst, ssexec_t *info)

Eric Vidal
committed
{
size_t pos = 0 ;
resolve_tree_t tres = RESOLVE_TREE_ZERO ;
resolve_wrapper_t_ref wres = resolve_set_struct(DATA_TREE, &tres) ;
resolve_service_t res = RESOLVE_SERVICE_ZERO ;
resolve_wrapper_t_ref swres = resolve_set_struct(DATA_SERVICE, &res) ;

Eric Vidal
committed
if (!resolve_get_field_tosa_g(&sa, base, treesrc, DATA_TREE, E_RESOLVE_TREE_CONTENTS))
log_dieu(LOG_EXIT_SYS, "get contents list of tree: ", treesrc) ;

Eric Vidal
committed
FOREACH_SASTR(&sa, pos) {
log_trace("switch service: ", sa.s + pos, " to tree: ", treedst) ;
tree_service_add(treedst, sa.s + pos, info) ;
if (!resolve_modify_field_g(swres, base, sa.s + pos, E_RESOLVE_SERVICE_TREENAME, treedst))
log_dieu(LOG_EXIT_SYS, "modify resolve file of: ", sa.s + pos) ;
}

Eric Vidal
committed
stralloc_free(&sa) ;
resolve_free(wres) ;
void tree_remove(graph_t *g, char const *base, char const *treename, ssexec_t *info)

Eric Vidal
committed
int r ;
char tree[SS_MAX_TREENAME + 1] ;
char *current = SS_DEFAULT_TREENAME ;

Eric Vidal
committed
log_trace("delete: ", treename, "..." ) ;

Eric Vidal
committed
tree_enable_disable(g, base, treename, 0) ;
/** depends */
tree_depends_requiredby_deps(g, base, treename, 0, 1, treename) ;
/** requiredby */
tree_depends_requiredby_deps(g, base, treename, 1, 1, treename) ;
if (tree_iscurrent(base, treename)) {
/** This symlink must be valid in any case to avoid crashing the sanitize_system process.
* If it is not valid, at least point it to the SS_DEFAULT_TREENAME,
* as this tree is automatically created at every 66 command invocation
* if it does not exist yet. */
log_warn("tree ",treename, " is marked as default -- switch default to: ", SS_DEFAULT_TREENAME) ;
if (!tree_switch_current(base, SS_DEFAULT_TREENAME))
log_dieusys(LOG_EXIT_SYS,"set: ", SS_DEFAULT_TREENAME, " as default") ;
log_info("Set successfully: ", SS_DEFAULT_TREENAME," as default") ;
} else {
r = tree_find_current(tree, base) ;
if (r < 0)
log_dieu(LOG_EXIT_SYS, "find default tree") ;
if (r)
current = tree ;
else
current = SS_DEFAULT_TREENAME ;

Eric Vidal
committed
tree_service_switch_contents(base, treename, current, info) ;
log_trace("remove resolve file of tree: ", treename) ;
resolve_remove_g(base, treename, DATA_TREE) ;

Eric Vidal
committed
log_info("Deleted successfully: ", treename) ;
}
void tree_current(ssexec_t *info)
{
log_trace("mark: ", info->treename.s," as default ..." ) ;
if (!tree_switch_current(info->base.s, info->treename.s))
log_dieusys(LOG_EXIT_SYS,"set: ", info->treename.s, " as default") ;
log_info("Set successfully: ", info->treename.s," as default") ;
}
void tree_clone(char const *clone, ssexec_t *info)
{
log_flow() ;