From e21191840f4e59fcb3dc468775571fbc0756c6f5 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Tue, 5 Mar 2019 23:57:35 +0100 Subject: [PATCH] refactored dispatch --- src/{ => 5_deprecated}/dispatch_exec.lib.c | 0 src/{ => 5_deprecated}/dispatch_f.lib.c | 0 src/{ => 5_deprecated}/dispatch_useradd.lib.c | 0 src/5_scratch/dispatch.lib.h | 25 +++ src/5_scratch/subu-mk-0.lib.h | 25 +-- src/dispatch.lib.c | 177 ++++++++++++++++++ src/subu-mk-0.lib.c | 21 ++- 7 files changed, 228 insertions(+), 20 deletions(-) rename src/{ => 5_deprecated}/dispatch_exec.lib.c (100%) rename src/{ => 5_deprecated}/dispatch_f.lib.c (100%) rename src/{ => 5_deprecated}/dispatch_useradd.lib.c (100%) create mode 100644 src/5_scratch/dispatch.lib.h create mode 100644 src/dispatch.lib.c diff --git a/src/dispatch_exec.lib.c b/src/5_deprecated/dispatch_exec.lib.c similarity index 100% rename from src/dispatch_exec.lib.c rename to src/5_deprecated/dispatch_exec.lib.c diff --git a/src/dispatch_f.lib.c b/src/5_deprecated/dispatch_f.lib.c similarity index 100% rename from src/dispatch_f.lib.c rename to src/5_deprecated/dispatch_f.lib.c diff --git a/src/dispatch_useradd.lib.c b/src/5_deprecated/dispatch_useradd.lib.c similarity index 100% rename from src/dispatch_useradd.lib.c rename to src/5_deprecated/dispatch_useradd.lib.c diff --git a/src/5_scratch/dispatch.lib.h b/src/5_scratch/dispatch.lib.h new file mode 100644 index 0000000..7db05d9 --- /dev/null +++ b/src/5_scratch/dispatch.lib.h @@ -0,0 +1,25 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +typedef struct dispatch_ctx dispatch_ctx; +dispatch_ctx *dispatch_exec(char **argv,char **envp); +dispatch_ctx *dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid); +int dbprintf(const char *format,...); +dispatch_ctx *dispatch_f(char *fname,int(*f)(void *arg),void *f_arg); +void dispatch_f_mess(struct dispatch_ctx *ctxp); +void dispatch_ctx_free(dispatch_ctx *ctxp); +dispatch_ctx *dispatch_ctx_mk(char *dispatcher,char *dispatchee); +#define ERR_DISPATCH_EXEC -1029 +#define ERR_DISPATCH_NULL_EXECUTABLE -1028 +#define ERR_DISPATCH_F_SETEGID -1027 +#define ERR_DISPATCH_F_SETEUID -1026 +#define ERR_DISPATCH_F_FORK -1025 +#define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024 +#define ERR_DISPATCH -1024 +struct dispatch_ctx { + char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.) + char *dispatchee; // name of the function being dispatched + int err; // error code as listed below, or status returned from dispatchee +}; +#define INTERFACE 0 diff --git a/src/5_scratch/subu-mk-0.lib.h b/src/5_scratch/subu-mk-0.lib.h index 22fb1fc..27ffcce 100644 --- a/src/5_scratch/subu-mk-0.lib.h +++ b/src/5_scratch/subu-mk-0.lib.h @@ -3,23 +3,17 @@ #include int subu_put_masteru_subu(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); #include -#include -typedef struct dispatch_useradd_ret_t dispatch_useradd_ret_t; -typedef unsigned int uint; -struct dispatch_useradd_ret_t { - uint error; - struct passwd *pw_record; -}; -struct dispatch_useradd_ret_t dispatch_useradd(char **argv,char **envp); -#define BUG_SSS_CACHE_RUID 1 #include -typedef struct dispatch_f_ctx dispatch_f_ctx; -dispatch_f_ctx *dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid); -struct dispatch_f_ctx { - char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid") +typedef struct dispatch_ctx dispatch_ctx; +dispatch_ctx *dispatch_exec(char **argv,char **envp); +#define BUG_SSS_CACHE_RUID 1 +void dispatch_f_mess(struct dispatch_ctx *ctxp); +#define ERR_DISPATCH -1024 +dispatch_ctx *dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid); +struct dispatch_ctx { + char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.) char *dispatchee; // name of the function being dispatched - int err; - int status; // return value from the function + int err; // error code as listed below, or status returned from dispatchee }; int subu_number_get(sqlite3 *db,char **nsp,char **errmsg); int dbprintf(const char *format,...); @@ -27,6 +21,7 @@ int dbprintf(const char *format,...); #include typedef struct subu_mk_0_ctx subu_mk_0_ctx; struct subu_mk_0_ctx *subu_mk_0(sqlite3 *db,char *subuname); +typedef unsigned int uint; extern uint subuhome_perms; void subu_mk_0_mess(struct subu_mk_0_ctx *ctxp); void subu_mk_0_ctx_free(struct subu_mk_0_ctx *ctxp); diff --git a/src/dispatch.lib.c b/src/dispatch.lib.c new file mode 100644 index 0000000..b04c7f4 --- /dev/null +++ b/src/dispatch.lib.c @@ -0,0 +1,177 @@ +/* + Runs a command or function as its own process. + + For the return status from command or function must be greater than ERR_DISPATCH. + In the case of dispatch_exec, we only have a promise from the user to not dispatch + non compliant commands. + + Interesting it isn't possible to have a kernel dispatch that calls fork, and then + others that call this kernel. The reason being is because of collision in return + status values between the function in the kernel, and with each wrapper. The + TTCA with the passed in error processing functions would not have this problem. + +*/ +#define _GNU_SOURCE + +#include "dispatch.lib.h" + +// we need the declaration for uid_t etc. +// without this #define execvpe is undefined +#define _GNU_SOURCE + +#include +#include +#include +#include + +#if INTERFACE +#include +#include +#endif + +//-------------------------------------------------------------------------------- +// dispatch returns an instance of this class. +// +#if INTERFACE +// currently both dispatcher and dispatchee strings are statically allocated +struct dispatch_ctx{ + char *dispatcher; // name of the dispatch function ("dispatch_f", "dispatch_f_euid_egid", etc.) + char *dispatchee; // name of the function being dispatched + int err; // error code as listed below, or status returned from dispatchee +}; +#define ERR_DISPATCH -1024 +#define ERR_DISPATCH_NEGATIVE_RETURN_STATUS -1024 +#define ERR_DISPATCH_F_FORK -1025 +#define ERR_DISPATCH_F_SETEUID -1026 +#define ERR_DISPATCH_F_SETEGID -1027 +#define ERR_DISPATCH_NULL_EXECUTABLE -1028 +#define ERR_DISPATCH_EXEC -1029 +#endif +dispatch_ctx *dispatch_ctx_mk(char *dispatcher, char *dispatchee){ + dispatch_ctx *ctxp = malloc(sizeof(dispatch_ctx)); + ctxp->dispatcher = dispatcher; + ctxp->dispatchee = dispatchee; + ctxp->err = 0; + return ctxp; +} +void dispatch_ctx_free(dispatch_ctx *ctxp){ + // currently no dynamic variables to be freed in ctx + free(ctxp); +} +void dispatch_f_mess(struct dispatch_ctx *ctxp){ + if(ctxp->err > ERR_DISPATCH) return; + fprintf(stderr, "%s", ctxp->dispatcher); // if fprintf gets an error, errno will be overwritten + switch(ctxp->err){ + case ERR_DISPATCH_NEGATIVE_RETURN_STATUS: + fprintf(stderr, " dispatchee \"%s\" returned a negative status.", ctxp->dispatchee); + break; + case ERR_DISPATCH_F_FORK: + case ERR_DISPATCH_F_SETEUID: + case ERR_DISPATCH_F_SETEGID: + fputc(' ', stderr); + perror(ctxp->dispatcher); + break; + case ERR_DISPATCH_NULL_EXECUTABLE: + fprintf(stderr, " executable was not specified"); + break; + case ERR_DISPATCH_EXEC: + // exec is in another process when it fails, so we can't see the errno value it set + fprintf(stderr, " exec of \"%s\" failed", ctxp->dispatchee); + break; + default: + fprintf(stderr, " returned undefined status"); + } + fputc('\n', stderr); +} + +//-------------------------------------------------------------------------------- +// interface call point, dispatch a function +dispatch_ctx *dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){ + dispatch_ctx *ctxp = dispatch_ctx_mk("dispatch_f", fname); + #ifdef DEBUG + dbprintf("%s %s\n", ctxp->dispatcher, ctxp->dispatchee); + #endif + pid_t pid = fork(); + if( pid == -1 ){ + ctxp->err = ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process + return ctxp; + } + if( pid == 0 ){ // we are the child + int status = (*f)(f_arg); // we require that f return a zero or positive value + if( status < ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS; + exit(status); + }else{ // we are the parent + waitpid(pid, &(ctxp->err), 0); + return ctxp; + } +} + +//-------------------------------------------------------------------------------- +// interface call point, dispatch a function with a given euid/egid +// of course this will only work if our euid is root in the first place +dispatch_ctx *dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){ + dispatch_ctx *ctxp = dispatch_ctx_mk("dispatch_f_euid_egid", fname); + #ifdef DEBUG + dbprintf("%s %s as euid:%u egid:%u\n", ctxp->dispatcher, ctxp->dispatchee, euid, egid); + #endif + pid_t pid = fork(); + if( pid == -1 ){ + ctxp->err = ERR_DISPATCH_F_FORK; + return ctxp; + } + if( pid == 0 ){ // we are the child + 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 <= ERR_DISPATCH ) status = ERR_DISPATCH_NEGATIVE_RETURN_STATUS; + exit(status); + } + }else{ // we are the parent + waitpid(pid, &(ctxp->err), 0); + return ctxp; + } +} + +//-------------------------------------------------------------------------------- +// interface call point, dispatch a executable +dispatch_ctx *dispatch_exec(char **argv, char **envp){ + dispatch_ctx *ctxp; + char *command; + { + if( !argv || !argv[0] ){ + ctxp = dispatch_ctx_mk("dispatch_exec", "NULL"); + ctxp->err = ERR_DISPATCH_NULL_EXECUTABLE; + return ctxp; + } + #ifdef DEBUG + dbprintf("dispatch_exec:"); + char **apt = argv; + while( *apt ){ + dbprintf(" %s",*apt); + apt++; + } + dbprintf("\n"); + #endif + command = argv[0]; + ctxp = dispatch_ctx_mk("dispatch_exec", command); + } + pid_t pid = fork(); + if( pid == -1 ){ + ctxp->err = ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process + return ctxp; + } + if( pid == 0 ){ // we are the child + execvpe(command, argv, envp); // exec will only return if it has an error + perror("dispatch_exec"); // our only chance to print this message, as this is the child process + exit(ERR_DISPATCH_EXEC); + }else{ // we are the parent + waitpid(pid, &(ctxp->err), 0); + return ctxp; + } +} + + diff --git a/src/subu-mk-0.lib.c b/src/subu-mk-0.lib.c index 9efa311..aa7add3 100644 --- a/src/subu-mk-0.lib.c +++ b/src/subu-mk-0.lib.c @@ -305,7 +305,7 @@ struct subu_mk_0_ctx *subu_mk_0(sqlite3 *db, char *subuname){ ctxp->err = ERR_SUBU_MK_0_SUBUHOME_EXISTS; return ctxp; } - struct dispatch_f_ctx *dfr = dispatch_f_euid_egid + dispatch_ctx *dfr = dispatch_f_euid_egid ( "masteru_makes_subuhome", masteru_makes_subuhome, @@ -313,7 +313,13 @@ struct subu_mk_0_ctx *subu_mk_0(sqlite3 *db, char *subuname){ masteru_uid, masteru_gid ); - if( dfr->err < 0 || dfr->err == ERR_SUBU_MK_0_MKDIR_SUBUHOME ){ + if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_MK_0_MKDIR_SUBUHOME ){ + #ifdef DEBUG + if( dfr->err == ERR_SUBU_MK_0_MKDIR_SUBUHOME ) + perror("mkdir"); + else + dispatch_f_mess(dfr); + #endif ctxp->err = ERR_SUBU_MK_0_MKDIR_SUBUHOME; return ctxp; } @@ -344,9 +350,14 @@ struct subu_mk_0_ctx *subu_mk_0(sqlite3 *db, char *subuname){ 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){ + dispatch_ctx *dfr = dispatch_exec(argv, envp); + if( dfr->err != 0 ){ + #ifdef DEBUG + if( dfr->err <= ERR_DISPATCH ) + dispatch_f_mess(dfr); + else + perror("useradd"); + #endif ctxp->err = ERR_SUBU_MK_0_FAILED_USERADD; return ctxp; } -- 2.20.1