/* * ss_utils.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/utils.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <pwd.h> #include <errno.h> #include <oblibs/log.h> #include <oblibs/files.h> #include <oblibs/sastr.h> #include <oblibs/string.h> #include <skalibs/genalloc.h> #include <skalibs/stralloc.h> #include <skalibs/types.h> #include <skalibs/djbunix.h> #include <66/config.h> #include <66/constants.h> #include <66/resolve.h> #include <66/parser.h> #include <s6/supervise.h> sv_alltype const sv_alltype_zero = SV_ALLTYPE_ZERO ; sv_name_t const sv_name_zero = SV_NAME_ZERO ; keynocheck const keynocheck_zero = KEYNOCHECK_ZERO ; ss_resolve_t const ss_resolve_zero = RESOLVE_ZERO ; /** this following function come from Laurent Bercot * author of s6 library all rights reserved on this author * It was just modified a little bit to be able to scan * a scandir directory instead of a service directory */ int scandir_ok (char const *dir) { log_flow() ; size_t dirlen = strlen(dir) ; int fd ; char fn[dirlen + 1 + strlen(S6_SVSCAN_CTLDIR) + 9 + 1] ; memcpy(fn, dir, dirlen) ; fn[dirlen] = '/' ; memcpy(fn + dirlen + 1, S6_SVSCAN_CTLDIR, strlen(S6_SVSCAN_CTLDIR)) ; memcpy(fn + dirlen + 1 + strlen(S6_SVSCAN_CTLDIR), "/control", 9) ; fn[dirlen + 1 + strlen(S6_SVSCAN_CTLDIR) + 9] = 0 ; fd = open_write(fn) ; if (fd < 0) { if ((errno == ENXIO) || (errno == ENOENT)) return 0 ; else return -1 ; } fd_close(fd) ; return 1 ; } int scandir_send_signal(char const *scandir,char const *signal) { log_flow() ; size_t idlen = strlen(signal) ; char data[idlen + 1] ; size_t datalen = 0 ; for (; datalen < idlen ; datalen++) data[datalen] = signal[datalen] ; switch (s6_svc_writectl(scandir, S6_SVSCAN_CTLDIR, data, datalen)) { case -1: log_warnusys("control: ", scandir) ; return 0 ; case -2: log_warnsys("something is wrong with the ", scandir, "/" S6_SVSCAN_CTLDIR " directory. errno reported") ; return 0 ; case 0: log_warnu("control: ", scandir, ": supervisor not listening") ; return 0 ; } return 1 ; } char const *get_userhome(uid_t myuid) { log_flow() ; char const *user_home = NULL ; struct passwd *st = getpwuid(myuid) ; int e = errno ; errno = 0 ; if (!st) { if (!errno) errno = ESRCH ; return 0 ; } user_home = st->pw_dir ; if (!user_home) return 0 ; errno = e ; return user_home ; } int youruid(uid_t *passto,char const *owner) { log_flow() ; int e ; e = errno ; errno = 0 ; struct passwd *st ; st = getpwnam(owner) ; if (!st) { if (!errno) errno = ESRCH ; return 0 ; } *passto = st->pw_uid ; errno = e ; return 1 ; } int yourgid(gid_t *passto,uid_t owner) { log_flow() ; int e ; e = errno ; errno = 0 ; struct passwd *st ; st = getpwuid(owner) ; if (!st) { if (!errno) errno = ESRCH ; return 0 ; } *passto = st->pw_gid ; errno = e ; return 1 ; } int set_livedir(stralloc *live) { log_flow() ; if (live->len) { if (live->s[0] != '/') return -1 ; if (live->s[live->len - 2] != '/') { live->len-- ; if (!stralloc_cats(live,"/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(live)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; } } else { if (!stralloc_cats(live,SS_LIVE)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(live)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; } live->len--; return 1 ; } int set_livescan(stralloc *scandir,uid_t owner) { log_flow() ; int r ; char ownerpack[UID_FMT] ; r = set_livedir(scandir) ; if (r < 0) return -1 ; if (!r) return 0 ; size_t ownerlen = uid_fmt(ownerpack,owner) ; ownerpack[ownerlen] = 0 ; if (!stralloc_cats(scandir,SS_SCANDIR "/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(scandir,ownerpack)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(scandir)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; scandir->len--; return 1 ; } int set_livetree(stralloc *livetree,uid_t owner) { log_flow() ; int r ; char ownerpack[UID_FMT] ; r = set_livedir(livetree) ; if (r < 0) return -1 ; if (!r) return 0 ; size_t ownerlen = uid_fmt(ownerpack,owner) ; ownerpack[ownerlen] = 0 ; if (!stralloc_cats(livetree,SS_TREE "/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(livetree,ownerpack)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(livetree)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; livetree->len--; return 1 ; } int set_livestate(stralloc *livestate,uid_t owner) { log_flow() ; int r ; char ownerpack[UID_FMT] ; r = set_livedir(livestate) ; if (r < 0) return -1 ; if (!r) return 0 ; size_t ownerlen = uid_fmt(ownerpack,owner) ; ownerpack[ownerlen] = 0 ; if (!stralloc_cats(livestate,SS_STATE + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(livestate,"/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(livestate,ownerpack)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(livestate)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; livestate->len--; return 1 ; } int set_ownerhome(stralloc *base,uid_t owner) { log_flow() ; char const *user_home = 0 ; int e = errno ; struct passwd *st = getpwuid(owner) ; errno = 0 ; if (!st) { if (!errno) errno = ESRCH ; return 0 ; } user_home = st->pw_dir ; errno = e ; if (!user_home) return 0 ; if (!stralloc_cats(base,user_home)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(base,"/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(base)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; base->len--; return 1 ; } int set_ownersysdir(stralloc *base, uid_t owner) { log_flow() ; char const *user_home = NULL ; int e = errno ; struct passwd *st = getpwuid(owner) ; errno = 0 ; if (!st) { if (!errno) errno = ESRCH ; return 0 ; } user_home = st->pw_dir ; errno = e ; if (user_home == NULL) return 0 ; if(owner > 0){ if (!stralloc_cats(base,user_home)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(base,"/")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(base,SS_USER_DIR)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(base)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; } else { if (!stralloc_cats(base,SS_SYSTEM_DIR)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(base)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; } base->len--; return 1 ; } int read_svfile(stralloc *sasv,char const *name,char const *src) { log_flow() ; int r ; size_t srclen = strlen(src) ; size_t namelen = strlen(name) ; char svtmp[srclen + namelen + 1] ; memcpy(svtmp,src,srclen) ; memcpy(svtmp + srclen, name, namelen) ; svtmp[srclen + namelen] = 0 ; size_t filesize=file_get_size(svtmp) ; if (!filesize) log_warn_return(LOG_EXIT_LESSONE,svtmp," is empty") ; r = openreadfileclose(svtmp,sasv,filesize) ; if(!r) log_warnusys_return(LOG_EXIT_ZERO,"open ", svtmp) ; /** ensure that we have an empty line at the end of the string*/ if (!stralloc_cats(sasv,"\n")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(sasv)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; return 1 ; } int module_in_cmdline(genalloc *gares, ss_resolve_t *res, char const *dir) { log_flow() ; stralloc tmp = STRALLOC_ZERO ; size_t pos = 0 ; if (!ss_resolve_append(gares,res)) goto err ; if (res->contents) { if (!sastr_clean_string(&tmp,res->sa.s + res->contents)) goto err ; } for (; pos < tmp.len ; pos += strlen(tmp.s + pos) + 1) { char *name = tmp.s + pos ; if (!ss_resolve_check(dir,name)) goto err ; if (!ss_resolve_read(res,dir,name)) goto err ; if (res->type == TYPE_CLASSIC) if (ss_resolve_search(gares,name) < 0) if (!ss_resolve_append(gares,res)) goto err ; } stralloc_free(&tmp) ; return 1 ; err: stralloc_free(&tmp) ; return 0 ; } int module_search_service(char const *src, genalloc *gares, char const *name,uint8_t *found, char module_name[256]) { log_flow() ; size_t srclen = strlen(src), pos = 0, deps = 0 ; stralloc list = STRALLOC_ZERO ; stralloc tmp = STRALLOC_ZERO ; ss_resolve_t res = RESOLVE_ZERO ; char const *exclude[2] = { SS_MASTER + 1, 0 } ; char t[srclen + SS_RESOLVE_LEN + 1] ; auto_strings(t,src,SS_RESOLVE) ; if (!sastr_dir_get(&list,t,exclude,S_IFREG)) goto err ; for (;pos < list.len ; pos += strlen(list.s + pos) + 1) { char *dname = list.s + pos ; if (!ss_resolve_read(&res,src,dname)) goto err ; if (res.type == TYPE_MODULE && res.contents) { if (!sastr_clean_string(&tmp,res.sa.s + res.contents)) goto err ; for (deps = 0 ; deps < tmp.len ; deps += strlen(tmp.s + deps) + 1) { if (!strcmp(name,tmp.s + deps)) { (*found)++ ; if (strlen(dname) > 255) log_1_warn_return(LOG_EXIT_ZERO,"module name too long") ; auto_strings(module_name,dname) ; goto end ; } } } } end: /** search if the service is on the commandline * if not we crash */ for(pos = 0 ; pos < genalloc_len(ss_resolve_t,gares) ; pos++) { ss_resolve_t_ref pres = &genalloc_s(ss_resolve_t,gares)[pos] ; char *str = pres->sa.s ; char *name = str + pres->name ; if (!strcmp(name,module_name)) { (*found) = 0 ; break ; } } stralloc_free(&list) ; stralloc_free(&tmp) ; ss_resolve_free(&res) ; return 1 ; err: stralloc_free(&list) ; stralloc_free(&tmp) ; ss_resolve_free(&res) ; return 0 ; }