refactored dispatch
authorThomas Walker Lynch <thomas.lynch@reasoningtechnology.com>
Tue, 5 Mar 2019 22:57:35 +0000 (23:57 +0100)
committerThomas Walker Lynch <thomas.lynch@reasoningtechnology.com>
Tue, 5 Mar 2019 22:57:35 +0000 (23:57 +0100)
src/5_deprecated/dispatch_exec.lib.c [new file with mode: 0644]
src/5_deprecated/dispatch_f.lib.c [new file with mode: 0644]
src/5_deprecated/dispatch_useradd.lib.c [new file with mode: 0644]
src/5_scratch/dispatch.lib.h [new file with mode: 0644]
src/5_scratch/subu-mk-0.lib.h
src/dispatch.lib.c [new file with mode: 0644]
src/dispatch_exec.lib.c [deleted file]
src/dispatch_f.lib.c [deleted file]
src/dispatch_useradd.lib.c [deleted file]
src/subu-mk-0.lib.c

diff --git a/src/5_deprecated/dispatch_exec.lib.c b/src/5_deprecated/dispatch_exec.lib.c
new file mode 100644 (file)
index 0000000..024bff8
--- /dev/null
@@ -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 <sys/types.h>
+#include <unistd.h>
+#include <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+
+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 (file)
index 0000000..5c199f5
--- /dev/null
@@ -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 <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#if INTERFACE
+#include <sys/types.h>
+#include <unistd.h>
+#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 (file)
index 0000000..7b75291
--- /dev/null
@@ -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 <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#if INTERFACE
+#include <sys/types.h>
+#include <pwd.h>
+#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 (file)
index 0000000..7db05d9
--- /dev/null
@@ -0,0 +1,25 @@
+/* \aThis file was automatically generated.  Do not edit! */
+#undef INTERFACE
+#include <sys/types.h>
+#include <unistd.h>
+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
index 22fb1fc..27ffcce 100644 (file)
@@ -3,23 +3,17 @@
 #include <sqlite3.h>
 int subu_put_masteru_subu(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
 #include <sys/types.h>
-#include <pwd.h>
-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 <unistd.h>
-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 <errno.h>
 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 (file)
index 0000000..b04c7f4
--- /dev/null
@@ -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 <wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#if INTERFACE
+#include <sys/types.h>
+#include <unistd.h>
+#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 (file)
index 024bff8..0000000
+++ /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 <sys/types.h>
-#include <unistd.h>
-#include <wait.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-
-
-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 (file)
index 5c199f5..0000000
+++ /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 <wait.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-#if INTERFACE
-#include <sys/types.h>
-#include <unistd.h>
-#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 (file)
index 7b75291..0000000
+++ /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 <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-#if INTERFACE
-#include <sys/types.h>
-#include <pwd.h>
-#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;
-    }}}
-
index 9efa311..aa7add3 100644 (file)
@@ -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;
     }