From: Thomas Walker Lynch Date: Tue, 5 Mar 2019 22:57:35 +0000 (+0100) Subject: refactored dispatch X-Git-Url: https://git.reasoningtechnology.com/style/rt_dark_doc.css?a=commitdiff_plain;h=e21191840f4e59fcb3dc468775571fbc0756c6f5;p=subu refactored dispatch --- diff --git a/src/5_deprecated/dispatch_exec.lib.c b/src/5_deprecated/dispatch_exec.lib.c new file mode 100644 index 0000000..024bff8 --- /dev/null +++ b/src/5_deprecated/dispatch_exec.lib.c @@ -0,0 +1,60 @@ +/* + fork/execs/wait the command passed in argv[0]; + Returns -1 upon failure. + + 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. +*/ +#include "dispatch_exec.lib.h" + +// without this #define execvpe is undefined +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + + + +int dispatch_exec(char **argv, char **envp){ + if( !argv || !argv[0] ){ + fprintf(stderr, "argv[0] null. Null command passed into dispatch().\n"); + return -1; + } + #ifdef DEBUG + dbprintf("dispatching exec, args follow:\n"); + char **apt = argv; + while( *apt ){ + dbprintf("\t%s",*apt); + apt++; + } + dbprintf("\n"); + #endif + char *command = argv[0]; + pid_t pid = fork(); + if( pid == -1 ){ + fprintf(stderr, "fork() failed in dispatch().\n"); + return -1; + } + if( pid == 0 ){ // we are the child + execvpe(command, argv, envp); + // exec will only return if it has an error .. + perror(command); + return -1; + }else{ // we are the parent + int wstatus; + waitpid(pid, &wstatus, 0); + if(wstatus) + return -1; + else + return 0; + } +} diff --git a/src/5_deprecated/dispatch_f.lib.c b/src/5_deprecated/dispatch_f.lib.c new file mode 100644 index 0000000..5c199f5 --- /dev/null +++ b/src/5_deprecated/dispatch_f.lib.c @@ -0,0 +1,130 @@ +/* + Forks a new process and runs the a function in that new process. I.e. it 'spawns' a function. + + f must have the specified prototype. I.e. it accepts one void pointer and + returns a positive integer. (Negative integers are used for dispatch error codes.) + + 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. + + +*/ +#define _GNU_SOURCE + +#include "dispatch_f.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_f_ctx class +// +#if INTERFACE +#define ERR_NEGATIVE_RETURN_STATUS -1 +#define ERR_DISPATCH_F_FORK -2 +#define ERR_DISPATCH_F_SETEUID -3 +#define ERR_DISPATCH_F_SETEGID -4 + +// both name and fname are static allocations +struct dispatch_f_ctx{ + char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid") + char *dispatchee; // name of the function being dispatched + int err; + int status; // return value from the function +}; +#endif +dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){ + dispatch_f_ctx *ctxp = malloc(sizeof(dispatch_f_ctx)); + ctxp->dispatcher = name; + ctxp->dispatchee = fname; + ctxp->err = 0; + return ctxp; +} +void dispatch_f_ctx_free(dispatch_f_ctx *ctxp){ + // no dynamic variables to be freed in ctx + free(ctxp); +} +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_DISPATCH_F_FORK: + case ERR_DISPATCH_F_SETEUID: + case ERR_DISPATCH_F_SETEGID: + fprintf(stderr, "%s, ", ctxp->dispatcher); + perror(ctxp->dispatcher); + break; + } + fputc('\n', stderr); +} + +//-------------------------------------------------------------------------------- +// interface call point +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", ctxp->dispatcher, ctxp->dispatchee); + #endif + pid_t pid = fork(); + if( pid == -1 ){ + 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); // 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 + waitpid(pid, &(ctxp->status), 0); + return ctxp; + } +} + +//-------------------------------------------------------------------------------- +// interface call point +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 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 < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; + exit(status); + } + }else{ // we are the parent + waitpid(pid, &(ctxp->status), 0); + return ctxp; + } +} + + diff --git a/src/5_deprecated/dispatch_useradd.lib.c b/src/5_deprecated/dispatch_useradd.lib.c new file mode 100644 index 0000000..7b75291 --- /dev/null +++ b/src/5_deprecated/dispatch_useradd.lib.c @@ -0,0 +1,68 @@ +/* +There is no C library interface to useradd(8), but if there were, this function +would be found there instead. + +*/ +#include "dispatch_useradd.lib.h" + +#include +#include +#include +#include +#include + +#if INTERFACE +#include +#include +#define ERR_DISPATCH_USERADD_ARGC 1 +#define ERR_DISPATCH_USERADD_DISPATCH 2 +#define ERR_DISPATCH_USERADD_PWREC 3 +struct dispatch_useradd_ret_t{ + uint error; + struct passwd *pw_record; +}; +#endif + + +// we have a contract with the caller that argv[1] is always the subuname +struct dispatch_useradd_ret_t dispatch_useradd(char **argv, char **envp){ + struct dispatch_useradd_ret_t ret; + { + if( !argv || !argv[0] || !argv[1]){ + fprintf(stderr,"useradd() needs a first argument as the name of the user to be made"); + ret.error = ERR_DISPATCH_USERADD_ARGC; + ret.pw_record = NULL; + return ret; + } + + char *subu_name; + { + subu_name = argv[1]; + if( dispatch_exec(argv, envp) == -1 ){ + fprintf(stderr,"%s failed\n", argv[0]); + ret.error = ERR_DISPATCH_USERADD_DISPATCH; + ret.pw_record = NULL; + return ret; + }} + + { + struct passwd *pw_record = getpwnam(subu_name); + uint count = 1; + while( !pw_record && count <= 3 ){ + #ifdef DEBUG + printf("try %u, getpwnam failed, trying again\n", count); + #endif + sleep(1); + pw_record = getpwnam(subu_name); + count++; + } + if( !pw_record ){ + ret.error = ERR_DISPATCH_USERADD_PWREC; + ret.pw_record = NULL; + return ret; + } + ret.error = 0; + ret.pw_record = pw_record; + return ret; + }}} + 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/dispatch_exec.lib.c b/src/dispatch_exec.lib.c deleted file mode 100644 index 024bff8..0000000 --- a/src/dispatch_exec.lib.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - fork/execs/wait the command passed in argv[0]; - Returns -1 upon failure. - - 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. -*/ -#include "dispatch_exec.lib.h" - -// without this #define execvpe is undefined -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - - - -int dispatch_exec(char **argv, char **envp){ - if( !argv || !argv[0] ){ - fprintf(stderr, "argv[0] null. Null command passed into dispatch().\n"); - return -1; - } - #ifdef DEBUG - dbprintf("dispatching exec, args follow:\n"); - char **apt = argv; - while( *apt ){ - dbprintf("\t%s",*apt); - apt++; - } - dbprintf("\n"); - #endif - char *command = argv[0]; - pid_t pid = fork(); - if( pid == -1 ){ - fprintf(stderr, "fork() failed in dispatch().\n"); - return -1; - } - if( pid == 0 ){ // we are the child - execvpe(command, argv, envp); - // exec will only return if it has an error .. - perror(command); - return -1; - }else{ // we are the parent - int wstatus; - waitpid(pid, &wstatus, 0); - if(wstatus) - return -1; - else - return 0; - } -} diff --git a/src/dispatch_f.lib.c b/src/dispatch_f.lib.c deleted file mode 100644 index 5c199f5..0000000 --- a/src/dispatch_f.lib.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - Forks a new process and runs the a function in that new process. I.e. it 'spawns' a function. - - f must have the specified prototype. I.e. it accepts one void pointer and - returns a positive integer. (Negative integers are used for dispatch error codes.) - - 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. - - -*/ -#define _GNU_SOURCE - -#include "dispatch_f.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_f_ctx class -// -#if INTERFACE -#define ERR_NEGATIVE_RETURN_STATUS -1 -#define ERR_DISPATCH_F_FORK -2 -#define ERR_DISPATCH_F_SETEUID -3 -#define ERR_DISPATCH_F_SETEGID -4 - -// both name and fname are static allocations -struct dispatch_f_ctx{ - char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid") - char *dispatchee; // name of the function being dispatched - int err; - int status; // return value from the function -}; -#endif -dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){ - dispatch_f_ctx *ctxp = malloc(sizeof(dispatch_f_ctx)); - ctxp->dispatcher = name; - ctxp->dispatchee = fname; - ctxp->err = 0; - return ctxp; -} -void dispatch_f_ctx_free(dispatch_f_ctx *ctxp){ - // no dynamic variables to be freed in ctx - free(ctxp); -} -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_DISPATCH_F_FORK: - case ERR_DISPATCH_F_SETEUID: - case ERR_DISPATCH_F_SETEGID: - fprintf(stderr, "%s, ", ctxp->dispatcher); - perror(ctxp->dispatcher); - break; - } - fputc('\n', stderr); -} - -//-------------------------------------------------------------------------------- -// interface call point -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", ctxp->dispatcher, ctxp->dispatchee); - #endif - pid_t pid = fork(); - if( pid == -1 ){ - 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); // 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 - waitpid(pid, &(ctxp->status), 0); - return ctxp; - } -} - -//-------------------------------------------------------------------------------- -// interface call point -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 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 < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; - exit(status); - } - }else{ // we are the parent - waitpid(pid, &(ctxp->status), 0); - return ctxp; - } -} - - diff --git a/src/dispatch_useradd.lib.c b/src/dispatch_useradd.lib.c deleted file mode 100644 index 7b75291..0000000 --- a/src/dispatch_useradd.lib.c +++ /dev/null @@ -1,68 +0,0 @@ -/* -There is no C library interface to useradd(8), but if there were, this function -would be found there instead. - -*/ -#include "dispatch_useradd.lib.h" - -#include -#include -#include -#include -#include - -#if INTERFACE -#include -#include -#define ERR_DISPATCH_USERADD_ARGC 1 -#define ERR_DISPATCH_USERADD_DISPATCH 2 -#define ERR_DISPATCH_USERADD_PWREC 3 -struct dispatch_useradd_ret_t{ - uint error; - struct passwd *pw_record; -}; -#endif - - -// we have a contract with the caller that argv[1] is always the subuname -struct dispatch_useradd_ret_t dispatch_useradd(char **argv, char **envp){ - struct dispatch_useradd_ret_t ret; - { - if( !argv || !argv[0] || !argv[1]){ - fprintf(stderr,"useradd() needs a first argument as the name of the user to be made"); - ret.error = ERR_DISPATCH_USERADD_ARGC; - ret.pw_record = NULL; - return ret; - } - - char *subu_name; - { - subu_name = argv[1]; - if( dispatch_exec(argv, envp) == -1 ){ - fprintf(stderr,"%s failed\n", argv[0]); - ret.error = ERR_DISPATCH_USERADD_DISPATCH; - ret.pw_record = NULL; - return ret; - }} - - { - struct passwd *pw_record = getpwnam(subu_name); - uint count = 1; - while( !pw_record && count <= 3 ){ - #ifdef DEBUG - printf("try %u, getpwnam failed, trying again\n", count); - #endif - sleep(1); - pw_record = getpwnam(subu_name); - count++; - } - if( !pw_record ){ - ret.error = ERR_DISPATCH_USERADD_PWREC; - ret.pw_record = NULL; - return ret; - } - ret.error = 0; - ret.pw_record = pw_record; - return ret; - }}} - 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; }