Skip to content
Snippets Groups Projects
tree_seed.c 8.24 KiB
/*
 * 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(tree_seed_t *seed, char const *seedpath)
{
    log_flow() ;

    int r, e = 0 ;

    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 ;
        }

    }

    e = 1 ;
    err:
        stralloc_free(&sa) ;
        return e ;
}

/** @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(tree_seed_t *seed, uint8_t check_service)
{
    log_flow() ;

    int e = 0 ;
    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) ;
    }
    */
    e = 1 ;
    err:
        stralloc_free(&sv) ;
        return e ;
}

int tree_seed_setseed(tree_seed_t *seed, char const *treename, uint8_t check_service)
{
    log_flow() ;

    int e = 0 ;
    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 ;

    e = 1 ;
    err:
        stralloc_free(&src) ;
        return e ;
}