From: Thomas Walker Lynch Date: Wed, 27 Feb 2019 23:12:42 +0000 (+0100) Subject: checkpoint refactored subu-mk-0 X-Git-Url: https://git.reasoningtechnology.com/style/static/gitweb.js?a=commitdiff_plain;h=d6eacc7f8595e2c4ed996ad14d8880d2727f9564;p=subu checkpoint refactored subu-mk-0 --- diff --git a/src/dispatch_f.lib.c b/src/dispatch_f.lib.c index 7edf41b..eda75da 100644 --- a/src/dispatch_f.lib.c +++ b/src/dispatch_f.lib.c @@ -1,27 +1,24 @@ /* - changes the uid, gid, and forks and calls the function - Returns -1 upon failure. + Forks a new process and runs the a function in that new process. I.e. it 'spawns' a function. + + f must have a specific prototype. It accepts one void pointer, and it returns a positive + integer. + + dispatch_f_euid_egid changes to the new euid and egid before running the function. + + If the change to in euid/egid fails, the forked process exits with a negative status. + If the function has an error, it returns a positive status. A status of zero means + that all went well. + + Because f is running in a separate process, the return status is the only means + of communication going back to the calling process. + - The wstatus returned from wait() might be either the error returned by exec - when it failed, or the return value from the command. An arbitary command is - passed in, so we don't know what its return values might be. Consquently, we - have no way of multiplexing a unique exec error code with the command return - value within wstatus. If the prorgrammer knows the return values of the - command passed in, and wants better behavior, he or she can spin a special - version of dispatch for that command. */ #define _GNU_SOURCE #include "dispatch_f.lib.h" // we need the declaration for uid_t etc. -#if INTERFACE -#include -#include -#define ERR_DISPATCH_F_FORK 1 -#define ERR_DISPATCH_F_SETEUID 2 -#define ERR_DISPATCH_F_SETEGID 3 -#endif - // without this #define execvpe is undefined #define _GNU_SOURCE @@ -30,55 +27,92 @@ #include #include -int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){ - char *perror_src = "dispatch_f_as"; +#if INTERFACE +#include +#include +#define ERR_NEGATIVE_RETURN_STATUS -1 +#define ERR_DISPATCH_F_FORK -2 +#define ERR_DISPATCH_F_SETEUID -3 +#define ERR_DISPATCH_F_SETEGID -4 +#endif + +// both name and fname are static allocations +struct dispatch_f_ctx{ + char *name; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid") + char *fname; // name of the function being dispatched + uint err; + int status; // return value from the function +}; +dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){ + ctxp = malloc(sizeof(dispatch_f_ctx)); + ctxp->dispatcher = name; + ctxp->dispatchee = fname; + ctxp->err = 0; + return ctxp; +} +void dispatch_f_ctx_free(dispatchf_ctx *ctxp){ + free(ctxp); // no dynamic variables in this context +} +void dispatch_f_mess(struct dispatch_f_ctx *ctxp){ + if(ctxp->err == 0) return; + switch(ctxp->err){ + case ERR_NEGATIVE_RETURN_STATUS: + fprintf(stderr, "%s, function \"%s\" broke contract with a negative return value.", ctxp->dispatcher, ctxp->dispatchee); + break; + case ERR_DISPATCHED_F_FORK: + case ERR_DISPATCHED_F_SETEUID: + case ERR_DISPATCHED_F_SETEGID: + fprintf(stderr, "%s, ", ctxp->dispatcher); + perror(ctxp->dispatcher); + break; + } + fputc('\n', stderr); +} + +dispatch_f_ctx *dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){ + dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f", fname); #ifdef DEBUG - dbprintf("%s %s\n", perror_src, fname); + dbprintf("%s %s\n", ctxp->dispatcher, ctxp->dispatchee); #endif pid_t pid = fork(); if( pid == -1 ){ - perror(perror_src); - fprintf(stderr, "%s %s\n", perror_src, fname); - return ERR_DISPATCH_F_FORK; + ctxp->err = ERR_DISPATCH_F_FORK; // we are still in the parent process + return ctxp; } if( pid == 0 ){ // we are the child - int status = (*f)(f_arg); + int status = (*f)(f_arg); // we require that f return a zero or positive value + if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; exit(status); }else{ // we are the parent - int wstatus; - waitpid(pid, &wstatus, 0); - return wstatus; + waitpid(pid, &(ctxp->status), 0); + return ctxp; } } -int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){ - char *perror_src = "dispatch_f_as"; +dispatch_f_ctx *dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){ + dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f_euid_egid", fname); #ifdef DEBUG - dbprintf("%s %s %u %u\n", perror_src, fname, euid, egid); + dbprintf("%s %s as euid:%u egid:%u\n", ctxp->dispatcher, ctxp->dispatchee, euid, egid); #endif pid_t pid = fork(); if( pid == -1 ){ - perror(perror_src); - fprintf(stderr, "%s %s %u %u\n", perror_src, fname, euid, egid); - return ERR_DISPATCH_F_FORK; + ctxp->err = ERR_DISPATCH_F_FORK; + return ctxp; } if( pid == 0 ){ // we are the child - if( seteuid(euid) == -1 ){ - perror(perror_src); - fprintf(stderr, "%s %s %u %u\n", perror_src, fname, euid, egid); - return ERR_DISPATCH_F_SETEUID; + int status; + if( seteuid(euid) == -1 ) + status = ERR_DISPATCH_F_SETEUID; + else if( setegid(egid) == -1 ) + status = ERR_DISPATCH_F_SETEGID; + else{ + status = (*f)(f_arg); + if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; + exit(status); } - if( setegid(egid) == -1 ){ - perror(perror_src); - fprintf(stderr, "%s %s %u %u\n", perror_src, fname, euid, egid); - return ERR_DISPATCH_F_SETEGID; - } - int status = (*f)(f_arg); - exit(status); }else{ // we are the parent - int wstatus; - waitpid(pid, &wstatus, 0); - return wstatus; + waitpid(pid, &(ctxp->status), 0); + return ctxp; } } diff --git a/src/subu-config.lib.c b/src/subu-config.lib.c index 0f02110..fda7ed8 100644 --- a/src/subu-config.lib.c +++ b/src/subu-config.lib.c @@ -21,6 +21,7 @@ currently a unit converted to base 10 will always fit in a 21 bit buffer. #include #include +//-------------------------------------------------------------------------------- int schema(sqlite3 *db, uint max_subu_number){ char max_subu_number_string[32]; uint max_subu_number_string_len = snprintf(max_subu_number_string, 32, "%u", max_subu_number); @@ -28,7 +29,7 @@ int schema(sqlite3 *db, uint max_subu_number){ fprintf(stderr, "error exit, max_subu_number too big to deal with\n"); return ERR_CONFIG_FILE; } - char sql1[] = "CREATE TABLE Master_Subu(master_name TEXT, subu_number INT, subu_name TEXT); "; + char sql1[] = "CREATE TABLE Master_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT); "; char sql2[] = "CREATE TABLE Key_Int(key TEXT, value INT); "; char sql3_1[] = "INSERT INTO Key_Int VALUES( 'max_subu_number', "; @@ -47,26 +48,37 @@ int schema(sqlite3 *db, uint max_subu_number){ return sqlite3_exec(db, sql, NULL, NULL, NULL); } -static int subu_number_extract(void *n, int colcnt, char **colvals, char **colnames){ +//-------------------------------------------------------------------------------- +static int subu_number_extract(void *nsp, int colcnt, char **colvals, char **colnames){ if(colcnt >= 1){ - sscanf(colvals[0], "%u", n); + char *buf = (char *)malloc(strlen(colvals[0]) + 1); + strcpy( buf, colvals[0] ); + *(char **)nsp = buf; return 0; } return -1; } -int subu_number_get(sqlite3 *db, uint *subu_number){ - *subu_number = 0; - char *sql = - "BEGIN TRANSACTION;" - "UPDATE Key_Int SET value = value + 1 WHERE key = 'max_subu_number';" - "SELECT value FROM Key_Int WHERE key = 'max_subu_number';" - "COMMIT;"; +static char *subu_number_sql = + "BEGIN TRANSACTION;" + "UPDATE Key_Int SET value = value + 1 WHERE key = 'max_subu_number';" + "SELECT value FROM Key_Int WHERE key = 'max_subu_number';" + "COMMIT;"; +int subu_number_get(sqlite3 *db, char **nsp, char **errmsg){ int ret; - char *errmsg; - ret = sqlite3_exec(db, sql, subu_number_extract, subu_number, &errmsg); - if( errmsg ){ - printf("exec failed when accessing max_subu_number: %s\n", errmsg); - sqlite3_free(errmsg); - } + ret = sqlite3_exec(db, sql, subu_number_extract, (void *)nsp, errmsg); return ret; } + +//-------------------------------------------------------------------------------- +int subu_put_masteru_subu(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){ + char *sql = "INSERT INTO Master_Subu (?1, ?2, ?3);"; + size_t sql_len = strlen(sql); + sqlite3_stmt *stmt; + sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL); + sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, subu_username, strlen(subu_username), SQLITE_STATIC); + int rc = sqlite3_step(stmt); + sqlite3_finalize(stmt); + return rc; +} diff --git a/src/subu-mk-0.cli.c b/src/subu-mk-0.cli.c index ffa8122..fb111a2 100644 --- a/src/subu-mk-0.cli.c +++ b/src/subu-mk-0.cli.c @@ -13,5 +13,17 @@ int main(int argc, char **argv){ } char *subuname = argv[1]; - return subu_mk_0(subuname, config_file); + int ret; + sqlite3 *db; + ret = sqlite3_open_v2(config_file, &db, SQLITE_OPEN_READWRITE, NULL); + if( ret != SQLITE_OK ){ + fprintf(stderr, "error exit, could not open configuration file\n"); + return ERR_CONFIG_FILE; + } + + subu_mk_0_ctx *ctxp = subu_mk_0(sqlite3 *db, subuname); + subu_mk_0_mess(ctxp); + int err = ctxp->err; + subu_mk_0_ctx_free(ctxp); + return err; } diff --git a/src/subu-mk-0.lib.c b/src/subu-mk-0.lib.c index e03399f..3b087fc 100644 --- a/src/subu-mk-0.lib.c +++ b/src/subu-mk-0.lib.c @@ -32,20 +32,6 @@ #include #include -#if INTERFACE -#include -#define ERR_SUBU_MK_0_ARG_CNT 1 -#define ERR_SUBU_MK_0_CONFIG_FILE 2 -#define ERR_SUBU_MK_0_SETUID_ROOT 3 -#define ERR_SUBU_MK_0_BAD_MASTERU_HOME 4 -#define ERR_SUBU_MK_0_MALLOC 5 -#define ERR_SUBU_MK_0_MK_SUBUHOME 6 -#define ERR_SUBU_MK_0_FAILED_MKDIR_SUBU 7 -#define ERR_SUBU_MK_0_BUG_SSS 8 -#define ERR_SUBU_MK_0_FAILED_USERADD 9 -#define ERR_SUBU_MK_0_SETFACL 10 -#endif - /* Fedora 29's sss_cache is checking the inherited uid instead of the effective @@ -55,24 +41,23 @@ */ #define BUG_SSS_CACHE_RUID 1 -static uint max_subuname_len = 128; - // a well formed subuname +// wonder if it makes sense to add a length limit ... // returns the length of the subuname, or -1 -int allowed_subuname(char *subuname){ +int allowed_subuname(char *subuname, size_t &subuname_len){ char *ch = subuname; uint i = 0; while( *ch && - i < max_subuname_len - && ( *ch >= 'a' && *ch <= 'z' || *ch >= 'A' && *ch <= 'Z' || *ch >= '0' && *ch <= '9' || + *ch == '-' + || *ch == '_' || *ch == '.' @@ -83,38 +68,115 @@ int allowed_subuname(char *subuname){ ch++; i++; } - if( !*ch && i < max_subuname_len ) - return i; - else + if( !*ch ){ + subuname_len = i; + return 0; + }else return -1; } +struct subu_mk_0_ctx{ + char *name; + char *subuland; + char *subuhome; + char *subu_username; + char *aux; + uint err; +}; +ctxp *subu_mk_0_ctx_mk(){ + ctxp = malloc(sizeof(subu_mk_0_ctx)); + ctxp->name = "subu_mk_0"; + ctxp->subuland = 0; + ctxp->subuhome = 0; + ctxp->subu_username = 0; + ctxp->free_aux = false; + ctxp->aux = 0; +} +void subu_mk_0_ctx_free(subu_mk_0_ctx ctxp){ + free(ctxp->subuland); + free(ctxp->subuhome); + free(ctxp->subu_username); + if(ctxp->free_aux) free(ctxp->aux); + free ctxp; +} + +#if INTERFACE +#include +#define ERR_SUBU_MK_0_MKDIR_SUBUHOME 1 +#define ERR_SUBU_MK_0_SUBUNAME_MALFORMED 2 +#define ERR_SUBU_MK_0_SETUID_ROOT 3 +#define ERR_SUBU_MK_0_MASTERU_HOMELESS 4 +#define ERR_SUBU_MK_0_MALLOC 5 +#define ERR_SUBU_MK_0_CONFIG_FILE 6 +#define ERR_SUBU_MK_0_SUBUHOME_EXISTS 7 +#define ERR_SUBU_MK_0_BUG_SSS 8 +#define ERR_SUBU_MK_0_FAILED_USERADD 9 +#define +#endif +// must be called before any system calls, or perror() will be messed up +void subu_mk_0_mess(struct subu_mk_0_ctx *ctxp){ + switch(ctxp->err){ + case 0: return; + case ERR_SUBU_MK_0_MKDIR_SUBUHOME: + fprintf(stderr, "masteru could not make subuhome, \"%s\"", ctxp->subuhome); + break; + case ERR_SUBU_MK_0_SUBUNAME_MALFORMED: + fprintf(stderr, "subuname, \"%s\" is not in [ _.\-a-zA-Z0-9]*", ctxp->aux); + break; + case ERR_SUBU_MK_0_SETUID_ROOT: + fprintf(stderr, "This program must be run setuid root from a user account."); + break; + case ERR_SUBU_MK_0_MASTERU_HOMELESS: + char *masteru_name = aux; // this should not be freed + fprintf(stderr,"Masteru, \"%s\", has no home directory", masteru_name); + break; + case ERR_SUBU_MK_0_MALLOC + perror(ctxp->name); + break; + case ERR_SUBU_MK_0_CONFIG_FILE + fprintf(stderr, "config file error: %s", ctxp->aux); + break; + case ERR_SUBU_MK_0_SUBUHOME_EXISTS + fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", ctxp->subuhome); + break; + case ERR_SUBU_MK_0_BUG_SSS + perror(ctxp->name); + break; + case ERR_SUBU_MK_0_FAILED_USERADD + fprintf(stderr, "%u useradd failed\n", ctxp->subu_username); + break; + default: + } + fputc('\n', stderr); +} + // will be called through dispatch_f_as masteru -int masteru_makes_subuhome(void *arg){ +static uint masteru_makes_subuhome(void *arg){ char *subuhome = (char *) arg; if( mkdir( subuhome, 0700 ) == -1 ){ perror("masteru_makes_subuhome"); - return -1; + return ERR_SUBU_MK_0_MKDIR_SUBUHOME; } return 0; } -int subu_mk_0(char *subuname, char *config_file){ +subu_mk_0_ctx *subu_mk_0(sqlite3 *db, char *subuname){ + + subu_mk_0_ctx *ctxp = subu_mk_0_ctx_mk(); - char *perror_src = "subu_mk_0"; - //-------------------------------------------------------------------------------- #ifdef DEBUG - dbprintf("Opening the configuration file, \"%s\"\n", config_file); + dbprintf("Checking that subuname is well formed, counting its length.\n"); #endif - sqlite3 *db; + size_t subuname_len; { - if( sqlite3_open(config_file, &db) ){ - fprintf(stderr, "error exit, could not open config file, \"%s\"\n", config_file); - return ERR_SUBU_MK_0_CONFIG_FILE; - } - } - + int ret = allowed_subuname(subuname, subuname_len); + if( ret == -1 ){ + ctxp->err = ERR_SUBU_MK_0_SUBU_MALFORMED; + ctxp->aux = subuname; + return ctxp + }} + //-------------------------------------------------------------------------------- #ifdef DEBUG dbprintf("Checking that we are running from a user and are setuid root.\n"); @@ -132,88 +194,92 @@ int subu_mk_0(char *subuname, char *config_file){ dbprintf("masteru_uid %u, masteru_gid %u, set_euid %u set_egid %u\n", masteru_uid, masteru_gid, set_euid, set_egid); #endif if( masteru_uid == 0 || set_euid != 0 ){ - fprintf(stderr, "error exit, this program must be run setuid root from a user account\n"); - sqlite3_close(db); - return ERR_SUBU_MK_0_SETUID_ROOT; - } - } - - //-------------------------------------------------------------------------------- - // The subuname is used as the directory mount point, and it appears in configuration - // file relations. - #ifdef DEBUG - dbprintf("creating subu by the name of \"%s\"\n", subuname); - #endif - size_t subuname_len; - { - // subuname will appear in our config file, so we constrain its form - subuname_len = allowed_subuname(subuname); - if( subuname_len == -1 ){ - fprintf(stderr, "error exit, subuname is not in [ _.a-zA-Z0-9]* less than %u characters", max_subuname_len); - sqlite3_close(db); - return ERR_SUBU_MK_0_CONFIG_FILE; + ctxp->err = ERR_SUBU_MK_0_SETUID_ROOT; + return ctxp; } } //-------------------------------------------------------------------------------- #ifdef DEBUG - dbprintf("creation of required strings: masteru_name, masteru_home, subuland path, and subuhome path\n"); + dbprintf("creation of required strings and recording their lengths\n"); #endif char *masteru_name; size_t masteru_name_len; char *masteru_home; size_t masteru_home_len; - char *subuland; size_t subuland_len; - char *subuhome; - size_t subuhome_len; { struct passwd *masteru_pw_record_pt = getpwuid(masteru_uid); // reading /etc/passwd masteru_name = masteru_pw_record_pt->pw_name; + masteru_name_len = strlen(masteru_name); #ifdef DEBUG - dbprintf("masteru_name \"%s\"\n", masteru_name); + dbprintf("masteru_name \"%s\" %zu\n", masteru_name, masteru_name_len); #endif - // The masteru_name will occur in our config file, so we constrain its form. - // The masteru_name is already a username so it might have, or might not - // have, already been filtered for form. - masteru_name_len = allowed_subuname(masteru_name); - if( masteru_name_len == -1 ){ - fprintf(stderr, "error exit, masteru_name is not in [ _.a-zA-Z0-9]* less than %u characters", max_subuname_len); - sqlite3_close(db); - return ERR_SUBU_MK_0_CONFIG_FILE; - } masteru_home = masteru_pw_record_pt->pw_dir; #ifdef DEBUG - dbprintf("masteru_home \"%s\"\n", masteru_home); + dbprintf("masteru_home \"%s\" %zu\n", masteru_home, masteru_home_len); #endif masteru_home_len = strlen(masteru_home); if( masteru_home_len == 0 || masteru_home[0] == '(' ){ - fprintf(stderr,"error exit, %s has no home directory\n", masteru_name); - sqlite3_close(db); - return ERR_SUBU_MK_0_BAD_MASTERU_HOME; + ctxp->err = ERR_SUBU_MK_0_MASTERU_HOMELESS; + ctxp->aux = masteru_name; // we can not free a passwd struct, or its fields. I assume then it isn't re-entrant safe. + return ctxp; } char *subuland_extension = "/subuland/"; size_t subuland_extension_len = strlen(subuland_extension); - subuland = (char *)malloc( masteru_home_len + subuland_extension_len + 1 ); - strcpy(subuland, masteru_home); - strcpy(subuland + masteru_home_len, subuland_extension); + ctxp->subuland = (char *)malloc( masteru_home_len + subuland_extension_len + 1 ); + if(!ctxp->subuland){ + ctxp->err = ERR_SUBU_MK_0_MALLOC; + return ctxp; + } + strcpy(ctxp->subuland, masteru_home); + strcpy(ctxp->subuland + masteru_home_len, subuland_extension); + subuland_len = masteru_home_len + subuland_extension_len; #ifdef DEBUG - dbprintf("subuland \"%s\"\n", subuland); + dbprintf("subuland \"%s\" %zu\n", ctxp->subuland, subuland_len); #endif - subuland_len = masteru_home_len + subuland_extension_len; - subuhome_len = subuland_len + subuname_len; - subuhome = (char *)malloc(subuhome_len + 1); - if( !subuhome ){ - perror(perror_src); - free(subuland); - sqlite3_close(db); - return ERR_SUBU_MK_0_MALLOC; + } + + //-------------------------------------------------------------------------------- + #ifdef DEBUG + dbprintf("generate the subu_username, set the subuhome\n"); + #endif + size_t subu_username_len; + size_t subuhome_len; + { + char *ns=0; + char *mess=0; + if( subu_number_get( db, &ns, &mess ) != SQLITE_OK ){ + ctxp->err = ERR_SUBU_MK_0_CONFIG_FILE; + ctxp->aux = mess; + ctxp->free_aux = true; + return ctxp; + } + ns_len = strlen(ns); + ctxp->subu_username = malloc(1 + ns_len + 1); + if( !ctxp->subu_username ){ + ctxp->err = ERR_SUBU_MK_0_MALLOC; + return ctxp; + } + strcpy(ctxp->subu_username, "s"); + strcpy(ctxp->subu_username + 1, ns); + subu_username_len = ns_len + 1; + #ifdef DEBUG + dbprintf("subu_username \"%s\" %zu\n", ctxp->subu_username, subu_username_len); + #endif + + subuhome_len = subuland_len + subu_username_len; + ctxp->subuhome = (char *)malloc(subuhome_len + 1); + if( !ctxp->subuhome ){ + ctxp->err = ERR_SUBU_MK_0_MALLOC; + return ctxp; } - strcpy (subuhome, subuland); - strcpy (subuhome + subuland_len, subuname); + strcpy (ctxp->subuhome, ctxp->subuland); + strcpy (ctxp->subuhome + subuland_len, subu_username_len); + subuhome_len = subuland_land_len + subu_username_len; #ifdef DEBUG - dbprintf("subuhome \"%s\"\n", subuhome); + dbprintf("subuhome \"%s\" %zu\n", ctxp->subuhome, subuhome_len); #endif } @@ -222,212 +288,80 @@ int subu_mk_0(char *subuname, char *config_file){ // to access this directory. This will be the mount point for bindfs { #ifdef DEBUG - dbprintf("as masteru, making the directory \"%s\"\n", subuhome); + dbprintf("as masteru, making the directory \"%s\"\n", ctxp->subuhome); #endif struct stat st; - if( stat(subuhome, &st) != -1 ){ - fprintf(stderr, "error exit, a file system object already exists at subuhome\n"); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_MK_SUBUHOME; + if( stat(ctxp->subuhome, &st) != -1 ){ + ctxp->err = ERR_SUBU_MK_0_SUBUHOME_EXISTS; + return ctxp; } int ret = dispatch_f_euid_egid ( "masteru_makes_subuhome", masteru_makes_subuhome, - (void *)subuhome, + (void *)ctxp->subuhome, masteru_uid, masteru_gid ); - if( ret == -1 ){ - fprintf(stderr, "error exit, masteru could not make \"%s\"\n", subuhome); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_FAILED_MKDIR_SUBU; + if( ret < 0 || ret == ERR_SUBU_MK_0_MKDIR_SUBUHOME ){ + ctxp->err = ERR_SUBU_MK_0_MKDIR_SUBUHOME; + return ctxp; } } #ifdef DEBUG - dbprintf("masteru made directory \"%s\"\n", subuhome); - #endif - - //-------------------------------------------------------------------------------- - #ifdef DEBUG - dbprintf("synthesize the subu user name\n"); + dbprintf("masteru made directory \"%s\"\n", ctxp->subuhome); #endif - char *subu_username; - { - } /*-------------------------------------------------------------------------------- - Make the subservient user, i.e. the subu + Make the subservient user account, i.e. the subu */ { #ifdef DEBUG - dbprintf("making user \"%s\"\n", subuname); + dbprintf("making subu \"%s\ as user \"%s\"\n", subuname, ctxp->subu_username); #endif #if BUG_SSS_CACHE_RUID #ifdef DEBUG dbprintf("setting inherited real uid to 0 to accomodate SSS_CACHE UID BUG\n"); #endif if( setuid(0) == -1 ){ - perror(perror_src); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_BUG_SSS; + ctxp->err = ERR_SUBU_MK_0_BUG_SSS; + return ctxp; } #endif char *command = "/usr/sbin/useradd"; - char *argv[6]; + char *argv[3]; argv[0] = command; - argv[1] = subuname; - argv[2] = "-d"; - argv[3] = subuhome; - argv[4] = "-M"; - argv[5] = (char *) NULL; + argv[1] = subu_username; + argv[2] = (char *) NULL; char *envp[1]; envp[0] = (char *) NULL; struct dispatch_useradd_ret_t ret; ret = dispatch_useradd(argv, envp); if(ret.error){ - fprintf(stderr, "error exit, %u useradd failed\n", ret.error); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_FAILED_USERADD; + ctxp->err = ERR_SUBU_MK_0_FAILED_USERADD; + return ctxp; } #ifdef DEBUG - dbprintf("useradd finished\n"); + dbprintf("added user \"%s\"\n", subu_username); #endif } - /*-------------------------------------------------------------------------------- - At this point we have a subservient user, a subu, and we have a home directory for - the subu. However, the home directory is owned by masteru. We will now: - 1. set default acls on the subuhome so that masteru can access everything - in it. Currently masteru owns subuhome, but we will change that subu. We - do this first so that there can not be race from a subu user to create a - filesystem object that masteru can't access. - 2. x acls set on subuland and master u so that subu can reach subuhome, e.g. - when logging in. - 3. ownerhips of subuhome changed to subu - - 1. setfacl -m d:u:masteru_name:rwX,u:masteru_name:rwX subuhome - 2. setfacl -m u:subuname:x subuland - setfacl -m u:subuname:x masteru_home - - */ - { - #ifdef DEBUG - dbprintf("setting access rights an subuhome ownerhip\n"); - #endif - // create a buffer to hold the longest access string we will find in this section - uint max_name_len = subuname_len > masteru_name_len ? subuname_len : masteru_name_len; - uint max_access_len = - strlen("d:u:") - + max_name_len - + strlen("rwX,u:") - + masteru_name_len - + strlen("rwX") - + 1; - char access[max_access_len]; - // 1. acls for subuhome - char *command = "/usr/bin/setfacl"; - strcpy(access, "d:u:"); - strcpy(access + strlen("d:u:"), masteru_name); - strcpy(access + strlen("d:u:") + masteru_name_len, ":rwX,u:"); - strcpy(access + strlen("d:u:") + masteru_name_len + strlen(":rwX,u:"), masteru_name); - strcpy(access + strlen("d:u:") + 2 * masteru_name_len + strlen(":rwX,u:"), ":rwX"); - char *argv[5]; - argv[0] = command; - argv[1] = "-m"; - argv[2] = access; - argv[3] = subuhome; - argv[4] = (char *) NULL; - char *envp[1]; - envp[0] = (char *) NULL; - if( dispatch_exec(argv, envp) == -1 ){ - fprintf(stderr, "error exit, while setting acls for subuhome, \"%s\" \n", subuhome); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_SETFACL; - } - // 2.1 x acls on subuland - // setfacl -m u:subuname:x subuland - strcpy(access, "u:"); - strcpy(access + strlen("u:"), subuname); - strcpy(access + strlen("u:") + subuname_len, ":x"); - argv[3] = subuland; - if( dispatch_exec(argv, envp) == -1 ){ - fprintf(stderr, "error exit, failed to give subuname x acl on subuland.\n"); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_SETFACL; - } - // 2.2 x acls on masteru_home - // setfacl -m u:subuname:x masteru_home - argv[3] = masteru_home; - if( dispatch_exec(argv, envp) == -1 ){ - fprintf(stderr, "error exit, failed to give subuname x acl on masteru_home.\n"); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_SETFACL; - } - // 3. give subu ownership of subuhome - - #ifdef DEBUG - dbprintf("subu can now cd to subuhome\n"); - #endif - } - //-------------------------------------------------------------------------------- - { - #ifdef DEBUG - dbprintf("give masteru default access to the subuhome\n"); - #endif - char *command = "/usr/bin/setfacl"; - char access[strlen("d:u:") + masteru_name_len + strlen(":rwX") + 1]; - strcpy(access, "d:u:"); - strcpy(access + 4, masteru_name); - strcpy(access + 4 + masteru_name_len, ":rwX"); - char *argv[5]; - argv[0] = command; - argv[1] = "-m"; - argv[2] = access; - argv[3] = subuhome; - argv[4] = (char *) NULL; - char *envp[1]; - envp[0] = (char *) NULL; - if( dispatch_exec(argv, envp) == -1 ){ - fprintf - ( - stderr, - "'setfacl -$ -m d:u:%s:rwX %s' returned an error.\n", - masteru_name, - masteru_name, - subuhome - ); - free(subuland); - free(subuhome); - sqlite3_close(db); - return ERR_SUBU_MK_0_SETFACL; + #ifdef DEBUG + dbprintf("setting the masteru_name, subuname, subu_username relation\n"); + #endif + { + int ret = subu_put_masteru_subu(db, masteru_name, subuname, subu_username); + if( rc != SQLITE_DONE ){ + ctxp->err = ERR_SUBU_MK_0_CONFIG_FILE; + ctxp->aux = "insert of masteru subu relation failed"; + return ctxp; } - #ifdef DEBUG - dbprintf("masteru now has default access\n"); - #endif } #ifdef DEBUG dbprintf("finished subu-mk-0(%s)\n", subuname); #endif - free(subuland); - free(subuhome); - sqlite3_close(db); - return 0; + RETURN_SUBU_MK_0(0); } diff --git a/src/subu-number.cli.c b/src/subu-number.cli.c index 68758a1..52c7ae5 100644 --- a/src/subu-number.cli.c +++ b/src/subu-number.cli.c @@ -7,23 +7,27 @@ Set or get a new maximum subu number. Currently doesn't do the setting part. int print_subu_number(sqlite3 *db){ - uint msn; - int ret = subu_number_get(db, &msn); - if( ret == 0 ) printf("%u\n", msn); return ret; } int main(){ - int ret; sqlite3 *db; - ret = sqlite3_open_v2(config_file, &db, SQLITE_OPEN_READWRITE, NULL); - if( ret != SQLITE_OK ){ - fprintf(stderr, "error exit, could not open configuration file\n"); - return ERR_CONFIG_FILE; + { + int ret = sqlite3_open_v2(config_file, &db, SQLITE_OPEN_READWRITE, NULL); + if( ret != SQLITE_OK ){ + fprintf(stderr, "error exit, could not open configuration file\n"); + return ERR_CONFIG_FILE; + }} + + char *n; + char *mess; + int ret = subu_number_get(db, &n, &mess); + if( mess ){ + fprintf(stderr, "subu_number, %s\n", mess); + free(mess); } - if( print_subu_number(db) == -1 ){ - fprintf(stderr, "error exit, could not read access maximum subunumber\n"); - return ERR_CONFIG_FILE; + if( ret == SQLITE_OK ){ + printf("%s\n", n); } if( sqlite3_close(db) != SQLITE_OK ){ fprintf(stderr, "error exit, strange, we could not close the configuration file\n");