--- /dev/null
+# src/0_makefile
+
+SHELL=/bin/bash
+
+-include 0_makefile_flags
+
+SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
+MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
+
+SOURCES=$(wildcard *.c)
+HFILES=$(wildcard *.h)
+
+all: version deps lib execs
+
+version:
+ $(MAKE) $@
+ @echo "SUID_TOOL: " $(SUID_TOOL)
+
+deps:
+ makeheaders $(SOURCES) $(HFILES)
+ sed -i '/^ *int *main *(.*)/d' *.h
+ $(MAKE) $@
+
+execs:
+ $(MAKE) $@
+ @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
+ cat $(SUID_TOOL)
+ @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
+ sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
+
+clean:
+ $(MAKE) $@
+ for i in $(HFILES); do rm $$i; done
+
+%::
+ $(MAKE) $@
+
+
+
+
--- /dev/null
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=1_deprecated
+DOCDIR=1_doc
+EXECSDIR=1_execs
+HDIR=1_headers
+LIBDIR=1_lib
+TESTDIR=1_tests
+TMPDIR=1_tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=1_try
+
+
+# compiler and flags
+CC=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-L1_lib -lsubu -lsqlite3
+
+LIB_FILE=$(LIBDIR)/libsubu.a
+
--- /dev/null
+/*
+ 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;
+ }
+}
--- /dev/null
+/*
+ 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;
+ }
+}
+
+
--- /dev/null
+/*
+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;
+ }}}
+
--- /dev/null
+/*
+ subu-rm-0 subuname
+
+ 1. get our uid and lookup masteru_name in /etc/passwd
+ 2. lookup masteru_name/subuname in config file, which gives us subu_username
+ 3. unmount subuland/subuname
+ 4. userdel subu_username
+ 5. rmdir subuland/subuname
+
+ Note, as per the man page, we are not allowed to free the memory allocated by getpwid().
+
+*/
+#include "subu-mk-0.lib.h"
+
+// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#if INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+#endif
+
+//--------------------------------------------------------------------------------
+// an instance is subu_rm_0_ctx is returned by subu_rm_0
+//
+#if INTERFACE
+#define ERR_SUBU_RM_0_MKDIR_SUBUHOME 1
+#define ERR_SUBU_RM_0_RMDIR_SUBUHOME 2
+#define ERR_SUBU_RM_0_SUBUNAME_MALFORMED 3
+#define ERR_SUBU_RM_0_SETUID_ROOT 4
+#define ERR_SUBU_RM_0_MASTERU_HOMELESS 5
+#define ERR_SUBU_RM_0_MALLOC 6
+#define ERR_SUBU_RM_0_CONFIG_FILE 7
+#define ERR_SUBU_RM_0_SUBUHOME_EXISTS 8
+#define ERR_SUBU_RM_0_BUG_SSS 9
+#define ERR_SUBU_RM_0_FAILED_USERADD 10
+
+struct subu_rm_0_ctx{
+ char *name;
+ char *subuland;
+ char *subuhome;
+ char *subu_username;
+ bool free_aux;
+ char *aux;
+ uint err;
+};
+#endif
+struct subu_rm_0_ctx *subu_rm_0_ctx_mk(){
+ struct subu_rm_0_ctx *ctxp = malloc(sizeof(struct subu_rm_0_ctx));
+ ctxp->name = "subu_rm_0";
+ ctxp->subuland = 0;
+ ctxp->subuhome = 0;
+ ctxp->subu_username = 0;
+ ctxp->free_aux = false;
+ ctxp->aux = 0;
+}
+void subu_rm_0_ctx_free(struct subu_rm_0_ctx *ctxp){
+ free(ctxp->subuland);
+ free(ctxp->subuhome);
+ free(ctxp->subu_username);
+ if(ctxp->free_aux) free(ctxp->aux);
+ free(ctxp);
+}
+// must be called before any system calls, otherwise perror() will be messed up
+void subu_rm_0_mess(struct subu_rm_0_ctx *ctxp){
+ switch(ctxp->err){
+ case 0: return;
+ case ERR_SUBU_RM_0_MKDIR_SUBUHOME:
+ fprintf(stderr, "masteru could not make subuhome, \"%s\"", ctxp->subuhome);
+ break;
+ case ERR_SUBU_RM_0_SUBUNAME_MALFORMED:
+ fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", ctxp->aux);
+ break;
+ case ERR_SUBU_RM_0_SETUID_ROOT:
+ fprintf(stderr, "This program must be run setuid root from a user account.");
+ break;
+ case ERR_SUBU_RM_0_MASTERU_HOMELESS:
+ fprintf(stderr,"Masteru, \"%s\", has no home directory", ctxp->aux);
+ break;
+ case ERR_SUBU_RM_0_MALLOC:
+ perror(ctxp->name);
+ break;
+ case ERR_SUBU_RM_0_CONFIG_FILE:
+ fprintf(stderr, "config file error: %s", ctxp->aux);
+ break;
+ case ERR_SUBU_RM_0_SUBUHOME_EXISTS:
+ fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", ctxp->subuhome);
+ break;
+ case ERR_SUBU_RM_0_BUG_SSS:
+ perror(ctxp->name);
+ break;
+ case ERR_SUBU_RM_0_FAILED_USERADD:
+ fprintf(stderr, "%u useradd failed\n", ctxp->subu_username);
+ break;
+ default:
+ fprintf(stderr, "unknown error code %d\n", ctxp->err);
+ }
+ fputc('\n', stderr);
+}
+
+//--------------------------------------------------------------------------------
+// dispatched functions
+//
+// the making of subuhome is dispatched to its own process so as to give it its own uid/gid
+static int masteru_mkdir_subuhome(void *arg){
+ char *subuhome = (char *) arg;
+ if( mkdir( subuhome, subuhome_perms ) == -1 ){ // find subuhome perms in common
+ perror("masteru_mkdir_subuhome");
+ return ERR_SUBU_RM_0_MKDIR_SUBUHOME;
+ }
+ return 0;
+}
+static int masteru_rmdir_subuhome(void *arg){
+ char *subuhome = (char *) arg;
+ if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
+ perror("masteru_rmdir_subuhome");
+ return ERR_SUBU_RM_0_RMDIR_SUBUHOME;
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------------------------
+// the public call point
+struct subu_rm_0_ctx *subu_rm_0(sqlite3 *db, char *subuname){
+
+ struct subu_rm_0_ctx *ctxp = subu_rm_0_ctx_mk();
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("Checking that subuname is well formed and finding its length\n");
+ #endif
+ size_t subuname_len;
+ {
+ int ret = allowed_subuname(subuname, &subuname_len);
+ if( ret == -1 ){
+ ctxp->err = ERR_SUBU_RM_0_SUBUNAME_MALFORMED;
+ ctxp->aux = subuname;
+ return ctxp;
+ }}
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("Checking that we are running from a user and are setuid root.\n");
+ #endif
+ uid_t masteru_uid;
+ gid_t masteru_gid;
+ uid_t set_euid;
+ gid_t set_egid;
+ {
+ masteru_uid = getuid();
+ masteru_gid = getgid();
+ set_euid = geteuid();
+ set_egid = getegid();
+ #ifdef DEBUG
+ 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 ){
+ ctxp->err = ERR_SUBU_RM_0_SETUID_ROOT;
+ return ctxp;
+ }
+ }
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("strings masteru_name and masteru_home\n");
+ #endif
+
+ char *masteru_name;
+ size_t masteru_name_len;
+ char *masteru_home;
+ size_t masteru_home_len;
+ size_t subuland_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\" %zu\n", masteru_name, masteru_name_len);
+ #endif
+ masteru_home = masteru_pw_record_pt->pw_dir;
+ masteru_home_len = strlen(masteru_home);
+ #ifdef DEBUG
+ 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] == '(' ){
+ ctxp->err = ERR_SUBU_RM_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/"; // moved to common.lib.c
+ size_t subuland_extension_len = strlen(subuland_extension);
+ ctxp->subuland = (char *)malloc( masteru_home_len + subuland_extension_len + 1 );
+ if(!ctxp->subuland){
+ ctxp->err = ERR_SUBU_RM_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\" %zu\n", ctxp->subuland, subuland_len);
+ #endif
+ }
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("lookup subu_username from masteru_name/subuname in config file\n");
+ #endif
+ char *subu_username; // this is part of ctx and must be freed
+ {
+ int ret = subu_get_masteru_subu(db, masteru_name, subuname, &subu_username);
+ if( ret != SQLITE_DONE ){
+ printf("get failed\n");
+ return 2;
+ }
+ #ifdef DEBUG
+ printf("subu_username: %s\n", subu_username);
+ #endif
+
+ }
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("strings subu_username and subuhome\n");
+ #endif
+ size_t subu_username_len;
+ size_t subuhome_len;
+ {
+ char *ns=0; // 'ns' Number as String
+ char *mess=0;
+ if( subu_number_get( db, &ns, &mess ) != SQLITE_OK ){
+ ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
+ ctxp->aux = mess;
+ ctxp->free_aux = true;
+ return ctxp;
+ }
+ size_t ns_len = strlen(ns);
+ ctxp->subu_username = malloc(1 + ns_len + 1);
+ if( !ctxp->subu_username ){
+ ctxp->err = ERR_SUBU_RM_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 + subuname_len;
+ ctxp->subuhome = (char *)malloc(subuhome_len + 1);
+ if( !ctxp->subuhome ){
+ ctxp->err = ERR_SUBU_RM_0_MALLOC;
+ return ctxp;
+ }
+ strcpy (ctxp->subuhome, ctxp->subuland);
+ strcpy (ctxp->subuhome + subuland_len, subuname);
+ #ifdef DEBUG
+ dbprintf("subuhome \"%s\" %zu\n", ctxp->subuhome, subuhome_len);
+ #endif
+ }
+
+ //--------------------------------------------------------------------------------
+ // By having masteru create the subuhome, we know that masteru has rights to
+ // to access this directory. This will be the mount point for bindfs
+ {
+ #ifdef DEBUG
+ dbprintf("as masteru, making the directory \"%s\"\n", ctxp->subuhome);
+ #endif
+ struct stat st;
+ if( stat(ctxp->subuhome, &st) != -1 ){
+ ctxp->err = ERR_SUBU_RM_0_SUBUHOME_EXISTS;
+ return ctxp;
+ }
+ dispatch_ctx *dfr = dispatch_f_euid_egid
+ (
+ "masteru_mkdir_subuhome",
+ masteru_mkdir_subuhome,
+ (void *)ctxp->subuhome,
+ masteru_uid,
+ masteru_gid
+ );
+ if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME ){
+ #ifdef DEBUG
+ if( dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME )
+ perror("mkdir");
+ else
+ dispatch_f_mess(dfr);
+ #endif
+ ctxp->err = ERR_SUBU_RM_0_MKDIR_SUBUHOME;
+ return ctxp;
+ }
+ }
+ #ifdef DEBUG
+ dbprintf("masteru made directory \"%s\"\n", ctxp->subuhome);
+ #endif
+
+ //--------------------------------------------------------------------------------
+ // Make the subservient user account, i.e. the subu
+ {
+ #ifdef DEBUG
+ 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 ){
+ ctxp->err = ERR_SUBU_RM_0_BUG_SSS;
+ return ctxp;
+ }
+ #endif
+ char *command = "/usr/sbin/useradd";
+ char *argv[3];
+ argv[0] = command;
+ argv[1] = ctxp->subu_username;
+ argv[2] = (char *) NULL;
+ char *envp[1];
+ envp[0] = (char *) NULL;
+ 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
+ // go back and remove the directory we made in subuland
+ dispatch_ctx *dfr = dispatch_f_euid_egid
+ (
+ "masteru_rmdir_subuhome",
+ masteru_rmdir_subuhome,
+ (void *)ctxp->subuhome,
+ masteru_uid,
+ masteru_gid
+ );
+ #ifdef DEBUG
+ if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
+ if( dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
+ perror("rmdir");
+ else
+ dispatch_f_mess(dfr);
+ #endif
+ ctxp->err = ERR_SUBU_RM_0_FAILED_USERADD;
+ return ctxp;
+ }
+ #ifdef DEBUG
+ dbprintf("added user \"%s\"\n", ctxp->subu_username);
+ #endif
+ }
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("setting the masteru_name, subuname, subu_username relation\n");
+ #endif
+ {
+ int ret = subu_put_masteru_subu(db, masteru_name, subuname, ctxp->subu_username);
+ if( ret != SQLITE_DONE ){
+ ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
+ ctxp->aux = "insert of masteru subu relation failed";
+ return ctxp;
+ }
+ }
+
+ #ifdef DEBUG
+ dbprintf("finished subu-mk-0(%s)\n", subuname);
+ #endif
+ ctxp->err = 0;
+ return ctxp;
+}
--- /dev/null
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include "subudb-number-next.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+ if( argc != 2 ){
+ fprintf(stderr, "usage: %s masteru_name \n",argv[0]);
+ return SUBU_ERR_ARG_CNT;
+ }
+ char *masteru_name = argv[1];
+
+ int rc;
+ sqlite3 *db;
+ rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( rc != SQLITE_OK ){
+ sqlite3_close(db);
+ fprintf(stderr, "error exit, could not open db file\n");
+ return SUBU_ERR_DB_FILE;
+ }
+
+ // read and print the current max
+ char *mess;
+ int n;
+ rc = subudb_number_next(db, masteru_name, &n, &mess);
+ if( rc == SQLITE_DONE ){
+ printf("%d\n", n);
+ }else{
+ fprintf(stderr, "subudb_number_next indicates failure by returning %d\n",rc);
+ fprintf(stderr, "and issues message, %s\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return SUBU_ERR_DB_FILE;
+ }
+ rc = sqlite3_close(db);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+}
--- /dev/null
+
+
+filename.tag.extension
+
+extension:
+ .c for C source
+ .cc for C++ source
+ .h for C header file
+ .hh for C++ header file
+ .o an object file
+
+tag:
+ .lib. The resulting .o file to be placed in release library and is part of the
+ programming interface.
+ .aux. The resulting.o file not directly part of the programming interface, but
+ it might be called by functions that are.
+ .cli. The source file has a main call and is to be relased as part of the command line interface
+ .loc. file has a main call to be made into a local uitlity function
+
+We carry the source file tag and extension to the .o file. We do not put tags
+nor extensions on command line executables.
+
+local_common.h should be included in all source files
--- /dev/null
+these are the comments from my RT makefile:
+
+#
+# 2010 11 20 TWL Created
+# 2011 05 26 TWL Modified to generalize
+# 2012 02 23 NLS Add ECHO variable to use on different environnement
+# corrected setup macro --> add include directory in the path to copy
+# corrected install macro --> change the name of installed library : lib$(LIB)$(LIBSUFFIX)
+# changed DOC_DIR directory name to 5_documents
+# 2012 02 23 TWL removed LIB variable which is now set from the command line so
+# so that all source dirs can use the same makefile
+# 2012 02 23 TWL added target make dist_clean which also deletes the 2_makefile_deps file
+# 2012 04 11 AWW added creation of temporary disk before each test is run
+# 2012 06 05 TWL moved tests and try .cc files to directories. caused rtmake tests to
+# dist_clean and make deps
+#
+#
+#----------------------------------------------------------------------------
+# use this makefile to compile and test the code:
+#
+# for a first time run, or for regression use the following:
+#
+# $ make setup # makes the directories, though should already exist
+# $ make regress
+#
+# the usual development workflow makes use of these:
+#
+# $ make deps # only when needed, for example if headers includes change or new files introduced
+# $ cd tests; make deps # only when needed
+# $ make lib # this makes the local library
+# $ make tests # this updates tests and compiles
+# $ make clean # deletes the .o files and library to force a recompile
+# $ cd 1_tests; make clean
+#
+# for a release of a component
+#
+# $ make regress
+# $ make install # this will only work if all the tests in 1_tests are passing
+#
+# before a checkin
+#
+# $ make dist_clean # will also clean the tests and try directories
+#
+# .lib.cc c++ files taken as source of object files for local build library
+# .exl.cc c++ files taken to have main calls and are linked against local build libary
+# .ex.cc c++ files taken to have main calls and are not linked against the local build library
+# there are no rules for other files in this makefile
+#
+# about dependencies
+# The makefile has no way of knowing if an edit changed the dependencies. Often they do not
+# and it would be unwieldy to make the deps every time. Hence *the programmer* must delete
+# the deps file if he has made any changes that change the dependencies.
+#
+# The makefile will make the 2_makefile_deps if the file is missing.
+#
+#
+# about testing
+#
+# the name of the directory you run make in is taken to also be: the name of the library,
+# the name of the main include file (with a .h added), and the name of the include directory
+# where the individual headers are found. It is called LIB
+#
+# test programs are kept in a subdirectory called 1_tests, and are either .exl.cc, ex.cc,
+# .sh files. When 'make tests' target is invoked they are all run. Test executables return 0
+# if the test fails, non-zero otherwise.
+#
+# to remove a test from the pool move it into the subdirectory in 1_tests, 9_broken,
+# 5_more_tests of 5_scratch. broken tests are things that are known but must be fixed
+# before a release. 5_more_tests are tests being worked on. 5_scratch is stuff that is
+# probably going to be deleted. if there is a 5_deprecated, that is for good stuff but it
+# is no longer used for some reason or other.
+#
+# There is a standard source code template and a
+# messaging convention. Also, the names, by convention,are test_xxxx_ where xxx is a
+# hexadecimal series nummber. If all the test executables pass the file 1_TESTS_PASSED is
+# left in the directory. Otherwise the file 1_TESTS_FAILED is left in the directory.
+#
+# about release directory
+#
+# this is set in the ApplicationBase variable by rt_init
+#
+# after the tests pass stuff might be copied to the release directory using
+#
+# make install
+#
+# the release directory must have these subdirectories:
+#
+# bin documents include src
+#
+#
+#
--- /dev/null
+
+This worked to force the include to be part of the interface:
+
+#if INTERFACE
+#include <sqlite3.h>
+#endif
+
+But this did not:
+
+#if INTERFACE
+ #include <sqlite3.h>
+#endif
+
+makeheaders looks to be sensitive to indentation
+
+
--- /dev/null
+
+1.
+ This sql:
+
+ 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;"
+ ;
+
+ with sqlite_exec, the call back is called with the data from the select.
+
+ with sqlite_prepare_v2, sqlite_step just returns SQLITE_DONE, and we never
+ get to see our data from the select.
--- /dev/null
+2019-02-05T23:14:40Z
+ error can cause subu-mk-0 to leave the creating of a subu in an intermediate
+ state. Rather than bailing on some of the errors we need to clean up instead.
+ Perhaps the yet to be written subu-rm program will be resilent enough to do
+ more general cleanup.
+
+2019-02-23T18:56:31Z
+ need to modify subu-init to take a configuration file name argument instead of
+ using a global variabel value. might want to add arguments to other subu
+ commands also
+
+2019-03-11T13:48:03Z
+ in subu.lib.c append cascading rmdir failure mess to useradd failure mess
+
+2019-03-11T13:48:03Z
+ want to add subu-type to masteru_subu(), I imagine there will be static,
+ permanent, and temporary subu types.
+
+2019-03-12T18:35:06Z
+ the masteru subu relation should contain the uid of the masteru as
+ well as the backup type for the subu: git, rdiff, rsync, none.
+ and the persisitance fo the subu: indefinite, session.
+ seems that operations need to be logged, in case the db is lost
+ the transcript can be played back. It should also be possible
+ to co-opt an existing user as a subu, though, would require
+ sudo privs.
+
+ need to add messages for subu errors I've added to the end of
+ the list in subu.lib.c
+
+2019-03-14T10:43:50Z
+
+ should mod all to he subudb routines to return a message, probably
+ strdup(sqlite_errmsg(db)), then the callers to these routines can just pass
+ mess in rather than making up new ones for each situation. The error code
+ probably already carries the contexts specific message. Or perhaps add
+ a string cat function for message strings, that would run through a stream
+ and free the originals.
--- /dev/null
+# src/1_tests/0_makefile
+
+SHELL=/bin/bash
+
+-include 0_makefile_flags
+
+MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
+
+SOURCES=$(wildcard *.c)
+HFILES=$(wildcard *.h)
+
+all: version deps lib execs
+
+deps:
+ makeheaders $(SOURCES) $(HFILES)
+ sed -i '/^ *int *main *(.*)/d' *.h
+ $(MAKE) $@
+
+clean:
+ $(MAKE) $@
+ for i in $(HFILES); do rm $$i; done
+
+dist-clean:
+ $(MAKE) $@
+ if [ -f subudb ]; then rm subudb; fi
+
+%::
+ $(MAKE) $@
+
+
+
+
--- /dev/null
+
+# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
+ECHO= echo
+#ECHO= echo -e
+
+# directories used by this makefile, these could all be set to dot for
+# the simplest source directory structure
+
+#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
+#$(PWD) is the directory that make was called from, this is already build in
+#set to dot to use the same directory as the source code
+#leave blank to ommit
+DEPRDIR=
+DOCDIR=
+EXECSDIR=.
+HDIR=.
+LIBDIR=.
+TESTDIR=.
+TMPDIR=1_tmp
+TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
+TRYDIR=
+
+
+# compiler and flags
+CC=gcc
+CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB
+#CFLAGS=-std=gnu11 -fPIC -I. -Werror
+LINKFLAGS=-L$(PROJECT_SUBU)/src/$(LIBDIR) -L. -lsubu -lsqlite3 -lsubutests
+
+LIB_FILE=$(LIBDIR)/libtests.a
+
--- /dev/null
+da.cli.o: da.cli.c da.cli.h
+
+./da : da.cli.o ./libtests.a
+ gcc -o ./da da.cli.o -L/home/morpheus/subu_land/subu/src/. -L. -lsubu -lsqlite3 -lsubutests
--- /dev/null
+/*
+Tests for da.
+
+*/
+
+#include <da.cli.h>
+#include <stdbool.h>
+
+int test_da_0(){
+ da da0;
+ da_alloc(&da0, sizeof(int)); // leaves room for 4 ints
+ int i = 0;
+ int *pt = da0->base;
+ // will double, 4 -> 8, then double 8 -> 16
+ while( i < 10 ){
+ if(da_boundq(&da0, pt)){
+ char *old_base = da_expand(&da);
+ da_rebase(&da, old_base, pt);
+ }
+ *pt = i;
+ i++;
+ pt++;
+ }
+
+ bool f0 = da.size == sizof(int) * 16;
+ bool f1 = 10 == (da.end - da.base) / sizeof(int);
+ bool f2 = true;
+ pt = da0->base;
+ while( i < 10 ){
+ f2 = f2 && *pt == i && !da_endq(&da, pt);
+ i++;
+ pt++;
+ }
+ bool f3 = da_endq(&da, pt);
+
+ return f0 && f1 && f2 && f3;
+}
+
+
+int main(){
+
+ bool da_0_passed = test_da_0();
+ if( da_0_passed ){
+ printf("da_0_passed");
+ return 0;
+ }
+ printf("da_0_failed");
+ return 1;
+
+}
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+int test_da_0();
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <stdlib.h>
+#include <stdbool.h>
+void daps_map(char **base,char **end_pt,void f(void *));
+#define RETURN(rc) \
+ { daps_map(mrs, mrs_end, free); return rc; }
+void daps_alloc(char ***base,size_t *s);
+#define MK_MRS \
+ char **mrs; \
+ char **mrs_end; \
+ size_t mrs_size; \
+ daps_alloc(&mrs, &mrs_size);\
+ mrs_end = mrs;
+void daps_push(char ***base,char ***pt,size_t *s,char *item);
+bool daps_bound(char **base,char **pt,size_t s);
+void daps_expand(char ***base,char ***pt,size_t *s);
+void da_map(void *base,void *end_pt,void f(void *),size_t item_size);
+void da_push(void **base,void **pt,size_t *s,void *item,size_t item_size);
+bool da_bound(void *base,void *pt,size_t s);
+void da_expand(void **base,void **pt,size_t *s);
+void da_alloc(void **base,size_t *s,size_t item_size);
+#define INTERFACE 0
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+int dbprintf(const char *format,...);
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sys/types.h>
+#include <unistd.h>
+int dispatch_exec(char **argv,char **envp);
+typedef unsigned int uint;
+int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
+int dbprintf(const char *format,...);
+int dispatch_f(char *fname,int(*f)(void *arg),void *f_arg);
+void dispatch_f_mess(char *fname,int err,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
+typedef struct dispatch_ctx dispatch_ctx;
+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
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+int subu_bind_all(char **mess,sqlite3 *db);
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+extern char Subuland_Extension[];
+typedef unsigned int uint;
+extern uint First_Max_Subunumber;
+extern uint Subuhome_Perms;
+extern char DB_File[];
+#define BUG_SSS_CACHE_RUID 1
+#define INTERFACE 0
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+void subu_err(char *fname,int err,char *mess);
+int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+void subu_err(char *fname,int err,char *mess);
+int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+typedef unsigned int uint;
+#include <sqlite3.h>
+typedef struct subudb_subu_element subudb_subu_element;
+int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
+struct subudb_subu_element {
+ char *subuname;
+ char *subu_username;
+};
+#include <stdbool.h>
+#include <errno.h>
+int subu_bind_all(char **mess,sqlite3 *db);
+int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
+int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
+int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
+int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <sys/types.h>
+#include <unistd.h>
+int dispatch_exec(char **argv,char **envp);
+#define BUG_SSS_CACHE_RUID 1
+void dispatch_f_mess(char *fname,int err,char *dispatchee);
+#define ERR_DISPATCH -1024
+int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
+#include <stdlib.h>
+void daps_map(char **base,char **end_pt,void f(void *));
+#define RETURN(rc) \
+ { daps_map(mrs, mrs_end, free); return rc; }
+void daps_push(char ***base,char ***pt,size_t *s,char *item);
+int dbprintf(const char *format,...);
+void daps_alloc(char ***base,size_t *s);
+#define MK_MRS \
+ char **mrs; \
+ char **mrs_end; \
+ size_t mrs_size; \
+ daps_alloc(&mrs, &mrs_size);\
+ mrs_end = mrs;
+int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
+extern char Subuland_Extension[];
+int db_commit(sqlite3 *db);
+int db_rollback(sqlite3 *db);
+int subudb_number_set(sqlite3 *db,int n);
+int subudb_number_get(sqlite3 *db,int *n);
+int db_begin(sqlite3 *db);
+extern uint Subuhome_Perms;
+extern char DB_File[];
+void subu_err(char *fname,int err,char *mess);
+#define SUBU_ERR_BIND 15
+#define SUBU_ERR_N 14
+#define SUBU_ERR_SUBU_NOT_FOUND 13
+#define SUBU_ERR_FAILED_USERDEL 12
+#define SUBU_ERR_FAILED_USERADD 11
+#define SUBU_ERR_BUG_SSS 10
+#define SUBU_ERR_SUBUHOME_EXISTS 9
+#define SUBU_ERR_DB_FILE 8
+#define SUBU_ERR_HOMELESS 7
+#define SUBU_ERR_SUBUNAME_MALFORMED 6
+#define SUBU_ERR_RMDIR_SUBUHOME 5
+#define SUBU_ERR_MKDIR_SUBUHOME 4
+#define SUBU_ERR_MALLOC 3
+#define SUBU_ERR_SETUID_ROOT 2
+#define SUBU_ERR_ARG_CNT 1
+char *userdel_mess(int err);
+char *useradd_mess(int err);
+#define INTERFACE 0
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int db_commit(sqlite3 *db);
+int db_rollback(sqlite3 *db);
+int subudb_schema(sqlite3 *db);
+int db_begin(sqlite3 *db);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_number_get(sqlite3 *db,int *n);
+int subudb_number_set(sqlite3 *db,int n);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_N 14
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+typedef struct subudb_subu_element subudb_subu_element;
+int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
+struct subudb_subu_element {
+ char *subuname;
+ char *subu_username;
+};
+#include <stdbool.h>
+#include <errno.h>
+#define SUBU_ERR_DB_FILE 8
+extern char DB_File[];
+#define SUBU_ERR_ARG_CNT 1
--- /dev/null
+/* \aThis file was automatically generated. Do not edit! */
+#undef INTERFACE
+#include <sqlite3.h>
+int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+#include <stdlib.h>
+#include <stdbool.h>
+void da_expand(void **base,void **pt,size_t *s);
+bool da_bound(void *base,void *pt,size_t s);
+typedef struct subudb_subu_element subudb_subu_element;
+int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
+void subu_element_free(subudb_subu_element *base,subudb_subu_element *end_pt);
+void da_alloc(void **base,size_t *s,size_t item_size);
+struct subudb_subu_element {
+ char *subuname;
+ char *subu_username;
+};
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
+int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
+int subudb_number_set(sqlite3 *db,int n);
+int subudb_number_get(sqlite3 *db,int *n);
+typedef unsigned int uint;
+extern uint First_Max_Subunumber;
+int subudb_schema(sqlite3 *db);
+int db_rollback(sqlite3 *db);
+int db_commit(sqlite3 *db);
+int db_begin(sqlite3 *db);
+#define INTERFACE 0
--- /dev/null
+/*
+Using preprocessor to make header file?
+
+gcc -E split.c -DPROTOTYPE
+
+Outputs source code source comment lines starting with a hash. Resolves all macro commands,
+hence the resulting header can not have macro commands.
+
+ */
+
+#if PROTOTYPE
+##define GREATNESS 21
+int f(int x);
+#endif
+
+#if IMPLEMENTATION
+int f(int x){
+ return x;
+}
+#endif
--- /dev/null
+/*
+Using preprocessor to make header file?
+
+gcc -E split.c -DPROTOTYPE
+
+Outputs source code source comment lines starting with a hash. Resolves all macro commands,
+hence the resulting header can not have macro commands.
+
+ */
+
+#if PROTOTYPE
+##define GREATNESS 21
+int f(int x);
+#endif
+
+#if IMPLEMENTATION
+int f(int x){
+ return x;
+}
+#endif
--- /dev/null
+/*
+They say a cast is not required passing a typed pointer to a void * argument,
+but What about void **?
+
+gcc -std=gnu11 -o voidptr voidptr.c
+voidptr.c: In function ‘main’:
+voidptr.c:28:5: warning: passing argument 1 of ‘g’ from incompatible pointer type [-Wincompatible-pointer-types]
+ g(&pt, y);
+ ^~~
+voidptr.c:13:15: note: expected ‘void **’ but argument is of type ‘int **’
+ void g(void **pt0, void *pt1){
+ ~~~~~~~^~~
+
+*/
+#include <stdio.h>
+
+int f(void *pt){
+ return *(int *)pt;
+}
+
+/* fails
+void g(void **pt0, int *pt1){
+ *pt0 = pt1;
+}
+*/
+
+// passes
+void g(void *pt0, int *pt1){
+ *(int **)pt0 = pt1;
+}
+
+int main(){
+ int x = 5;
+ int *xp = &x;
+ printf("%d\n",f(xp));
+
+ int y[3];
+ y[0] = 10;
+ y[1] = 11;
+ y[2] = 12;
+
+ int *pt;
+ g(&pt, y);
+ printf("%d\n",*pt);
+
+ printf("that's all folks\n");
+ return 0;
+}
--- /dev/null
+
+#include "subu-common.lib.h"
+
+#if INTERFACE
+typedef unsigned int uint;
+/*
+ Fedora 29's sss_cache is checking the inherited uid instead of the effective
+ uid, so setuid root scripts will fail when calling sss_cache.
+
+ Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root
+ program subu-mk-0.
+*/
+#define BUG_SSS_CACHE_RUID 1
+#endif
+
+// char *DB_File = "/etc/subudb";
+char DB_File[] = "subudb";
+uint Subuhome_Perms = 0700;
+uint First_Max_Subunumber = 114;
+char Subuland_Extension[] = "/subuland/";
--- /dev/null
+/*
+The db file is maintained in SQLite
+
+Because user names of are of limited length, subu user names are always named _s<number>.
+A separate table translates the numbers into the subu names.
+
+The first argument is the biggest subu number in the system, or one minus an
+starting point for subu numbering.
+
+currently a unit converted to base 10 will always fit in a 21 bit buffer.
+
+Each of these returns SQLITE_OK upon success
+*/
+#include "subudb.lib.h"
+
+#if INTERFACE
+#include <sqlite3.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+//--------------------------------------------------------------------------------
+// sqlite transactions don't nest. There is a way to use save points, but still
+// we can't just nest transactions. Instead use these wrappers around the whole
+// of something that needs to be in a transaction.
+int db_begin(sqlite3 *db){
+ return sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
+}
+int db_commit(sqlite3 *db){
+ return sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
+}
+int db_rollback(sqlite3 *db){
+ return sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
+}
+
+//--------------------------------------------------------------------------------
+int subudb_schema(sqlite3 *db){
+ int rc;
+
+ { // build tables
+ char sql[] =
+ "CREATE TABLE Masteru_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT);"
+ "CREATE TABLE Attribute_Int(attribute TEXT, value INT);"
+ ;
+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+ if(rc != SQLITE_OK) return rc;
+ }
+
+ { // data initialization
+ char *sql = "INSERT INTO Attribute_Int (attribute, value) VALUES ('Max_Subunumber', ?1);";
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, First_Max_Subunumber);
+ rc = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ if( rc != SQLITE_DONE ) return rc;
+ }
+
+ return SQLITE_OK;
+}
+
+//--------------------------------------------------------------------------------
+int subudb_number_get(sqlite3 *db, int *n){
+ char *sql = "SELECT value FROM Attribute_Int WHERE attribute = 'Max_Subunumber';";
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ int rc = sqlite3_step(stmt);
+ if( rc == SQLITE_ROW ){
+ *n = sqlite3_column_int(stmt,0);
+ rc = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ if( rc != SQLITE_DONE ) return rc;
+ return SQLITE_OK;
+ }
+ // should have a message return, suppose
+ sqlite3_finalize(stmt);
+ return SQLITE_NOTFOUND;
+}
+
+int subudb_number_set(sqlite3 *db, int n){
+ int rc;
+ char *sql = "UPDATE Attribute_Int SET value = ?1 WHERE attribute = 'Max_Subunumber';";
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ sqlite3_bind_int(stmt, 1, n);
+ rc = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ if( rc == SQLITE_DONE ) return SQLITE_OK;
+ return rc;
+}
+
+//--------------------------------------------------------------------------------
+// put relation into Masteru_Subu table
+int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
+ char *sql = "INSERT INTO Masteru_Subu VALUES (?1, ?2, ?3);";
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+ sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
+ int rc = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ if( rc == SQLITE_DONE ) return SQLITE_OK;
+ return rc;
+}
+
+//--------------------------------------------------------------------------------
+int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username){
+ char *sql = "SELECT subu_username FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2;";
+ size_t sql_len = strlen(sql);
+ sqlite3_stmt *stmt;
+ int rc;
+ rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
+ if( rc != SQLITE_OK ) return rc;
+ sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC);
+ rc = sqlite3_step(stmt);
+ if( rc == SQLITE_ROW ){
+ const char *username = sqlite3_column_text(stmt, 0);
+ *subu_username = strdup(username);
+ }else{
+ sqlite3_finalize(stmt);
+ return rc; // woops this needs to return an error!, be sure it is not SQLITE_DONE
+ }
+ rc = sqlite3_step(stmt);
+ if( rc == SQLITE_DONE ) return SQLITE_OK;
+ return rc;
+}
+
+//--------------------------------------------------------------------------------
+
+// we return and array of subudb_subu_info
+#if INTERFACE
+struct subudb_subu_element{
+ char *subuname;
+ char *subu_username;
+};
+#endif
+
+int subudb_Masteru_Subu_get_subus
+(
+ sqlite3 *db,
+ char *masteru_name,
+ da *subus
+){
+ char *sql = "SELECT subuname, subu_username"
+ " FROM Masteru_Subu"
+ " WHERE masteru_name = ?1;";
+ size_t sql_len = strlen(sql);
+ sqlite3_stmt *stmt;
+ int rc;
+ rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
+ if( rc != SQLITE_OK ) return rc;
+ sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
+
+ da_alloc(subus, sizeof(subudb_subu_element));
+ subudb_subu_element *pt = (subudb_subu_element *)subus->base;
+ rc = sqlite3_step(stmt);
+ while( rc == SQLITE_ROW ){
+ if( da_boundq(subus, pt) ){
+ char *old_base = da_expand(subus);
+ da_rebase(subus, old_base, pt);
+ }
+ pt->subuname = strdup(sqlite3_column_text(stmt, 0));
+ pt->subu_username = strdup(sqlite3_column_text(stmt, 1));
+ rc = sqlite3_step(stmt);
+ pt++;
+ }
+ sqlite3_finalize(stmt);
+ if( rc != SQLITE_DONE ) return rc;
+ return SQLITE_OK;
+}
+
+//--------------------------------------------------------------------------------
+int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
+ char *sql = "DELETE FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2 AND subu_username = ?3;";
+ size_t sql_len = strlen(sql);
+ sqlite3_stmt *stmt;
+ int rc;
+ rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
+ if( rc != SQLITE_OK ) return rc;
+ sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
+ rc = sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ if( rc == SQLITE_DONE ) return SQLITE_OK;
+ return rc;
+}
--- /dev/null
+/*
+mount all the subu user directories into master's subuland
+uses unmount to undo this
+
+*/
+#include "subu-bind-all.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+ if( argc != 1){
+ fprintf(stderr, "%s does not take arguments\n",argv[0]);
+ return SUBU_ERR_ARG_CNT;
+ }
+
+ int rc;
+ sqlite3 *db;
+ rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+ return SUBU_ERR_DB_FILE;
+ }
+
+ char *mess;
+ rc = subu_bind_all(&mess, db);
+ if(rc != 0){
+ fprintf(stderr, "subu-bind: %s\n", mess);
+ return rc;
+ }
+ return 0;
+}
--- /dev/null
+/*
+mount a subu user directory into master's subuland
+uses unmount to undo this
+
+*/
+#include "subu-bind.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+ if( argc != 4){
+ fprintf(stderr, "usage: %s masteru subu_username subuhome\n",argv[0]);
+ return SUBU_ERR_ARG_CNT;
+ }
+
+ int rc;
+ char *mess;
+ rc = subu_bind(&mess, argv[1], argv[2], argv[3]);
+ if(rc != 0){
+ fprintf(stderr, "subu-bind: %s\n", mess);
+ return rc;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ subu-mk-0 command
+
+*/
+#include "subu-mk-0.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+ char *command = argv[0];
+ if( argc != 2 ){
+ fprintf(stderr, "usage: %s subu", command);
+ return SUBU_ERR_ARG_CNT;
+ }
+ char *subuname = argv[1];
+
+ int rc;
+ sqlite3 *db;
+ rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "error when opening db, %s\n", DB_File);
+ fprintf(stderr, "sqlite3 says: %s\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return SUBU_ERR_DB_FILE;
+ }
+
+ char *mess;
+ rc = subu_mk_0(&mess, db, subuname);
+ if( rc ){
+ subu_err("subu_mk_0", rc, mess);
+ free(mess);
+ sqlite3_close(db);
+ return rc;
+ }
+
+ rc = sqlite3_close(db);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+
+}
--- /dev/null
+/*
+ subu-mk-0 command
+
+*/
+#include "subu-rm-0.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+ char *command = argv[0];
+ if( argc != 2 ){
+ fprintf(stderr, "usage: %s subu", command);
+ return SUBU_ERR_ARG_CNT;
+ }
+ char *subuname = argv[1];
+
+ sqlite3 *db;
+ {
+ int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
+ return SUBU_ERR_DB_FILE;
+ }}
+
+ {
+ char *mess=0;
+ int ret = subu_rm_0(&mess, db, subuname);
+ subu_err("subu_rm_0", ret, mess);
+ free(mess);
+ return ret;
+ }
+}
--- /dev/null
+/*
+ sqllite3 is used to maintain the db file, which is currently compiled
+ in as /etc/subu.db, (or just subu.db for testing).
+
+ masteru is the user who ran this script. The masteru name comes from getuid
+ and /etc/passwd.
+
+ subu is a subservient user. The subuname is passed in as an argument.
+
+ subu-mk-0 synthesizes a new user user name s<number>, calls useradd to creat
+ the new uswer account, and enters the relationship between masteru, subu, and
+ s<number> in the db file. It is this relation in the db file that
+ associates the subuname with the s<number> user.
+
+ subu-rm-0 uses userdel to delete the related s<number> user account. It
+ then removes the relaton from the db file.
+
+ subu-mk-0 and subu-rm-0 are setuid root scripts.
+
+*/
+#include "subu.lib.h"
+
+// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#if INTERFACE
+#include <stdbool.h>
+#include <errno.h>
+#include <sqlite3.h>
+#endif
+
+//--------------------------------------------------------------------------------
+// dispatched command errors .. should add mkdir and rmdir ...
+//
+char *useradd_mess(int err){
+ if(err <= 0) return NULL;
+ char *mess;
+ switch(err){
+ case 1: mess = "can't update password file"; break;
+ case 2: mess = "invalid command syntax"; break;
+ case 3: mess = "invalid argument to option"; break;
+ case 4: mess = "UID already in use (and no -o)"; break;
+ case 5: mess = "undefined"; break;
+ case 6: mess = "specified group doesn't exist"; break;
+ case 7:
+ case 8: mess = "undefined"; break;
+ case 9: mess = "username already in use"; break;
+ case 10: mess = "can't update group file:"; break;
+ case 11: mess = "undefined"; break;
+ case 12: mess = "can't create home directory"; break;
+ case 13: mess = "undefined"; break;
+ case 14: mess = "can't update SELinux user mapping"; break;
+ default: mess = "undefined"; break;
+ }
+ return strdup(mess);
+}
+char *userdel_mess(int err){
+ if(err <= 0) return NULL;
+ char *mess;
+ switch(err){
+ case 1: mess = "can't update password file"; break;
+ case 2: mess = "invalid command syntax"; break;
+ case 3:
+ case 4:
+ case 5: mess = "undefined"; break;
+ case 6: mess = "specified user doesn't exist"; break;
+ case 7:
+ case 8:
+ case 9: mess = "undefined"; break;
+ case 10: mess = "can't update group file:"; break;
+ case 11: mess = "undefined"; break;
+ case 12: mess = "can't remove home directory"; break;
+ default: mess = "undefined"; break;
+ }
+ return strdup(mess);
+}
+
+
+//--------------------------------------------------------------------------------
+//
+#if INTERFACE
+#define SUBU_ERR_ARG_CNT 1
+#define SUBU_ERR_SETUID_ROOT 2
+#define SUBU_ERR_MALLOC 3
+#define SUBU_ERR_MKDIR_SUBUHOME 4
+#define SUBU_ERR_RMDIR_SUBUHOME 5
+#define SUBU_ERR_SUBUNAME_MALFORMED 6
+#define SUBU_ERR_HOMELESS 7
+#define SUBU_ERR_DB_FILE 8
+#define SUBU_ERR_SUBUHOME_EXISTS 9
+#define SUBU_ERR_BUG_SSS 10
+#define SUBU_ERR_FAILED_USERADD 11
+#define SUBU_ERR_FAILED_USERDEL 12
+#define SUBU_ERR_SUBU_NOT_FOUND 13
+#define SUBU_ERR_N 14
+#define SUBU_ERR_BIND 15
+#endif
+
+void subu_err(char *fname, int err, char *mess){
+ if(!mess) mess = "";
+ switch(err){
+ case 0: return;
+ case SUBU_ERR_ARG_CNT:
+ if(mess[0])
+ fprintf(stderr, "Incorrect number of arguments, %s", mess);
+ else
+ fprintf(stderr, "Incorrect number of arguments.", mess);
+ break;
+ case SUBU_ERR_SETUID_ROOT:
+ fprintf(stderr, "This program must be run setuid root from a user account.");
+ break;
+ case SUBU_ERR_MALLOC:
+ perror(fname);
+ break;
+ case SUBU_ERR_DB_FILE:
+ fprintf(stderr, "error on %s", DB_File); // DB_File is in common
+ fprintf(stderr, ": %s", mess);
+ break;
+ case SUBU_ERR_HOMELESS:
+ fprintf(stderr,"Masteru, \"%s\", has no home directory", mess);
+ break;
+ case SUBU_ERR_SUBUNAME_MALFORMED:
+ fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", mess);
+ break;
+ case SUBU_ERR_SUBUHOME_EXISTS:
+ fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", mess);
+ break;
+ case SUBU_ERR_MKDIR_SUBUHOME:
+ fprintf(stderr, "masteru could not make subuhome, \"%s\"", mess);
+ break;
+ case SUBU_ERR_BUG_SSS:
+ perror(fname);
+ break;
+ case SUBU_ERR_FAILED_USERADD:
+ fprintf(stderr, "%s useradd failed\n", mess);
+ break;
+ default:
+ fprintf(stderr, "unknown error code %d\n", err);
+ }
+ fputc('\n', stderr);
+}
+
+
+//--------------------------------------------------------------------------------
+// a well formed subuname
+// returns the length of the subuname, or -1
+//
+static int allowed_subuname(char **mess, char *subuname, size_t *subuname_len){
+ char *ch = subuname;
+ size_t i = 0;
+ while(
+ *ch
+ &&
+ ( *ch >= 'a' && *ch <= 'z'
+ ||
+ *ch >= 'A' && *ch <= 'Z'
+ ||
+ *ch >= '0' && *ch <= '9'
+ ||
+ *ch == '-'
+ ||
+ *ch == '_'
+ ||
+ *ch == '.'
+ ||
+ *ch == ' '
+ )
+ ){
+ ch++;
+ i++;
+ }
+ if( !*ch ){
+ *subuname_len = i;
+ return 0;
+ }else{
+ if(mess) *mess = strdup(subuname);
+ return SUBU_ERR_SUBUNAME_MALFORMED;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// dispatched functions
+//
+static int masteru_mkdir_subuhome(void *arg){
+ char *subuhome = (char *) arg;
+ if( mkdir( subuhome, Subuhome_Perms ) == -1 ){ // find subuhome perms in common
+ perror("masteru_mkdir_subuhome");
+ return SUBU_ERR_MKDIR_SUBUHOME;
+ }
+ return 0;
+}
+static int masteru_rmdir_subuhome(void *arg){
+ char *subuhome = (char *) arg;
+ if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
+ perror("masteru_rmdir_subuhome");
+ return SUBU_ERR_RMDIR_SUBUHOME;
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------------------------
+// build strings
+//
+static int mk_subu_username(char **mess, sqlite3 *db, char **subu_username){
+ int rc,n;
+ db_begin(db);
+ if(
+ (rc = subudb_number_get(db, &n))
+ ||
+ (rc = subudb_number_set(db, ++n))
+ ){
+ db_rollback(db);
+ return SUBU_ERR_DB_FILE;
+ }
+ db_commit(db);
+
+ size_t len = 0;
+ FILE* name_stream = open_memstream(subu_username, &len);
+ fprintf(name_stream, "s%d", n);
+ fclose(name_stream);
+ return 0;
+}
+
+// man page says that getpwuid strings may not be freed, I don't know how long until they
+// are overwritten, so I just make my own copies that can be freed
+static int uid_to_name_and_home(uid_t uid, char **name, char **home ){
+ struct passwd *pw_record_pt = getpwuid(uid); // reading /etc/passwd
+ *name = strdup(pw_record_pt->pw_name);
+ *home = strdup(pw_record_pt->pw_dir);
+ if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
+ return 0;
+}
+
+static int username_to_home(char *name, char **home ){
+ struct passwd *pw_record_pt = getpwnam(name); // reading /etc/passwd
+ *home = strdup(pw_record_pt->pw_dir);
+ if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
+ return 0;
+}
+
+static int mk_subuland(char *masteru_home, char **subuland){
+ size_t masteru_home_len = strlen(masteru_home);
+ char *Subuland_Extension = "/subuland/";
+ size_t Subuland_Extension_len = strlen(Subuland_Extension);
+ *subuland = (char *)malloc( masteru_home_len + Subuland_Extension_len + 1 );
+ if(!*subuland) SUBU_ERR_MALLOC;
+ strcpy(*subuland, masteru_home);
+ strcpy(*subuland + masteru_home_len, Subuland_Extension);
+ return 0;
+}
+
+static int mk_subuhome(char *subuland, char *subuname, char **subuhome){
+ size_t subuland_len = strlen(subuland);
+ size_t subuhome_len = subuland_len + strlen(subuname); // subuland has a trailing '/'
+ *subuhome = (char *)malloc(subuhome_len + 1);
+ if(!*subuhome) return SUBU_ERR_MALLOC;
+ strcpy (*subuhome, subuland);
+ strcpy (*subuhome + subuland_len, subuname);
+ return 0;
+}
+
+
+
+//===============================================================================
+int subu_mk_0(char **mess, sqlite3 *db, char *subuname){
+
+ int rc;
+ if(mess)*mess = 0;
+ da resources;
+ da_alloc(&resources, sizeof(char *));
+
+ //--------------------------------------------------------------------------------
+ size_t subuname_len;
+ rc = allowed_subuname(mess, subuname, &subuname_len);
+ if(rc) return rc;
+ #ifdef DEBUG
+ dbprintf("subuname is well formed\n");
+ #endif
+
+ //--------------------------------------------------------------------------------
+ uid_t masteru_uid;
+ gid_t masteru_gid;
+ uid_t set_euid;
+ gid_t set_egid;
+ {
+ masteru_uid = getuid();
+ masteru_gid = getgid();
+ set_euid = geteuid();
+ set_egid = getegid();
+ #ifdef DEBUG
+ 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 ) return SUBU_ERR_SETUID_ROOT;
+ }
+
+ //--------------------------------------------------------------------------------
+ char *masteru_name = 0;
+ char *masteru_home = 0;
+ char *subu_username = 0;
+ char *subuland = 0;
+ char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+ da_push(&resources, masteru_name);
+ da_push(&resources, masteru_home);
+ da_push(&resources, subu_username);
+ da_push(&resources, subuland);
+ da_push(&resources, subuhome);
+ rc =
+ uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+ ||
+ mk_subu_username(mess, db, &subu_username)
+ ||
+ mk_subuland(masteru_home, &subuland)
+ ||
+ mk_subuhome(subuland, subuname, &subuhome)
+ ;
+ if(rc) RETURN(&resources, rc);
+ #ifdef DEBUG
+ dbprintf("subu_username, subuland, subuhome: \"%s\"\"%s\"\"%s\"\n", subu_username, subuland, subuhome);
+ #endif
+
+ //--------------------------------------------------------------------------------
+ // By having masteru create the subuhome, we know that masteru has rights to
+ // to access this directory. This will be the mount point for bindfs
+ {
+ struct stat st;
+ if( stat(subuhome, &st) != -1 ){
+ if(mess)*mess = strdup(subuhome);
+ RETURN(&resources, SUBU_ERR_SUBUHOME_EXISTS);
+ }
+ int dispatch_err = dispatch_f_euid_egid
+ (
+ "masteru_mkdir_subuhome",
+ masteru_mkdir_subuhome,
+ (void *)subuhome,
+ masteru_uid,
+ masteru_gid
+ );
+ if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_MKDIR_SUBUHOME ){
+ #ifdef DEBUG
+ dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_mkdir_subuhome");
+ #endif
+ if(mess)*mess = strdup(subuhome);
+ RETURN(&resources, SUBU_ERR_MKDIR_SUBUHOME);
+ }
+ }
+ #ifdef DEBUG
+ dbprintf("made directory \"%s\"\n", subuhome);
+ #endif
+
+ //--------------------------------------------------------------------------------
+ // Make the subservient user account, i.e. the subu
+ {
+ #ifdef DEBUG
+ dbprintf("making subu \"%s\" as user \"%s\"\n", subuname, 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 ) RETURN(&resources, SUBU_ERR_BUG_SSS);
+ #endif
+ char *command = "/usr/sbin/useradd";
+ char *argv[3];
+ argv[0] = command;
+ argv[1] = subu_username;
+ argv[2] = (char *) NULL;
+ char *envp[1];
+ envp[0] = (char *) NULL;
+ int dispatch_err = dispatch_exec(argv, envp);
+ if( dispatch_err != 0 ){
+ #ifdef DEBUG
+ dispatch_f_mess("dispatch_exec", dispatch_err, command);
+ #endif
+ // go back and remove the directory we made in subuland
+ int dispatch_err_rmdir = dispatch_f_euid_egid
+ (
+ "masteru_rmdir_subuhome",
+ masteru_rmdir_subuhome,
+ (void *)subuhome,
+ masteru_uid,
+ masteru_gid
+ );
+ #ifdef DEBUG
+ dispatch_f_mess("dispatch_f_euid_egid", dispatch_err_rmdir, "masteru_rmdir_subuhome");
+ #endif
+ if(mess)*mess = useradd_mess(dispatch_err);
+ RETURN(&resources, SUBU_ERR_FAILED_USERADD);
+ }
+ #ifdef DEBUG
+ dbprintf("added user \"%s\"\n", subu_username);
+ #endif
+ }
+
+ //--------------------------------------------------------------------------------
+ #ifdef DEBUG
+ dbprintf("setting the masteru_name, subuname, subu_username relation\n");
+ #endif
+ {
+ int rc = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
+ if( rc != SQLITE_OK ){
+ if(mess)*mess = strdup("insert of masteru subu relation failed");
+ RETURN(&resources, SUBU_ERR_DB_FILE);
+ }
+ }
+ #ifdef DEBUG
+ dbprintf("finished subu-mk-0(%s)\n", subuname);
+ #endif
+ RETURN(&resources, 0);
+}
+
+//================================================================================
+int subu_rm_0(char **mess, sqlite3 *db, char *subuname){
+
+ int rc;
+ if(mess)*mess = 0;
+ da resources;
+ da_alloc(&resources, sizeof(char *));
+
+ //--------------------------------------------------------------------------------
+ size_t subuname_len;
+ rc = allowed_subuname(mess, subuname, &subuname_len);
+ if(rc) return rc;
+ #ifdef DEBUG
+ dbprintf("subuname is well formed\n");
+ #endif
+
+ //--------------------------------------------------------------------------------
+ uid_t masteru_uid;
+ gid_t masteru_gid;
+ uid_t set_euid;
+ gid_t set_egid;
+ {
+ masteru_uid = getuid();
+ masteru_gid = getgid();
+ set_euid = geteuid();
+ set_egid = getegid();
+ #ifdef DEBUG
+ 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 ) return SUBU_ERR_SETUID_ROOT;
+ }
+
+ //--------------------------------------------------------------------------------
+ // various strings that we will need
+ char *masteru_name = 0;
+ char *masteru_home = 0;
+ char *subuland = 0;
+ char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+ da_push(&resources, masteru_name);
+ da_push(&resources, masteru_home);
+ da_push(&resources, subuland);
+ da_push(&resources, subuhome);
+ rc =
+ uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+ ||
+ mk_subuland(masteru_home, &subuland)
+ ||
+ mk_subuhome(subuland, subuname, &subuhome)
+ ;
+ if(rc) RETURN(&resources, rc);
+ #ifdef DEBUG
+ dbprintf("masteru_home, subuhome: \"%s\", \"%s\"\n", masteru_home, subuhome);
+ #endif
+
+ //--------------------------------------------------------------------------------
+ // removal from db
+ char *subu_username = 0;
+ da_push(&resources, subu_username);
+
+ db_begin(db);
+
+ rc = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
+ if( rc != SQLITE_OK ){
+ if(mess) *mess = strdup("subu requested for removal not found under this masteru in db file");
+ rc = SUBU_ERR_SUBU_NOT_FOUND;
+ db_rollback(db);
+ RETURN(&resources, rc);
+ }
+ #ifdef DEBUG
+ printf("subu_username: \"%s\"\n", subu_username);
+ #endif
+
+ rc = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
+ if( rc != SQLITE_OK ){
+ if(mess)*mess = strdup("removal of masteru subu relation failed");
+ db_rollback(db);
+ RETURN(&resources, SUBU_ERR_DB_FILE);
+ }
+ #ifdef DEBUG
+ dbprintf("removed the masteru_name, subuname, subu_username relation\n");
+ #endif
+
+ rc = db_commit(db);
+ if( rc != SQLITE_OK ){
+ if(mess)*mess = strdup("removal of masteru subu relation in unknown state, exiting");
+ RETURN(&resources, SUBU_ERR_DB_FILE);
+ }
+
+ // even after removing the last masteru subu relation, we still do not remove
+ // the max subu count. Hence, a masteru will keep such for a life time.
+
+
+ //--------------------------------------------------------------------------------
+ // Only masteru can remove directories from masteru/subuland, so we switch to
+ // masteru's uid to perform the rmdir.
+ //
+ {
+ #ifdef DEBUG
+ dbprintf("as masteru, removing the directory \"%s\"\n", subuhome);
+ #endif
+ int dispatch_err = dispatch_f_euid_egid
+ (
+ "masteru_rmdir_subuhome",
+ masteru_rmdir_subuhome,
+ (void *)subuhome,
+ masteru_uid,
+ masteru_gid
+ );
+ if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_RMDIR_SUBUHOME ){
+ #ifdef DEBUG
+ dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_rmdir_subuhome");
+ #endif
+ if(mess)*mess = strdup(subuhome);
+ RETURN(&resources, SUBU_ERR_RMDIR_SUBUHOME);
+ }
+ }
+
+ //--------------------------------------------------------------------------------
+ // Delete the subservient user account
+ {
+ #ifdef DEBUG
+ dbprintf("deleting user \"%s\"\n", 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 ){
+ RETURN(&resources, SUBU_ERR_BUG_SSS);
+ }
+ #endif
+ char *command = "/usr/sbin/userdel";
+ char *argv[4];
+ argv[0] = command;
+ argv[1] = subu_username;
+ argv[2] = "-r";
+ argv[3] = (char *) NULL;
+ char *envp[1];
+ envp[0] = (char *) NULL;
+ int dispatch_err = dispatch_exec(argv, envp);
+ if( dispatch_err != 0 ){
+ #ifdef DEBUG
+ dispatch_f_mess("dispatch_exec", dispatch_err, command);
+ #endif
+ if(mess)*mess = userdel_mess(dispatch_err);
+ RETURN(&resources, SUBU_ERR_FAILED_USERDEL);
+ }
+ #ifdef DEBUG
+ dbprintf("deleted user \"%s\"\n", subu_username);
+ #endif
+ }
+
+ #ifdef DEBUG
+ dbprintf("finished subu-rm-0(%s)\n", subuname);
+ #endif
+ RETURN(&resources, 0);
+}
+
+//================================================================================
+// identifies masteru, the bindfs maps each subu_user's home to its mount point
+// in subuland.
+int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome){
+
+ int rc;
+ if(mess)*mess = 0;
+ da resources;
+ da_alloc(&resources, sizeof(char *));
+
+ // lookup the subu_user_home
+ char *subu_user_home = 0;
+ da_push(&resources, subu_user_home);
+
+ rc = username_to_home(subu_username, &subu_user_home);
+ if( rc ){
+ if(mess) *mess = strdup("in subu_bind, subu user home directory lookup in /etc/passwd failed.");
+ RETURN(&resources, rc);
+ }
+
+ size_t len = 0;
+ char *map = 0;
+ da_push(&resources, map);
+
+ FILE* map_stream = open_memstream(&map, &len);
+ fprintf(map_stream, "--map=%s/%s:@%s/@%s", subu_username, masteru_name, subu_username, masteru_name);
+ fclose(map_stream);
+
+ char *command = "/usr/bin/bindfs";
+ char *argv[5];
+ argv[0] = command;
+ argv[1] = map;
+ argv[2] = subu_user_home;
+ argv[3] = subuhome;
+ argv[4] = (char *) NULL;
+ char *envp[1];
+ envp[0] = (char *) NULL;
+ int dispatch_err = dispatch_exec(argv, envp);
+ if( dispatch_err != 0 ){
+ #ifdef DEBUG
+ dispatch_f_mess(command, dispatch_err, "dispatch_exec");
+ #endif
+ if(mess)*mess = strdup("bind failed");
+ RETURN(&resources, SUBU_ERR_BIND);
+ }
+ #ifdef DEBUG
+ dbprintf("mapped \"%s\" as \"%s\"\n", subu_user_home, subuhome);
+ #endif
+ RETURN(&resources, 0);
+}
+
+int subu_bind_all(char **mess, sqlite3 *db){
+
+ int rc;
+ if(mess)*mess = 0;
+ da resources;
+ da_alloc(&resources, sizeof(char *));
+
+ //--------------------------------------------------------------------------------
+ uid_t masteru_uid;
+ gid_t masteru_gid;
+ uid_t set_euid;
+ gid_t set_egid;
+ {
+ masteru_uid = getuid();
+ masteru_gid = getgid();
+ set_euid = geteuid();
+ set_egid = getegid();
+ #ifdef DEBUG
+ 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 ) return SUBU_ERR_SETUID_ROOT;
+ }
+
+ //--------------------------------------------------------------------------------
+ // various strings that we will need
+ char *masteru_name = 0;
+ char *masteru_home = 0;
+ char *subuland = 0;
+ da_push(&resources, masteru_name);
+ da_push(&resources, masteru_home);
+ da_push(&resources, subuland);
+ rc =
+ uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
+ ||
+ mk_subuland(masteru_home, &subuland)
+ ;
+ if(rc) RETURN(&resources, rc);
+ #ifdef DEBUG
+ if(masteru_name)
+ dbprintf("masteru_name: \"%s\"", masteru_name);
+ else
+ dbprintf("masteru_name unknown");
+ if(subuland)
+ dbprintf("subuland: \"%s\"", subuland);
+ else
+ dbprintf("subuland unknown");
+ dbprintf("\n");
+ #endif
+
+ //--------------------------------------------------------------------------------
+ da subus;
+ rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &subus);
+ if( rc != SQLITE_OK ){
+ if(mess)*mess = strdup("db access failed when fetching a list of subus");
+ return rc;
+ }
+ // a limitation of our error reporting approach is that we can only
+ // return one error, but here is a loop that might generate many
+ rc = 0;
+ char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
+ uint err_cnt = 0;
+ subudb_subu_element *pt = (subudb_subu_element *)(subus.base);
+ while( !da_endq(&subus,pt) ){
+ rc = mk_subuhome(subuland, pt->subuname, &subuhome);
+ #ifdef DEBUG
+ if(subuhome)
+ dbprintf("subuhome: \"%s\"\n", subuhome);
+ else
+ dbprintf("subuhome unknown \n");
+ #endif
+ if(!rc) rc = subu_bind(NULL, masteru_name, pt->subu_username, subuhome);
+ if(rc) err_cnt++;
+ free(subuhome);
+ subuhome=0;
+ pt++;
+ }
+ if(err_cnt==1){
+ RETURN(&resources, rc);
+ }
+ if(err_cnt > 1){
+ *mess = strdup("multiple errors occured while binding subus");
+ RETURN(&resources, SUBU_ERR_BIND);
+ }
+ RETURN(&resources, 0);
+}
--- /dev/null
+/*
+This command initializes the db file.
+
+*/
+#include "subudb-init.cli.h"
+#include <stdio.h>
+
+int main(){
+ sqlite3 *db;
+ if( sqlite3_open(DB_File, &db) != SQLITE_OK ){
+ fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
+ return SUBU_ERR_DB_FILE;
+ }
+ db_begin(db);
+ if( subudb_schema(db) != SQLITE_OK ){
+ db_rollback(db);
+ fprintf(stderr, "error exit, opened db file but could not build schema\n");
+ return SUBU_ERR_DB_FILE;
+ }
+ db_commit(db);
+ if( sqlite3_close(db) != SQLITE_OK ){
+ fprintf(stderr, "error exit, could not close the db\n");
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+}
--- /dev/null
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include "subudb-number.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+ if( argc < 1 || argc > 2){
+ fprintf(stderr, "usage: %s [n]\n",argv[0]);
+ return SUBU_ERR_ARG_CNT;
+ }
+
+ int rc;
+ sqlite3 *db;
+ rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "error exit, could not open db file\n");
+ sqlite3_close(db);
+ return SUBU_ERR_DB_FILE;
+ }
+
+ // then arg[1] holds a number to set the max to
+ if(argc == 2){
+ long int i = strtol(argv[1], NULL, 10);
+ if( i < 0 ){
+ fprintf(stderr, "n must be positive\n");
+ sqlite3_close(db);
+ return SUBU_ERR_N;
+ }
+ if( i > INT_MAX ){
+ fprintf(stderr, "n is too big, max supported by this program is %d\n", INT_MAX);
+ sqlite3_close(db);
+ return SUBU_ERR_N;
+ }
+ rc = subudb_number_set(db, i);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "couldn't set Max_Subunumber: %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_N;
+ }
+ }
+
+ // read and print the current max
+ int n;
+ rc = subudb_number_get(db, &n);
+ if( rc == SQLITE_OK ){
+ printf("%d\n", n);
+ }else{
+ fprintf(stderr, "couldn't get Max_Subunumber: %s\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return SUBU_ERR_DB_FILE;
+ }
+ rc = sqlite3_close(db);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+
+}
--- /dev/null
+/*
+get the username from the db file
+for testing subudb_Masteru_Subu_get_subu_username
+
+*/
+#include "subudb-rel-get.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+ if(argc != 3){
+ fprintf(stderr, "usage: %s masteru_name subuname\n", argv[0]);
+ return SUBU_ERR_ARG_CNT;
+ }
+
+ int rc;
+ sqlite3 *db;
+ rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+ return SUBU_ERR_DB_FILE;
+ }
+
+ char *masteru_name = argv[1];
+ char *subuname = argv[2];
+ char *subu_username;
+
+ int ret = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
+ if( ret != SQLITE_DONE ){
+ fprintf(stderr, "subudb_Masteru_Subu_get_subu_username indicates failure by returning %d\n",ret);
+ fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ ret = sqlite3_close(db);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+ fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+}
--- /dev/null
+/*
+puts a relation in the masteru/subu table
+
+*/
+#include "subudb-rel-put.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+ if(argc != 4){
+ fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
+ return 1;
+ }
+ char *masteru_name = argv[1];
+ char *subuname = argv[2];
+ char *subu_username = argv[3];
+
+ sqlite3 *db;
+ {
+ int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+ return SUBU_ERR_DB_FILE;
+ }}
+
+ int ret = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "subudb_Masteru_Subu_put indicates failure by returning %d\n",ret);
+ fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ ret = sqlite3_close(db);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+ fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+}
--- /dev/null
+/*
+puts a relation in the masteru/subu table
+
+*/
+#include "subudb-rel-rm.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv){
+
+ if(argc != 4){
+ fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
+ return 1;
+ }
+ char *masteru_name = argv[1];
+ char *subuname = argv[2];
+ char *subu_username = argv[3];
+
+ sqlite3 *db;
+ {
+ int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
+ return SUBU_ERR_DB_FILE;
+ }}
+
+ int ret = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
+ if( ret != SQLITE_DONE ){
+ fprintf(stderr, "subudb_Masteru_Subu_rm indicates failure by returning %d\n",ret);
+ fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
+ printf("put failed\n");
+ return 2;
+ }
+ ret = sqlite3_close(db);
+ if( ret != SQLITE_OK ){
+ fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
+ fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+}
--- /dev/null
+/*
+Set or get a new maximum subu number. Currently doesn't do the setting part.
+
+*/
+#include "subudb-subus.cli.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char **argv){
+
+ if( argc != 2){
+ fprintf(stderr, "usage: %s masteru_name\n",argv[0]);
+ return SUBU_ERR_ARG_CNT;
+ }
+ char *masteru_name = argv[1];
+
+ int rc;
+ sqlite3 *db;
+ rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "error exit, could not open db file\n");
+ sqlite3_close(db);
+ return SUBU_ERR_DB_FILE;
+ }
+
+ subudb_subu_element *sa;
+ subudb_subu_element *sa_end;
+ rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
+ if( rc == SQLITE_OK ){
+ subudb_subu_element *pt = sa;
+ while( pt != sa_end ){
+ printf("%s %s\n", pt->subuname, pt->subu_username);
+ pt++;
+ }
+ rc = sqlite3_close(db);
+ if( rc != SQLITE_OK ){
+ fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
+ return SUBU_ERR_DB_FILE;
+ }
+ return 0;
+ }
+ fprintf(stderr, "lookup failed %s\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return SUBU_ERR_DB_FILE;
+
+}
--- /dev/null
+/*
+Dynamic Array
+
+*/
+
+#include "da.lib.h"
+
+#if INTERFACE
+#include<stdlib.h>
+#include<stdbool.h>
+#endif
+#include<string.h>
+
+//--------------------------------------------------------------------------------
+// generic
+// We manipulate pointers to a smallest addressable unit. The sizeof operator
+// returns counts in these addressable units. Sizeof(char) is defined to be 1.
+
+#if INTERFACE
+struct da{
+ char *base;
+ char *end; // one byte/one item off the end of the array
+ size_t size; // size >= (end - base) + 1;
+ size_t item_size;
+};
+#endif
+
+void da_alloc(da *dap, size_t item_size){
+ dap->size = 4 * item_size;
+ dap->item_size = item_size;
+ dap->end = 0;
+ dap->base = malloc(dap->size);
+}
+
+// Doubles size of of da. Returns old base, so that existing pointers into the
+// array can be moved to the new array
+char *da_expand(da *dap){
+ size_t end_offset = ((char *)dap->end - (char *)dap->base);
+ size_t new_size = dap->size << 1;
+ char *old_base = dap->base;
+ char *new_base = malloc( new_size );
+ memcpy( new_base, dap->base, end_offset + 1);
+ free(old_base);
+ dap->base = new_base;
+ dap->end = new_base + end_offset;
+ dap->size = new_size;
+ return old_base;
+}
+
+void da_rebase(da *dap, char *old_base, void *pta){
+ char **pt = (char **)pta;
+ size_t offset = *pt - old_base;
+ *pt = dap->base + offset;
+}
+
+// true when pt has run off the end of the area currently allocated for the array
+bool da_endq(da *dap, void *pt){
+ return (char *)pt >= dap->end;
+}
+
+// true when pt has run off the end of the area allocated for the array
+bool da_boundq(da *dap, void *pt){
+ return (char *)pt >= dap->base + dap->size;
+}
+
+void da_push(da *dap, void *item){
+ if( dap->end + dap->item_size >= dap->base + dap->size ) da_expand(dap);
+ memcpy(dap->end, item, dap->item_size);
+ dap->end += dap->item_size;
+}
+
+// passed in f(item_pt, arg_pt)
+// We have no language support closures, so we pass in an argument for it.
+// The closure may be set to NULL if it is not needed.
+void da_map(da *dap, void f(void *, void *), void *closure){
+ char *pt = dap->base;
+ while( pt != dap->end ){
+ f(pt, closure);
+ pt += dap->item_size;
+ }
+}
+
+// da_lists are sometimes used as resource managers
+void da_free(void *pt, void *closure){
+ free(pt);
+}
+
+#if INTERFACE
+#define RETURN(dap, r) \
+ { da_map(dap, da_free, NULL); return r; }
+#endif
+
--- /dev/null
+
+#include "dbprintf.lib.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+int dbprintf(const char *format, ...){
+ va_list args;
+ va_start(args,format);
+ int ret = vfprintf(stdout, format, args);
+ fflush(stdout);
+ va_end(args);
+ return ret;
+}
--- /dev/null
+/*
+ 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
+void dispatch_f_mess(char *fname, int err, char *dispatchee){
+ if(err == 0) return;
+ fprintf(stderr, "%s: ", fname); // if fprintf gets an error, errno will be overwritten
+ if(err > ERR_DISPATCH){
+ fprintf(stderr, "dispatchee \"%s\" returned the error %d\n", dispatchee, err);
+ return;
+ }
+ switch(err){
+ case ERR_DISPATCH_NEGATIVE_RETURN_STATUS:
+ fprintf(stderr, " dispatchee \"%s\" returned a negative status.", dispatchee);
+ break;
+ case ERR_DISPATCH_F_FORK:
+ case ERR_DISPATCH_F_SETEUID:
+ case ERR_DISPATCH_F_SETEGID:
+ fputc(' ', stderr);
+ perror(dispatchee);
+ break;
+ case ERR_DISPATCH_NULL_EXECUTABLE:
+ fprintf(stderr, " executable was not specified");
+ break;
+ case ERR_DISPATCH_EXEC:
+ // exec is running in another process when it fails, so we can't see the errno value it set
+ fprintf(stderr, " exec of \"%s\" failed", dispatchee);
+ break;
+ default:
+ fprintf(stderr, " returned undefined status when dispatching \"%s\"", dispatchee);
+ }
+ fputc('\n', stderr);
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a function
+int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
+ #ifdef DEBUG
+ dbprintf("%s %s\n", "dispatch_f", fname);
+ #endif
+ pid_t pid = fork();
+ if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
+ 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
+ int err;
+ waitpid(pid, &err, 0);
+ return err;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// 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
+int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
+ #ifdef DEBUG
+ dbprintf("%s %s as euid:%u egid:%u\n", "dispatch_f_euid_egid", fname, euid, egid);
+ #endif
+ pid_t pid = fork();
+ if( pid == -1 ) return ERR_DISPATCH_F_FORK;
+ 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
+ uint err;
+ waitpid(pid, &err, 0);
+ return err;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// interface call point, dispatch a executable
+int dispatch_exec(char **argv, char **envp){
+ char *command;
+ {
+ if( !argv || !argv[0] ) return ERR_DISPATCH_NULL_EXECUTABLE;
+ #ifdef DEBUG
+ dbprintf("dispatch_exec:");
+ char **apt = argv;
+ while( *apt ){
+ dbprintf(" %s",*apt);
+ apt++;
+ }
+ dbprintf("\n");
+ #endif
+ command = argv[0];
+ }
+ pid_t pid = fork();
+ if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
+ if( pid == 0 ){ // we are the child
+ execvpe(command, argv, envp); // exec will only return if it has an error
+ #ifdef DEBUG
+ dbprintf("dispatch_exec: exec returned, perror message:");
+ perror("dispatch_exec"); // our only chance to print this message, as this is the child process
+ #endif
+ fflush(stdout);
+ exit(ERR_DISPATCH_EXEC);
+ }else{ // we are the parent
+ int err;
+ waitpid(pid, &err, 0);
+ return err;
+ }
+}
+
+
--- /dev/null
+#!/usr/bin/python
+# see the help option for syntax
+# this script must be run from root or sudo
+#
+# on Fedora 29 os.getresuid returned all zeros for a script run from sudo.
+# Hence, I am using the environment variable SUDO_USER
+
+import getpass
+import os
+import sys
+import libuser
+from __future__ import print_function
+
+command = os.path.base(argv[0])
+
+#--------------------------------------------------------------------------------
+# utilities
+#
+def prn(str):
+ print(str,end='')
+
+#--------------------------------------------------------------------------------
+# help
+#
+def help():
+ print( command +
+""" [=help] [=version] [shell=<shell>][owner=<owner-username>] [subu=]<subu-username>
+Makes a subservient user.
+If no arguments are given, or if =help is given, this message is printed.
+When this command is invoked through sudo, $SUDO_USER is taken as the owner's username.
+Otherwise, when invoked directly from root, the owner= option must be provided.
+The subu-username argument is the username for the new subservient user
+The the new subu home directory is created in /home/owner/subu/.
+Facls are set to give the owner access to the new subu's home directory.
+The shell option is not implemented yet. Probably need a number of other options also.
+"""
+ )
+
+def version():
+ print(" version 0")
+
+#--------------------------------------------------------------------------------
+# a manager for handling error messages
+#
+class class_err:
+"""
+An error record has the form [flag, message, args]
+ class is fatal, warning, info [currently not implemented]
+ flag is true if an error has occured [need to change this to a count]
+ args is an array of strings to be given after the error message is printed.
+
+The dict holds named error records.
+
+register() is used to name and place error records in the dict. register() is
+typically called multiple times to initialize and error instance.
+
+tattle() is used by the program at run time in order to signal errors.
+
+has_error() returns true if tattle was ever called
+
+report() prints an error report. When errors have occured this
+
+vector() [unimplemented] returns a bit vector with one bit per fatal error
+record, in the order they appear in the dictionary. The bit is set if the error
+ever occured.
+
+We check for as many errors as is convenient to do so rather than stopping on
+the first error.
+"""
+
+ # field offsets into the error record
+ flag_dex = 0;
+ message_dex = 1;
+ args_dex = 2;
+
+ def __init__(self):
+ self.total_cnt = 0
+ self.dict = {}
+
+ def register(name, message):
+ self.dict[name] = [False, message, []]
+
+ def tattle(name, *args):
+ self.total_cnt += 1
+ if name in self.dict:
+ self.dict[name][0] = True
+ self.dict[name][2].extend(args)
+
+ def report():
+ if self.total_cnt:
+ for k,v in self.dict.items():
+ if v[self.flag_dex]:
+ print(v[self.message_dex],end='')
+ args = v[self.args_dex]
+ if length(args) :
+ print(args[0],end='')
+ for arg in args[1:]:
+ print( " " + arg, end='')
+ print()
+
+#--------------------------------------------------------------------------------
+# parse the command line
+#
+err.register(
+ 'impossible_split',
+ "It is not possible, yet this token split into other than one or two pieces: "
+ )
+err.register(
+ 'lone_delim',
+ "No spaces should appear around the '=' delimiter."
+ )
+
+args = sys.argv[1:]
+if len(args) == 0 :
+ version()
+ help()
+ exit(1)
+
+#create a dictionary based on the command line arguments
+arg_dict = {}
+subu_cnt = 0
+delim = '='
+for token in args:
+ token_pair = split(token, delim);
+ if len(token_pair) == 1 : #means there was no '=' in the token
+ arg_dict['subu'] = token_pair
+ subu_cnt++
+ elif len(token_pair) == 2 :
+ if token_pair[0] == '' and token_pair[1] == '' :
+ err.tattle('lone_delim')
+ elif token_pair[1] == '' : # then has trailing delim, will treat the same as a leading delim
+ arg_dict[token_pair[0]] = None
+ elif token_pair[0] == '' : # then has leading delim
+ arg_dict[token_pair[1]] = None
+ else:
+ arg_dict[token_pair[0]] = token_pair[1]
+ else:
+ err.tattle('impossible_split', token)
+
+if not arg_dict or arg_dict.get('help'):
+ help()
+ err.report()
+ exit(1)
+
+if arg_dict.get('version'):
+ version()
+
+#--------------------------------------------------------------------------------
+# check that the command line arguments are well formed.
+#
+err.register(
+ 'too_many_args',
+ command + " takes at most one non-option argument, but we counted: "
+ )
+err.register(
+ 'no_subu'
+ command + " missing subservient username."
+ )
+err.register(
+ 'bad_username'
+ "Usernames match ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$, but found: "
+ )
+err.register(
+ 'unknown_option'
+ command + " doesn't implement option: "
+ )
+
+subu = arg_dict.get('subu')
+if subu_cnt > 1:
+ err.tattle('too_many_args')
+elif not subu
+ err.tattle('no_subu')
+elif not re.match("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$", subu)
+ err.tattle('bad_username', subu)
+
+for k in arg_dict:
+ if k not in ['help', 'version', 'shell', 'owner', 'subu'] :
+ err.tattle('unkown_option', k)
+
+if arg_dict.get('shell') :
+ print "shell option aint implemented yet"
+
+
+
+#--------------------------------------------------------------------------------
+# check that we have root privilege
+#
+err.register(
+ 'not_root'
+ command + "requires root privilege"
+ )
+
+uid = os.getuid()
+if uid != 0 :
+ err.tattle('not root')
+
+username = getpass.getuser()
+sudo_caller_username = os.environ.get('SUDO_USER')
+
+if !sudo_caller_username
+ if username not == "root":
+ err.tattle('not_root')
+ elif:
+ owner
+
+
+ def has_error(*errs):
+ return self.cnt > 0
+
+
+
+#-----
+
+
+
+
+#--------------------------------------------------------------------------------
+# pull out the owner_dir and subu_dir
+#
+admin= libuser.admin()
+
+err_arg_form = class_err()
+err_arg_form.register('too_many', "too many semicolon delineated parts in")
+
+owner_parts = args[0].split(":")
+subu_parts = args[1].split(":")
+
+owner_user_name = owner_parts[0]
+if not owner_user_name:
+ err_arg_form.tattle('owner_user_name_missing', args[0])
+else:
+ owner_user = admin.lookupUserByName(owner_user_name)
+ if owner_user == None:
+ err_arg_form.tattle('no_such_user_name', owner_user_name)
+ else:
+
+
+subu_user_name = subu_parts[0]
+
+
+if length(owner_parts) > 2:
+ err_arg_form.tattle('too_many', args[0])
+elif length(owner_parts) == 2:
+ owner_dir = owner_parts[1]
+else # get the home directory
+
+
+
+
+
+#--------------------------------------------------------------------------------
+# set the home directory
+#
+if len(args) > args_dir_index:
+ dir = args[args_dir_index]
+else:
+ dir = os.getcwd()
+
+home = dir + "/" + name
+home_flag = not os.path.exists(home)
+
+#--------------------------------------------------------------------------------
+# create the user, setfacls
+#
+err_cnt = 0
+name_available_flag = False
+
+if name_flag:
+ admin = libuser.admin()
+ name_available_flag = name not in admin.enumeratedUsers()
+
+if owner_flag and name_flag and name_available_flag and home_flag :
+ user = admin.initUser(name)
+ user[libuser.HOMEDIRECTORY] = home
+ if opt_shell : user[libuser.SHELL] = opt_shell
+ admin.addUser(user)
+ #setfacl -m d:u:plato:rwx,u:plato:rwx directory
+ setfacl = "setfacl -m d:u:" + name + ":rwx,u:" + name + ":rwx " + home
+ exit(0)
+
+#--------------------------------------------------------------------------------
+# error return
+# .. need to grab the return code from setfacl above and delete the user if it fails
+#
+err_flags = 0
+if not owner_flag :
+ err_flags |= 2**2
+ print "missing owning username argument"
+if not name_flag :
+ err_flags |= 2**3
+ print name + "missing subservient username argument"
+if not name_available_flag :
+ err_flags |= 2**4
+ print name + "specified subservient username already exists"
+if not home_flag :
+ err_flags |= 2**5
+ print "user home directory already exists"
+
+exit(err_flags)
+++ /dev/null
-dbprintf.aux.o: dbprintf.aux.c /usr/include/stdc-predef.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h /usr/include/stdio.h \
- /usr/include/bits/libc-header-start.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h dbprintf.aux.h
-
-/usr/include/stdc-predef.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-dbprintf.aux.h:
+++ /dev/null
-dispatch.lib.o: dispatch.lib.c /usr/include/stdc-predef.h \
- /usr/include/sys/types.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
- /usr/include/bits/typesizes.h /usr/include/bits/types/clock_t.h \
- /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
- /usr/include/bits/types/timer_t.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/unistd.h \
- /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
- /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
- /usr/include/bits/getopt_core.h /usr/include/wait.h \
- /usr/include/sys/wait.h /usr/include/signal.h /usr/include/bits/signum.h \
- /usr/include/bits/signum-generic.h \
- /usr/include/bits/types/sig_atomic_t.h \
- /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \
- /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \
- /usr/include/bits/siginfo-consts-arch.h \
- /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \
- /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \
- /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \
- /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \
- /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \
- /usr/include/bits/sigthread.h /usr/include/bits/waitflags.h \
- /usr/include/bits/waitstatus.h /usr/include/stdlib.h \
- /usr/include/bits/libc-header-start.h /usr/include/bits/floatn.h \
- /usr/include/bits/floatn-common.h /usr/include/bits/types/locale_t.h \
- /usr/include/bits/types/__locale_t.h /usr/include/alloca.h \
- /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
- /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/types/cookie_io_functions_t.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/errno.h /usr/include/bits/errno.h \
- /usr/include/linux/errno.h /usr/include/asm/errno.h \
- /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
- /usr/include/bits/types/error_t.h local_common.h ../config.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h dbprintf.aux.h \
- dispatch.lib.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/unistd.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/wait.h:
-
-/usr/include/sys/wait.h:
-
-/usr/include/signal.h:
-
-/usr/include/bits/signum.h:
-
-/usr/include/bits/signum-generic.h:
-
-/usr/include/bits/types/sig_atomic_t.h:
-
-/usr/include/bits/types/siginfo_t.h:
-
-/usr/include/bits/types/__sigval_t.h:
-
-/usr/include/bits/siginfo-arch.h:
-
-/usr/include/bits/siginfo-consts.h:
-
-/usr/include/bits/siginfo-consts-arch.h:
-
-/usr/include/bits/types/sigval_t.h:
-
-/usr/include/bits/types/sigevent_t.h:
-
-/usr/include/bits/sigevent-consts.h:
-
-/usr/include/bits/sigaction.h:
-
-/usr/include/bits/sigcontext.h:
-
-/usr/include/bits/types/stack_t.h:
-
-/usr/include/sys/ucontext.h:
-
-/usr/include/bits/sigstack.h:
-
-/usr/include/bits/ss_flags.h:
-
-/usr/include/bits/types/struct_sigstack.h:
-
-/usr/include/bits/sigthread.h:
-
-/usr/include/bits/waitflags.h:
-
-/usr/include/bits/waitstatus.h:
-
-/usr/include/stdlib.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/bits/floatn.h:
-
-/usr/include/bits/floatn-common.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/alloca.h:
-
-/usr/include/bits/stdlib-bsearch.h:
-
-/usr/include/bits/stdlib-float.h:
-
-/usr/include/stdio.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/types/cookie_io_functions_t.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/errno.h:
-
-/usr/include/bits/errno.h:
-
-/usr/include/linux/errno.h:
-
-/usr/include/asm/errno.h:
-
-/usr/include/asm-generic/errno.h:
-
-/usr/include/asm-generic/errno-base.h:
-
-/usr/include/bits/types/error_t.h:
-
-local_common.h:
-
-../config.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h:
-
-dbprintf.aux.h:
-
-dispatch.lib.h:
+++ /dev/null
-dispatch_exec.lib.o: dispatch_exec.lib.c /usr/include/stdc-predef.h \
- /usr/include/sys/types.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
- /usr/include/bits/typesizes.h /usr/include/bits/types/clock_t.h \
- /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
- /usr/include/bits/types/timer_t.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/unistd.h \
- /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
- /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
- /usr/include/bits/getopt_core.h /usr/include/wait.h \
- /usr/include/sys/wait.h /usr/include/signal.h /usr/include/bits/signum.h \
- /usr/include/bits/signum-generic.h \
- /usr/include/bits/types/sig_atomic_t.h \
- /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \
- /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \
- /usr/include/bits/siginfo-consts-arch.h \
- /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \
- /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \
- /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \
- /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \
- /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \
- /usr/include/bits/sigthread.h /usr/include/bits/waitflags.h \
- /usr/include/bits/waitstatus.h /usr/include/stdlib.h \
- /usr/include/bits/libc-header-start.h /usr/include/bits/floatn.h \
- /usr/include/bits/floatn-common.h /usr/include/bits/types/locale_t.h \
- /usr/include/bits/types/__locale_t.h /usr/include/alloca.h \
- /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
- /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/types/cookie_io_functions_t.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/errno.h /usr/include/bits/errno.h \
- /usr/include/linux/errno.h /usr/include/asm/errno.h \
- /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
- /usr/include/bits/types/error_t.h local_common.h ../config.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h dbprintf.aux.h \
- dispatch_exec.lib.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/unistd.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/wait.h:
-
-/usr/include/sys/wait.h:
-
-/usr/include/signal.h:
-
-/usr/include/bits/signum.h:
-
-/usr/include/bits/signum-generic.h:
-
-/usr/include/bits/types/sig_atomic_t.h:
-
-/usr/include/bits/types/siginfo_t.h:
-
-/usr/include/bits/types/__sigval_t.h:
-
-/usr/include/bits/siginfo-arch.h:
-
-/usr/include/bits/siginfo-consts.h:
-
-/usr/include/bits/siginfo-consts-arch.h:
-
-/usr/include/bits/types/sigval_t.h:
-
-/usr/include/bits/types/sigevent_t.h:
-
-/usr/include/bits/sigevent-consts.h:
-
-/usr/include/bits/sigaction.h:
-
-/usr/include/bits/sigcontext.h:
-
-/usr/include/bits/types/stack_t.h:
-
-/usr/include/sys/ucontext.h:
-
-/usr/include/bits/sigstack.h:
-
-/usr/include/bits/ss_flags.h:
-
-/usr/include/bits/types/struct_sigstack.h:
-
-/usr/include/bits/sigthread.h:
-
-/usr/include/bits/waitflags.h:
-
-/usr/include/bits/waitstatus.h:
-
-/usr/include/stdlib.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/bits/floatn.h:
-
-/usr/include/bits/floatn-common.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/alloca.h:
-
-/usr/include/bits/stdlib-bsearch.h:
-
-/usr/include/bits/stdlib-float.h:
-
-/usr/include/stdio.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/types/cookie_io_functions_t.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/errno.h:
-
-/usr/include/bits/errno.h:
-
-/usr/include/linux/errno.h:
-
-/usr/include/asm/errno.h:
-
-/usr/include/asm-generic/errno.h:
-
-/usr/include/asm-generic/errno-base.h:
-
-/usr/include/bits/types/error_t.h:
-
-local_common.h:
-
-../config.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h:
-
-dbprintf.aux.h:
-
-dispatch_exec.lib.h:
+++ /dev/null
-dispatch_f.lib.o: dispatch_f.lib.c /usr/include/stdc-predef.h \
- /usr/include/sys/types.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
- /usr/include/bits/typesizes.h /usr/include/bits/types/clock_t.h \
- /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
- /usr/include/bits/types/timer_t.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/unistd.h \
- /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
- /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
- /usr/include/bits/getopt_core.h /usr/include/wait.h \
- /usr/include/sys/wait.h /usr/include/signal.h /usr/include/bits/signum.h \
- /usr/include/bits/signum-generic.h \
- /usr/include/bits/types/sig_atomic_t.h \
- /usr/include/bits/types/siginfo_t.h /usr/include/bits/types/__sigval_t.h \
- /usr/include/bits/siginfo-arch.h /usr/include/bits/siginfo-consts.h \
- /usr/include/bits/siginfo-consts-arch.h \
- /usr/include/bits/types/sigval_t.h /usr/include/bits/types/sigevent_t.h \
- /usr/include/bits/sigevent-consts.h /usr/include/bits/sigaction.h \
- /usr/include/bits/sigcontext.h /usr/include/bits/types/stack_t.h \
- /usr/include/sys/ucontext.h /usr/include/bits/sigstack.h \
- /usr/include/bits/ss_flags.h /usr/include/bits/types/struct_sigstack.h \
- /usr/include/bits/sigthread.h /usr/include/bits/waitflags.h \
- /usr/include/bits/waitstatus.h /usr/include/stdlib.h \
- /usr/include/bits/libc-header-start.h /usr/include/bits/floatn.h \
- /usr/include/bits/floatn-common.h /usr/include/bits/types/locale_t.h \
- /usr/include/bits/types/__locale_t.h /usr/include/alloca.h \
- /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
- /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/types/cookie_io_functions_t.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/errno.h /usr/include/bits/errno.h \
- /usr/include/linux/errno.h /usr/include/asm/errno.h \
- /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
- /usr/include/bits/types/error_t.h local_common.h ../config.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h dbprintf.aux.h \
- dispatch_f.lib.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/unistd.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/wait.h:
-
-/usr/include/sys/wait.h:
-
-/usr/include/signal.h:
-
-/usr/include/bits/signum.h:
-
-/usr/include/bits/signum-generic.h:
-
-/usr/include/bits/types/sig_atomic_t.h:
-
-/usr/include/bits/types/siginfo_t.h:
-
-/usr/include/bits/types/__sigval_t.h:
-
-/usr/include/bits/siginfo-arch.h:
-
-/usr/include/bits/siginfo-consts.h:
-
-/usr/include/bits/siginfo-consts-arch.h:
-
-/usr/include/bits/types/sigval_t.h:
-
-/usr/include/bits/types/sigevent_t.h:
-
-/usr/include/bits/sigevent-consts.h:
-
-/usr/include/bits/sigaction.h:
-
-/usr/include/bits/sigcontext.h:
-
-/usr/include/bits/types/stack_t.h:
-
-/usr/include/sys/ucontext.h:
-
-/usr/include/bits/sigstack.h:
-
-/usr/include/bits/ss_flags.h:
-
-/usr/include/bits/types/struct_sigstack.h:
-
-/usr/include/bits/sigthread.h:
-
-/usr/include/bits/waitflags.h:
-
-/usr/include/bits/waitstatus.h:
-
-/usr/include/stdlib.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/bits/floatn.h:
-
-/usr/include/bits/floatn-common.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/alloca.h:
-
-/usr/include/bits/stdlib-bsearch.h:
-
-/usr/include/bits/stdlib-float.h:
-
-/usr/include/stdio.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/types/cookie_io_functions_t.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/errno.h:
-
-/usr/include/bits/errno.h:
-
-/usr/include/linux/errno.h:
-
-/usr/include/asm/errno.h:
-
-/usr/include/asm-generic/errno.h:
-
-/usr/include/asm-generic/errno-base.h:
-
-/usr/include/bits/types/error_t.h:
-
-local_common.h:
-
-../config.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h:
-
-dbprintf.aux.h:
-
-dispatch_f.lib.h:
+++ /dev/null
-dispatch_useradd.lib.o: dispatch_useradd.lib.c /usr/include/stdc-predef.h \
- /usr/include/sys/types.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
- /usr/include/bits/typesizes.h /usr/include/bits/types/clock_t.h \
- /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
- /usr/include/bits/types/timer_t.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/stdlib.h \
- /usr/include/bits/libc-header-start.h /usr/include/bits/waitflags.h \
- /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
- /usr/include/bits/floatn-common.h /usr/include/alloca.h \
- /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
- /usr/include/unistd.h /usr/include/bits/posix_opt.h \
- /usr/include/bits/environments.h /usr/include/bits/confname.h \
- /usr/include/bits/getopt_posix.h /usr/include/bits/getopt_core.h \
- /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/errno.h /usr/include/bits/errno.h \
- /usr/include/linux/errno.h /usr/include/asm/errno.h \
- /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
- local_common.h ../config.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h dbprintf.aux.h \
- dispatch_exec.lib.h dispatch_useradd.lib.h /usr/include/pwd.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/stdlib.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/bits/waitflags.h:
-
-/usr/include/bits/waitstatus.h:
-
-/usr/include/bits/floatn.h:
-
-/usr/include/bits/floatn-common.h:
-
-/usr/include/alloca.h:
-
-/usr/include/bits/stdlib-bsearch.h:
-
-/usr/include/bits/stdlib-float.h:
-
-/usr/include/unistd.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/stdio.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/errno.h:
-
-/usr/include/bits/errno.h:
-
-/usr/include/linux/errno.h:
-
-/usr/include/asm/errno.h:
-
-/usr/include/asm-generic/errno.h:
-
-/usr/include/asm-generic/errno-base.h:
-
-local_common.h:
-
-../config.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h:
-
-dbprintf.aux.h:
-
-dispatch_exec.lib.h:
-
-dispatch_useradd.lib.h:
-
-/usr/include/pwd.h:
+++ /dev/null
-subu-config.lib.o: subu-config.lib.c /usr/include/stdc-predef.h \
- /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
- /usr/include/features.h /usr/include/sys/cdefs.h \
- /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
- /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/string.h /usr/include/bits/types/locale_t.h \
- /usr/include/bits/types/__locale_t.h /usr/include/strings.h \
- subu-config.lib.h /usr/include/sqlite3.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/string.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/strings.h:
-
-subu-config.lib.h:
-
-/usr/include/sqlite3.h:
+++ /dev/null
-subu-config.lib.o: subu-config.lib.c /usr/include/stdc-predef.h \
- /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
- /usr/include/features.h /usr/include/sys/cdefs.h \
- /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
- /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/string.h /usr/include/bits/types/locale_t.h \
- /usr/include/bits/types/__locale_t.h /usr/include/strings.h \
- subu-config.lib.h /usr/include/sqlite3.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/string.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/strings.h:
-
-subu-config.lib.h:
-
-/usr/include/sqlite3.h:
+++ /dev/null
-subu-init.cli.o: subu-init.cli.c /usr/include/stdc-predef.h \
- subu-init.cli.h /usr/include/sqlite3.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h /usr/include/stdio.h \
- /usr/include/bits/libc-header-start.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-
-/usr/include/stdc-predef.h:
-
-subu-init.cli.h:
-
-/usr/include/sqlite3.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
+++ /dev/null
-subu-mk-0.o: subu-mk-0.c /usr/include/stdc-predef.h /usr/include/stdio.h \
- /usr/include/bits/libc-header-start.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h subu-mk-0.lib.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-subu-mk-0.lib.h:
+++ /dev/null
-subu-mk-0.cli.o: subu-mk-0.cli.c /usr/include/stdc-predef.h \
- /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
- /usr/include/features.h /usr/include/sys/cdefs.h \
- /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
- /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h subu-mk-0.lib.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-subu-mk-0.lib.h:
+++ /dev/null
-subu-mk-0.fi.o: subu-mk-0.fi.c /usr/include/stdc-predef.h \
- /usr/include/unistd.h /usr/include/features.h /usr/include/sys/cdefs.h \
- /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
- /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
- /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
- /usr/include/bits/getopt_core.h /usr/include/sys/types.h \
- /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \
- /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/stdio.h \
- /usr/include/bits/libc-header-start.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/types/cookie_io_functions_t.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/stdlib.h \
- /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
- /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \
- /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
- /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
- /usr/include/bits/stdlib-float.h /usr/include/pwd.h \
- /usr/include/string.h /usr/include/strings.h /usr/include/sys/stat.h \
- /usr/include/bits/stat.h /usr/include/bits/statx.h ../config.h \
- dispatch.h local_common.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h dispatch_useradd.h \
- subu-mk-0.fi.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/unistd.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/types/cookie_io_functions_t.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/stdlib.h:
-
-/usr/include/bits/waitflags.h:
-
-/usr/include/bits/waitstatus.h:
-
-/usr/include/bits/floatn.h:
-
-/usr/include/bits/floatn-common.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/alloca.h:
-
-/usr/include/bits/stdlib-bsearch.h:
-
-/usr/include/bits/stdlib-float.h:
-
-/usr/include/pwd.h:
-
-/usr/include/string.h:
-
-/usr/include/strings.h:
-
-/usr/include/sys/stat.h:
-
-/usr/include/bits/stat.h:
-
-/usr/include/bits/statx.h:
-
-../config.h:
-
-dispatch.h:
-
-local_common.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h:
-
-dispatch_useradd.h:
-
-subu-mk-0.fi.h:
+++ /dev/null
-subu-mk-0.lib.o: subu-mk-0.lib.c /usr/include/stdc-predef.h \
- /usr/include/sys/types.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
- /usr/include/bits/typesizes.h /usr/include/bits/types/clock_t.h \
- /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
- /usr/include/bits/types/timer_t.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/unistd.h \
- /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
- /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
- /usr/include/bits/getopt_core.h /usr/include/stdio.h \
- /usr/include/bits/libc-header-start.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/types/cookie_io_functions_t.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/errno.h /usr/include/bits/errno.h \
- /usr/include/linux/errno.h /usr/include/asm/errno.h \
- /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
- /usr/include/bits/types/error_t.h /usr/include/stdlib.h \
- /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
- /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \
- /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
- /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
- /usr/include/bits/stdlib-float.h /usr/include/pwd.h \
- /usr/include/string.h /usr/include/strings.h /usr/include/sys/stat.h \
- /usr/include/bits/stat.h /usr/include/bits/statx.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h dispatch_f.lib.h \
- local_common.h ../config.h dbprintf.aux.h dispatch_exec.lib.h \
- dispatch_useradd.lib.h subu-mk-0.lib.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/unistd.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/types/cookie_io_functions_t.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/errno.h:
-
-/usr/include/bits/errno.h:
-
-/usr/include/linux/errno.h:
-
-/usr/include/asm/errno.h:
-
-/usr/include/asm-generic/errno.h:
-
-/usr/include/asm-generic/errno-base.h:
-
-/usr/include/bits/types/error_t.h:
-
-/usr/include/stdlib.h:
-
-/usr/include/bits/waitflags.h:
-
-/usr/include/bits/waitstatus.h:
-
-/usr/include/bits/floatn.h:
-
-/usr/include/bits/floatn-common.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/alloca.h:
-
-/usr/include/bits/stdlib-bsearch.h:
-
-/usr/include/bits/stdlib-float.h:
-
-/usr/include/pwd.h:
-
-/usr/include/string.h:
-
-/usr/include/strings.h:
-
-/usr/include/sys/stat.h:
-
-/usr/include/bits/stat.h:
-
-/usr/include/bits/statx.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdbool.h:
-
-dispatch_f.lib.h:
-
-local_common.h:
-
-../config.h:
-
-dbprintf.aux.h:
-
-dispatch_exec.lib.h:
-
-dispatch_useradd.lib.h:
-
-subu-mk-0.lib.h:
+++ /dev/null
-subu_init-subu-config.lib.o: subu-config.lib.c /usr/include/stdc-predef.h \
- /usr/include/stdio.h /usr/include/bits/libc-header-start.h \
- /usr/include/features.h /usr/include/sys/cdefs.h \
- /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
- /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types.h /usr/include/bits/typesizes.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/string.h /usr/include/bits/types/locale_t.h \
- /usr/include/bits/types/__locale_t.h /usr/include/strings.h \
- subu-config.lib.h /usr/include/sqlite3.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/string.h:
-
-/usr/include/bits/types/locale_t.h:
-
-/usr/include/bits/types/__locale_t.h:
-
-/usr/include/strings.h:
-
-subu-config.lib.h:
-
-/usr/include/sqlite3.h:
+++ /dev/null
-subu_init-subu-init.cli.o: subu-init.cli.c /usr/include/stdc-predef.h \
- subu-init.cli.h /usr/include/sqlite3.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h
-
-/usr/include/stdc-predef.h:
-
-subu-init.cli.h:
-
-/usr/include/sqlite3.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+++ /dev/null
-useradd-0.o: useradd-0.c /usr/include/stdc-predef.h \
- /usr/include/sys/types.h /usr/include/features.h \
- /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
- /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
- /usr/include/gnu/stubs-64.h /usr/include/bits/types.h \
- /usr/include/bits/typesizes.h /usr/include/bits/types/clock_t.h \
- /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
- /usr/include/bits/types/timer_t.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
- /usr/include/bits/stdint-intn.h /usr/include/endian.h \
- /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
- /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
- /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
- /usr/include/bits/types/__sigset_t.h \
- /usr/include/bits/types/struct_timeval.h \
- /usr/include/bits/types/struct_timespec.h \
- /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
- /usr/include/bits/pthreadtypes-arch.h /usr/include/unistd.h \
- /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
- /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
- /usr/include/bits/getopt_core.h /usr/include/stdio.h \
- /usr/include/bits/libc-header-start.h \
- /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
- /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
- /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
- /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
- /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
- /usr/include/bits/stdio.h /usr/include/errno.h /usr/include/bits/errno.h \
- /usr/include/linux/errno.h /usr/include/asm/errno.h \
- /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h
-
-/usr/include/stdc-predef.h:
-
-/usr/include/sys/types.h:
-
-/usr/include/features.h:
-
-/usr/include/sys/cdefs.h:
-
-/usr/include/bits/wordsize.h:
-
-/usr/include/bits/long-double.h:
-
-/usr/include/gnu/stubs.h:
-
-/usr/include/gnu/stubs-64.h:
-
-/usr/include/bits/types.h:
-
-/usr/include/bits/typesizes.h:
-
-/usr/include/bits/types/clock_t.h:
-
-/usr/include/bits/types/clockid_t.h:
-
-/usr/include/bits/types/time_t.h:
-
-/usr/include/bits/types/timer_t.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
-
-/usr/include/bits/stdint-intn.h:
-
-/usr/include/endian.h:
-
-/usr/include/bits/endian.h:
-
-/usr/include/bits/byteswap.h:
-
-/usr/include/bits/uintn-identity.h:
-
-/usr/include/sys/select.h:
-
-/usr/include/bits/select.h:
-
-/usr/include/bits/types/sigset_t.h:
-
-/usr/include/bits/types/__sigset_t.h:
-
-/usr/include/bits/types/struct_timeval.h:
-
-/usr/include/bits/types/struct_timespec.h:
-
-/usr/include/bits/pthreadtypes.h:
-
-/usr/include/bits/thread-shared-types.h:
-
-/usr/include/bits/pthreadtypes-arch.h:
-
-/usr/include/unistd.h:
-
-/usr/include/bits/posix_opt.h:
-
-/usr/include/bits/environments.h:
-
-/usr/include/bits/confname.h:
-
-/usr/include/bits/getopt_posix.h:
-
-/usr/include/bits/getopt_core.h:
-
-/usr/include/stdio.h:
-
-/usr/include/bits/libc-header-start.h:
-
-/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
-
-/usr/include/bits/types/__fpos_t.h:
-
-/usr/include/bits/types/__mbstate_t.h:
-
-/usr/include/bits/types/__fpos64_t.h:
-
-/usr/include/bits/types/__FILE.h:
-
-/usr/include/bits/types/FILE.h:
-
-/usr/include/bits/types/struct_FILE.h:
-
-/usr/include/bits/stdio_lim.h:
-
-/usr/include/bits/sys_errlist.h:
-
-/usr/include/bits/stdio.h:
-
-/usr/include/errno.h:
-
-/usr/include/bits/errno.h:
-
-/usr/include/linux/errno.h:
-
-/usr/include/asm/errno.h:
-
-/usr/include/asm-generic/errno.h:
-
-/usr/include/asm-generic/errno-base.h:
+++ /dev/null
-# src/0_makefile
-
-SHELL=/bin/bash
-
--include 0_makefile_flags
-
-SUID_TOOL=$(TOOLSDIR)/bin/setuid_root.sh
-MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-SOURCES=$(wildcard *.c)
-HFILES=$(wildcard *.h)
-
-all: version deps lib execs
-
-version:
- $(MAKE) $@
- @echo "SUID_TOOL: " $(SUID_TOOL)
-
-deps:
- makeheaders $(SOURCES) $(HFILES)
- sed -i '/^ *int *main *(.*)/d' *.h
- $(MAKE) $@
-
-execs:
- $(MAKE) $@
- @echo "-> $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all"
- cat $(SUID_TOOL)
- @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} == y ]
- sudo $(SUID_TOOL) $(EXECSDIR)/subu-mk-0 $(EXECSDIR)/subu-rm-0 $(EXECSDIR)/subu-bind-all
-
-clean:
- $(MAKE) $@
- for i in $(HFILES); do rm $$i; done
-
-%::
- $(MAKE) $@
-
-
-
-
+++ /dev/null
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=1_deprecated
-DOCDIR=1_doc
-EXECSDIR=1_execs
-HDIR=1_headers
-LIBDIR=1_lib
-TESTDIR=1_tests
-TMPDIR=1_tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=1_try
-
-
-# compiler and flags
-CC=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-L1_lib -lsubu -lsqlite3
-
-LIB_FILE=$(LIBDIR)/libsubu.a
-
+++ /dev/null
-/*
- 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;
- }
-}
+++ /dev/null
-/*
- 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;
- }
-}
-
-
+++ /dev/null
-/*
-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;
- }}}
-
+++ /dev/null
-/*
- subu-rm-0 subuname
-
- 1. get our uid and lookup masteru_name in /etc/passwd
- 2. lookup masteru_name/subuname in config file, which gives us subu_username
- 3. unmount subuland/subuname
- 4. userdel subu_username
- 5. rmdir subuland/subuname
-
- Note, as per the man page, we are not allowed to free the memory allocated by getpwid().
-
-*/
-#include "subu-mk-0.lib.h"
-
-// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#if INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-#endif
-
-//--------------------------------------------------------------------------------
-// an instance is subu_rm_0_ctx is returned by subu_rm_0
-//
-#if INTERFACE
-#define ERR_SUBU_RM_0_MKDIR_SUBUHOME 1
-#define ERR_SUBU_RM_0_RMDIR_SUBUHOME 2
-#define ERR_SUBU_RM_0_SUBUNAME_MALFORMED 3
-#define ERR_SUBU_RM_0_SETUID_ROOT 4
-#define ERR_SUBU_RM_0_MASTERU_HOMELESS 5
-#define ERR_SUBU_RM_0_MALLOC 6
-#define ERR_SUBU_RM_0_CONFIG_FILE 7
-#define ERR_SUBU_RM_0_SUBUHOME_EXISTS 8
-#define ERR_SUBU_RM_0_BUG_SSS 9
-#define ERR_SUBU_RM_0_FAILED_USERADD 10
-
-struct subu_rm_0_ctx{
- char *name;
- char *subuland;
- char *subuhome;
- char *subu_username;
- bool free_aux;
- char *aux;
- uint err;
-};
-#endif
-struct subu_rm_0_ctx *subu_rm_0_ctx_mk(){
- struct subu_rm_0_ctx *ctxp = malloc(sizeof(struct subu_rm_0_ctx));
- ctxp->name = "subu_rm_0";
- ctxp->subuland = 0;
- ctxp->subuhome = 0;
- ctxp->subu_username = 0;
- ctxp->free_aux = false;
- ctxp->aux = 0;
-}
-void subu_rm_0_ctx_free(struct subu_rm_0_ctx *ctxp){
- free(ctxp->subuland);
- free(ctxp->subuhome);
- free(ctxp->subu_username);
- if(ctxp->free_aux) free(ctxp->aux);
- free(ctxp);
-}
-// must be called before any system calls, otherwise perror() will be messed up
-void subu_rm_0_mess(struct subu_rm_0_ctx *ctxp){
- switch(ctxp->err){
- case 0: return;
- case ERR_SUBU_RM_0_MKDIR_SUBUHOME:
- fprintf(stderr, "masteru could not make subuhome, \"%s\"", ctxp->subuhome);
- break;
- case ERR_SUBU_RM_0_SUBUNAME_MALFORMED:
- fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", ctxp->aux);
- break;
- case ERR_SUBU_RM_0_SETUID_ROOT:
- fprintf(stderr, "This program must be run setuid root from a user account.");
- break;
- case ERR_SUBU_RM_0_MASTERU_HOMELESS:
- fprintf(stderr,"Masteru, \"%s\", has no home directory", ctxp->aux);
- break;
- case ERR_SUBU_RM_0_MALLOC:
- perror(ctxp->name);
- break;
- case ERR_SUBU_RM_0_CONFIG_FILE:
- fprintf(stderr, "config file error: %s", ctxp->aux);
- break;
- case ERR_SUBU_RM_0_SUBUHOME_EXISTS:
- fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", ctxp->subuhome);
- break;
- case ERR_SUBU_RM_0_BUG_SSS:
- perror(ctxp->name);
- break;
- case ERR_SUBU_RM_0_FAILED_USERADD:
- fprintf(stderr, "%u useradd failed\n", ctxp->subu_username);
- break;
- default:
- fprintf(stderr, "unknown error code %d\n", ctxp->err);
- }
- fputc('\n', stderr);
-}
-
-//--------------------------------------------------------------------------------
-// dispatched functions
-//
-// the making of subuhome is dispatched to its own process so as to give it its own uid/gid
-static int masteru_mkdir_subuhome(void *arg){
- char *subuhome = (char *) arg;
- if( mkdir( subuhome, subuhome_perms ) == -1 ){ // find subuhome perms in common
- perror("masteru_mkdir_subuhome");
- return ERR_SUBU_RM_0_MKDIR_SUBUHOME;
- }
- return 0;
-}
-static int masteru_rmdir_subuhome(void *arg){
- char *subuhome = (char *) arg;
- if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
- perror("masteru_rmdir_subuhome");
- return ERR_SUBU_RM_0_RMDIR_SUBUHOME;
- }
- return 0;
-}
-
-//--------------------------------------------------------------------------------
-// the public call point
-struct subu_rm_0_ctx *subu_rm_0(sqlite3 *db, char *subuname){
-
- struct subu_rm_0_ctx *ctxp = subu_rm_0_ctx_mk();
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("Checking that subuname is well formed and finding its length\n");
- #endif
- size_t subuname_len;
- {
- int ret = allowed_subuname(subuname, &subuname_len);
- if( ret == -1 ){
- ctxp->err = ERR_SUBU_RM_0_SUBUNAME_MALFORMED;
- ctxp->aux = subuname;
- return ctxp;
- }}
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("Checking that we are running from a user and are setuid root.\n");
- #endif
- uid_t masteru_uid;
- gid_t masteru_gid;
- uid_t set_euid;
- gid_t set_egid;
- {
- masteru_uid = getuid();
- masteru_gid = getgid();
- set_euid = geteuid();
- set_egid = getegid();
- #ifdef DEBUG
- 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 ){
- ctxp->err = ERR_SUBU_RM_0_SETUID_ROOT;
- return ctxp;
- }
- }
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("strings masteru_name and masteru_home\n");
- #endif
-
- char *masteru_name;
- size_t masteru_name_len;
- char *masteru_home;
- size_t masteru_home_len;
- size_t subuland_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\" %zu\n", masteru_name, masteru_name_len);
- #endif
- masteru_home = masteru_pw_record_pt->pw_dir;
- masteru_home_len = strlen(masteru_home);
- #ifdef DEBUG
- 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] == '(' ){
- ctxp->err = ERR_SUBU_RM_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/"; // moved to common.lib.c
- size_t subuland_extension_len = strlen(subuland_extension);
- ctxp->subuland = (char *)malloc( masteru_home_len + subuland_extension_len + 1 );
- if(!ctxp->subuland){
- ctxp->err = ERR_SUBU_RM_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\" %zu\n", ctxp->subuland, subuland_len);
- #endif
- }
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("lookup subu_username from masteru_name/subuname in config file\n");
- #endif
- char *subu_username; // this is part of ctx and must be freed
- {
- int ret = subu_get_masteru_subu(db, masteru_name, subuname, &subu_username);
- if( ret != SQLITE_DONE ){
- printf("get failed\n");
- return 2;
- }
- #ifdef DEBUG
- printf("subu_username: %s\n", subu_username);
- #endif
-
- }
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("strings subu_username and subuhome\n");
- #endif
- size_t subu_username_len;
- size_t subuhome_len;
- {
- char *ns=0; // 'ns' Number as String
- char *mess=0;
- if( subu_number_get( db, &ns, &mess ) != SQLITE_OK ){
- ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
- ctxp->aux = mess;
- ctxp->free_aux = true;
- return ctxp;
- }
- size_t ns_len = strlen(ns);
- ctxp->subu_username = malloc(1 + ns_len + 1);
- if( !ctxp->subu_username ){
- ctxp->err = ERR_SUBU_RM_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 + subuname_len;
- ctxp->subuhome = (char *)malloc(subuhome_len + 1);
- if( !ctxp->subuhome ){
- ctxp->err = ERR_SUBU_RM_0_MALLOC;
- return ctxp;
- }
- strcpy (ctxp->subuhome, ctxp->subuland);
- strcpy (ctxp->subuhome + subuland_len, subuname);
- #ifdef DEBUG
- dbprintf("subuhome \"%s\" %zu\n", ctxp->subuhome, subuhome_len);
- #endif
- }
-
- //--------------------------------------------------------------------------------
- // By having masteru create the subuhome, we know that masteru has rights to
- // to access this directory. This will be the mount point for bindfs
- {
- #ifdef DEBUG
- dbprintf("as masteru, making the directory \"%s\"\n", ctxp->subuhome);
- #endif
- struct stat st;
- if( stat(ctxp->subuhome, &st) != -1 ){
- ctxp->err = ERR_SUBU_RM_0_SUBUHOME_EXISTS;
- return ctxp;
- }
- dispatch_ctx *dfr = dispatch_f_euid_egid
- (
- "masteru_mkdir_subuhome",
- masteru_mkdir_subuhome,
- (void *)ctxp->subuhome,
- masteru_uid,
- masteru_gid
- );
- if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME ){
- #ifdef DEBUG
- if( dfr->err == ERR_SUBU_RM_0_MKDIR_SUBUHOME )
- perror("mkdir");
- else
- dispatch_f_mess(dfr);
- #endif
- ctxp->err = ERR_SUBU_RM_0_MKDIR_SUBUHOME;
- return ctxp;
- }
- }
- #ifdef DEBUG
- dbprintf("masteru made directory \"%s\"\n", ctxp->subuhome);
- #endif
-
- //--------------------------------------------------------------------------------
- // Make the subservient user account, i.e. the subu
- {
- #ifdef DEBUG
- 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 ){
- ctxp->err = ERR_SUBU_RM_0_BUG_SSS;
- return ctxp;
- }
- #endif
- char *command = "/usr/sbin/useradd";
- char *argv[3];
- argv[0] = command;
- argv[1] = ctxp->subu_username;
- argv[2] = (char *) NULL;
- char *envp[1];
- envp[0] = (char *) NULL;
- 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
- // go back and remove the directory we made in subuland
- dispatch_ctx *dfr = dispatch_f_euid_egid
- (
- "masteru_rmdir_subuhome",
- masteru_rmdir_subuhome,
- (void *)ctxp->subuhome,
- masteru_uid,
- masteru_gid
- );
- #ifdef DEBUG
- if( dfr->err <= ERR_DISPATCH || dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
- if( dfr->err == ERR_SUBU_RM_0_RMDIR_SUBUHOME )
- perror("rmdir");
- else
- dispatch_f_mess(dfr);
- #endif
- ctxp->err = ERR_SUBU_RM_0_FAILED_USERADD;
- return ctxp;
- }
- #ifdef DEBUG
- dbprintf("added user \"%s\"\n", ctxp->subu_username);
- #endif
- }
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("setting the masteru_name, subuname, subu_username relation\n");
- #endif
- {
- int ret = subu_put_masteru_subu(db, masteru_name, subuname, ctxp->subu_username);
- if( ret != SQLITE_DONE ){
- ctxp->err = ERR_SUBU_RM_0_CONFIG_FILE;
- ctxp->aux = "insert of masteru subu relation failed";
- return ctxp;
- }
- }
-
- #ifdef DEBUG
- dbprintf("finished subu-mk-0(%s)\n", subuname);
- #endif
- ctxp->err = 0;
- return ctxp;
-}
+++ /dev/null
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-number-next.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
- if( argc != 2 ){
- fprintf(stderr, "usage: %s masteru_name \n",argv[0]);
- return SUBU_ERR_ARG_CNT;
- }
- char *masteru_name = argv[1];
-
- int rc;
- sqlite3 *db;
- rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( rc != SQLITE_OK ){
- sqlite3_close(db);
- fprintf(stderr, "error exit, could not open db file\n");
- return SUBU_ERR_DB_FILE;
- }
-
- // read and print the current max
- char *mess;
- int n;
- rc = subudb_number_next(db, masteru_name, &n, &mess);
- if( rc == SQLITE_DONE ){
- printf("%d\n", n);
- }else{
- fprintf(stderr, "subudb_number_next indicates failure by returning %d\n",rc);
- fprintf(stderr, "and issues message, %s\n", sqlite3_errmsg(db));
- sqlite3_close(db);
- return SUBU_ERR_DB_FILE;
- }
- rc = sqlite3_close(db);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-}
+++ /dev/null
-
-
-filename.tag.extension
-
-extension:
- .c for C source
- .cc for C++ source
- .h for C header file
- .hh for C++ header file
- .o an object file
-
-tag:
- .lib. The resulting .o file to be placed in release library and is part of the
- programming interface.
- .aux. The resulting.o file not directly part of the programming interface, but
- it might be called by functions that are.
- .cli. The source file has a main call and is to be relased as part of the command line interface
- .loc. file has a main call to be made into a local uitlity function
-
-We carry the source file tag and extension to the .o file. We do not put tags
-nor extensions on command line executables.
-
-local_common.h should be included in all source files
+++ /dev/null
-these are the comments from my RT makefile:
-
-#
-# 2010 11 20 TWL Created
-# 2011 05 26 TWL Modified to generalize
-# 2012 02 23 NLS Add ECHO variable to use on different environnement
-# corrected setup macro --> add include directory in the path to copy
-# corrected install macro --> change the name of installed library : lib$(LIB)$(LIBSUFFIX)
-# changed DOC_DIR directory name to 5_documents
-# 2012 02 23 TWL removed LIB variable which is now set from the command line so
-# so that all source dirs can use the same makefile
-# 2012 02 23 TWL added target make dist_clean which also deletes the 2_makefile_deps file
-# 2012 04 11 AWW added creation of temporary disk before each test is run
-# 2012 06 05 TWL moved tests and try .cc files to directories. caused rtmake tests to
-# dist_clean and make deps
-#
-#
-#----------------------------------------------------------------------------
-# use this makefile to compile and test the code:
-#
-# for a first time run, or for regression use the following:
-#
-# $ make setup # makes the directories, though should already exist
-# $ make regress
-#
-# the usual development workflow makes use of these:
-#
-# $ make deps # only when needed, for example if headers includes change or new files introduced
-# $ cd tests; make deps # only when needed
-# $ make lib # this makes the local library
-# $ make tests # this updates tests and compiles
-# $ make clean # deletes the .o files and library to force a recompile
-# $ cd 1_tests; make clean
-#
-# for a release of a component
-#
-# $ make regress
-# $ make install # this will only work if all the tests in 1_tests are passing
-#
-# before a checkin
-#
-# $ make dist_clean # will also clean the tests and try directories
-#
-# .lib.cc c++ files taken as source of object files for local build library
-# .exl.cc c++ files taken to have main calls and are linked against local build libary
-# .ex.cc c++ files taken to have main calls and are not linked against the local build library
-# there are no rules for other files in this makefile
-#
-# about dependencies
-# The makefile has no way of knowing if an edit changed the dependencies. Often they do not
-# and it would be unwieldy to make the deps every time. Hence *the programmer* must delete
-# the deps file if he has made any changes that change the dependencies.
-#
-# The makefile will make the 2_makefile_deps if the file is missing.
-#
-#
-# about testing
-#
-# the name of the directory you run make in is taken to also be: the name of the library,
-# the name of the main include file (with a .h added), and the name of the include directory
-# where the individual headers are found. It is called LIB
-#
-# test programs are kept in a subdirectory called 1_tests, and are either .exl.cc, ex.cc,
-# .sh files. When 'make tests' target is invoked they are all run. Test executables return 0
-# if the test fails, non-zero otherwise.
-#
-# to remove a test from the pool move it into the subdirectory in 1_tests, 9_broken,
-# 5_more_tests of 5_scratch. broken tests are things that are known but must be fixed
-# before a release. 5_more_tests are tests being worked on. 5_scratch is stuff that is
-# probably going to be deleted. if there is a 5_deprecated, that is for good stuff but it
-# is no longer used for some reason or other.
-#
-# There is a standard source code template and a
-# messaging convention. Also, the names, by convention,are test_xxxx_ where xxx is a
-# hexadecimal series nummber. If all the test executables pass the file 1_TESTS_PASSED is
-# left in the directory. Otherwise the file 1_TESTS_FAILED is left in the directory.
-#
-# about release directory
-#
-# this is set in the ApplicationBase variable by rt_init
-#
-# after the tests pass stuff might be copied to the release directory using
-#
-# make install
-#
-# the release directory must have these subdirectories:
-#
-# bin documents include src
-#
-#
-#
+++ /dev/null
-
-This worked to force the include to be part of the interface:
-
-#if INTERFACE
-#include <sqlite3.h>
-#endif
-
-But this did not:
-
-#if INTERFACE
- #include <sqlite3.h>
-#endif
-
-makeheaders looks to be sensitive to indentation
-
-
+++ /dev/null
-
-1.
- This sql:
-
- 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;"
- ;
-
- with sqlite_exec, the call back is called with the data from the select.
-
- with sqlite_prepare_v2, sqlite_step just returns SQLITE_DONE, and we never
- get to see our data from the select.
+++ /dev/null
-2019-02-05T23:14:40Z
- error can cause subu-mk-0 to leave the creating of a subu in an intermediate
- state. Rather than bailing on some of the errors we need to clean up instead.
- Perhaps the yet to be written subu-rm program will be resilent enough to do
- more general cleanup.
-
-2019-02-23T18:56:31Z
- need to modify subu-init to take a configuration file name argument instead of
- using a global variabel value. might want to add arguments to other subu
- commands also
-
-2019-03-11T13:48:03Z
- in subu.lib.c append cascading rmdir failure mess to useradd failure mess
-
-2019-03-11T13:48:03Z
- want to add subu-type to masteru_subu(), I imagine there will be static,
- permanent, and temporary subu types.
-
-2019-03-12T18:35:06Z
- the masteru subu relation should contain the uid of the masteru as
- well as the backup type for the subu: git, rdiff, rsync, none.
- and the persisitance fo the subu: indefinite, session.
- seems that operations need to be logged, in case the db is lost
- the transcript can be played back. It should also be possible
- to co-opt an existing user as a subu, though, would require
- sudo privs.
-
- need to add messages for subu errors I've added to the end of
- the list in subu.lib.c
-
-2019-03-14T10:43:50Z
-
- should mod all to he subudb routines to return a message, probably
- strdup(sqlite_errmsg(db)), then the callers to these routines can just pass
- mess in rather than making up new ones for each situation. The error code
- probably already carries the contexts specific message. Or perhaps add
- a string cat function for message strings, that would run through a stream
- and free the originals.
+++ /dev/null
-# src/1_tests/0_makefile
-
-SHELL=/bin/bash
-
--include 0_makefile_flags
-
-MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc
-
-SOURCES=$(wildcard *.c)
-HFILES=$(wildcard *.h)
-
-all: version deps lib execs
-
-deps:
- makeheaders $(SOURCES) $(HFILES)
- sed -i '/^ *int *main *(.*)/d' *.h
- $(MAKE) $@
-
-clean:
- $(MAKE) $@
- for i in $(HFILES); do rm $$i; done
-
-dist-clean:
- $(MAKE) $@
- if [ -f subudb ]; then rm subudb; fi
-
-%::
- $(MAKE) $@
-
-
-
-
+++ /dev/null
-
-# some versions of Linux need a -e option others complain if there is a -e .. and it isn't the binary for echo ..
-ECHO= echo
-#ECHO= echo -e
-
-# directories used by this makefile, these could all be set to dot for
-# the simplest source directory structure
-
-#LIDBIR, EXECSDIR, HDIR hold the make results that might later be staged
-#$(PWD) is the directory that make was called from, this is already build in
-#set to dot to use the same directory as the source code
-#leave blank to ommit
-DEPRDIR=
-DOCDIR=
-EXECSDIR=.
-HDIR=.
-LIBDIR=.
-TESTDIR=.
-TMPDIR=1_tmp
-TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools)
-TRYDIR=
-
-
-# compiler and flags
-CC=gcc
-CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB
-#CFLAGS=-std=gnu11 -fPIC -I. -Werror
-LINKFLAGS=-L$(PROJECT_SUBU)/src/$(LIBDIR) -L. -lsubu -lsqlite3 -lsubutests
-
-LIB_FILE=$(LIBDIR)/libtests.a
-
+++ /dev/null
-/*
-Tests for da.
-
-*/
-
-#include <da.cli.h>
-#include <stdbool.h>
-
-int test_da_0(){
- da da0;
- da_alloc(&da0, sizeof(int)); // leaves room for 4 ints
- int i = 0;
- int *pt = da0->base;
- // will double, 4 -> 8, then double 8 -> 16
- while( i < 10 ){
- if(da_boundq(&da0, pt)){
- char *old_base = da_expand(&da);
- da_rebase(&da, old_base, pt);
- }
- *pt = i;
- i++;
- pt++;
- }
-
- bool f0 = da.size == sizof(int) * 16;
- bool f1 = 10 == (da.end - da.base) / sizeof(int);
- bool f2 = true;
- pt = da0->base;
- while( i < 10 ){
- f2 = f2 && *pt == i && !da_endq(&da, pt);
- i++;
- pt++;
- }
- bool f3 = da_endq(&da, pt);
-
- return f0 && f1 && f2 && f3;
-}
-
-
-int main(){
-
- bool da_0_passed = test_da_0();
- if( da_0_passed ){
- printf("da_0_passed");
- return 0;
- }
- printf("da_0_failed");
- return 1;
-
-}
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <stdlib.h>
-#include <stdbool.h>
-void daps_map(char **base,char **end_pt,void f(void *));
-#define RETURN(rc) \
- { daps_map(mrs, mrs_end, free); return rc; }
-void daps_alloc(char ***base,size_t *s);
-#define MK_MRS \
- char **mrs; \
- char **mrs_end; \
- size_t mrs_size; \
- daps_alloc(&mrs, &mrs_size);\
- mrs_end = mrs;
-void daps_push(char ***base,char ***pt,size_t *s,char *item);
-bool daps_bound(char **base,char **pt,size_t s);
-void daps_expand(char ***base,char ***pt,size_t *s);
-void da_map(void *base,void *end_pt,void f(void *),size_t item_size);
-void da_push(void **base,void **pt,size_t *s,void *item,size_t item_size);
-bool da_bound(void *base,void *pt,size_t s);
-void da_expand(void **base,void **pt,size_t *s);
-void da_alloc(void **base,size_t *s,size_t item_size);
-#define INTERFACE 0
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-int dbprintf(const char *format,...);
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sys/types.h>
-#include <unistd.h>
-int dispatch_exec(char **argv,char **envp);
-typedef unsigned int uint;
-int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
-int dbprintf(const char *format,...);
-int dispatch_f(char *fname,int(*f)(void *arg),void *f_arg);
-void dispatch_f_mess(char *fname,int err,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
-typedef struct dispatch_ctx dispatch_ctx;
-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
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-int subu_bind_all(char **mess,sqlite3 *db);
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-extern char Subuland_Extension[];
-typedef unsigned int uint;
-extern uint First_Max_Subunumber;
-extern uint Subuhome_Perms;
-extern char DB_File[];
-#define BUG_SSS_CACHE_RUID 1
-#define INTERFACE 0
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-void subu_err(char *fname,int err,char *mess);
-int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-void subu_err(char *fname,int err,char *mess);
-int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-typedef unsigned int uint;
-#include <sqlite3.h>
-typedef struct subudb_subu_element subudb_subu_element;
-int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
-struct subudb_subu_element {
- char *subuname;
- char *subu_username;
-};
-#include <stdbool.h>
-#include <errno.h>
-int subu_bind_all(char **mess,sqlite3 *db);
-int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome);
-int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
-int subu_rm_0(char **mess,sqlite3 *db,char *subuname);
-int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <sys/types.h>
-#include <unistd.h>
-int dispatch_exec(char **argv,char **envp);
-#define BUG_SSS_CACHE_RUID 1
-void dispatch_f_mess(char *fname,int err,char *dispatchee);
-#define ERR_DISPATCH -1024
-int dispatch_f_euid_egid(char *fname,int(*f)(void *arg),void *f_arg,uid_t euid,gid_t egid);
-#include <stdlib.h>
-void daps_map(char **base,char **end_pt,void f(void *));
-#define RETURN(rc) \
- { daps_map(mrs, mrs_end, free); return rc; }
-void daps_push(char ***base,char ***pt,size_t *s,char *item);
-int dbprintf(const char *format,...);
-void daps_alloc(char ***base,size_t *s);
-#define MK_MRS \
- char **mrs; \
- char **mrs_end; \
- size_t mrs_size; \
- daps_alloc(&mrs, &mrs_size);\
- mrs_end = mrs;
-int subu_mk_0(char **mess,sqlite3 *db,char *subuname);
-extern char Subuland_Extension[];
-int db_commit(sqlite3 *db);
-int db_rollback(sqlite3 *db);
-int subudb_number_set(sqlite3 *db,int n);
-int subudb_number_get(sqlite3 *db,int *n);
-int db_begin(sqlite3 *db);
-extern uint Subuhome_Perms;
-extern char DB_File[];
-void subu_err(char *fname,int err,char *mess);
-#define SUBU_ERR_BIND 15
-#define SUBU_ERR_N 14
-#define SUBU_ERR_SUBU_NOT_FOUND 13
-#define SUBU_ERR_FAILED_USERDEL 12
-#define SUBU_ERR_FAILED_USERADD 11
-#define SUBU_ERR_BUG_SSS 10
-#define SUBU_ERR_SUBUHOME_EXISTS 9
-#define SUBU_ERR_DB_FILE 8
-#define SUBU_ERR_HOMELESS 7
-#define SUBU_ERR_SUBUNAME_MALFORMED 6
-#define SUBU_ERR_RMDIR_SUBUHOME 5
-#define SUBU_ERR_MKDIR_SUBUHOME 4
-#define SUBU_ERR_MALLOC 3
-#define SUBU_ERR_SETUID_ROOT 2
-#define SUBU_ERR_ARG_CNT 1
-char *userdel_mess(int err);
-char *useradd_mess(int err);
-#define INTERFACE 0
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int db_commit(sqlite3 *db);
-int db_rollback(sqlite3 *db);
-int subudb_schema(sqlite3 *db);
-int db_begin(sqlite3 *db);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_number_get(sqlite3 *db,int *n);
-int subudb_number_set(sqlite3 *db,int n);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_N 14
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-typedef struct subudb_subu_element subudb_subu_element;
-int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
-struct subudb_subu_element {
- char *subuname;
- char *subu_username;
-};
-#include <stdbool.h>
-#include <errno.h>
-#define SUBU_ERR_DB_FILE 8
-extern char DB_File[];
-#define SUBU_ERR_ARG_CNT 1
+++ /dev/null
-/* \aThis file was automatically generated. Do not edit! */
-#undef INTERFACE
-#include <sqlite3.h>
-int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-#include <stdlib.h>
-#include <stdbool.h>
-void da_expand(void **base,void **pt,size_t *s);
-bool da_bound(void *base,void *pt,size_t s);
-typedef struct subudb_subu_element subudb_subu_element;
-int subudb_Masteru_Subu_get_subus(sqlite3 *db,char *masteru_name,subudb_subu_element **sa_pt,subudb_subu_element **sa_end_pt);
-void subu_element_free(subudb_subu_element *base,subudb_subu_element *end_pt);
-void da_alloc(void **base,size_t *s,size_t item_size);
-struct subudb_subu_element {
- char *subuname;
- char *subu_username;
-};
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username);
-int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username);
-int subudb_number_set(sqlite3 *db,int n);
-int subudb_number_get(sqlite3 *db,int *n);
-typedef unsigned int uint;
-extern uint First_Max_Subunumber;
-int subudb_schema(sqlite3 *db);
-int db_rollback(sqlite3 *db);
-int db_commit(sqlite3 *db);
-int db_begin(sqlite3 *db);
-#define INTERFACE 0
+++ /dev/null
-/*
-They say a cast is not required passing a typed pointer to a void * argument,
-but What about void **?
-
-gcc -std=gnu11 -o voidptr voidptr.c
-voidptr.c: In function ‘main’:
-voidptr.c:28:5: warning: passing argument 1 of ‘g’ from incompatible pointer type [-Wincompatible-pointer-types]
- g(&pt, y);
- ^~~
-voidptr.c:13:15: note: expected ‘void **’ but argument is of type ‘int **’
- void g(void **pt0, void *pt1){
- ~~~~~~~^~~
-
-*/
-#include <stdio.h>
-
-int f(void *pt){
- return *(int *)pt;
-}
-
-/* fails
-void g(void **pt0, int *pt1){
- *pt0 = pt1;
-}
-*/
-
-// passes
-void g(void *pt0, int *pt1){
- *(int **)pt0 = pt1;
-}
-
-int main(){
- int x = 5;
- int *xp = &x;
- printf("%d\n",f(xp));
-
- int y[3];
- y[0] = 10;
- y[1] = 11;
- y[2] = 12;
-
- int *pt;
- g(&pt, y);
- printf("%d\n",*pt);
-
- printf("that's all folks\n");
- return 0;
-}
+++ /dev/null
-/*
-Dynamic Array
-
-*/
-
-#include "da.lib.h"
-
-#if INTERFACE
-#include<stdlib.h>
-#include<stdbool.h>
-#endif
-#include<string.h>
-
-//--------------------------------------------------------------------------------
-// generic
-// We manipulate pointers to a smallest addressable unit. The sizeof operator
-// returns counts in these addressable units. Sizeof(char) is defined to be 1.
-
-struct da{
- char *base;
- char *end; // one byte/one item off the end of the array
- size_t *size; // size >= (end - base) + 1;
- size_t item_size;
-};
-
-void da_alloc(da *dap, size_t item_size){
- dap->size = 4 * item_size;
- dap->item_size = item_size;
- dap->end = 0;
- dap->base = malloc(dap->size);
-}
-
-// Doubles size of of da. Returns old base, so that existing pointers into the
-// array can be moved to the new array
-char *da_expand(da *dap){
- size_t end_offset = ((char *)dap->end - (char *)dap->base);
- size_t new_size = dap->size << 1;
- char *old_base = dap->base;
- char *new_base = malloc( new_size );
- memcpy( new_base, dap->base, end_offset + 1);
- free(old_base);
- dap->base = new_base;
- dap->end = new_base + offset;
- dap->size = new_size;
- return old_base;
-}
-
-void da_rebase(da *dap, char *old_base, void *pta){
- char **pt = (char **)pta;
- size_t offset = *pt - old_base;
- *pt = dap->base + offset;
-}
-
-// true when pt has run off the end of the area currently allocated for the array
-bool da_endq(da *dap, void *pt){
- return (char *)pt >= dap->end;
-}
-
-// true when pt has run off the end of the area allocated for the array
-bool da_boundq(da *dap, void *pt){
- return (char *)pt >= dap->base + dap->size
-}
-
-void da_push(da *dap, void *item){
- if( dap->end + dap->item_size >= dap->base + dap->size ) da_expand(dap);
- memcpy(dap->end, item, dap->item_size);
- dap->end += dap->item_size;
-}
-
-// passed in f(item_pt, arg_pt)
-// Curring is difficult in C, so we allow that we might like to have an
-// additional arg. The additional arg may be set to NULL if it is not needed.
-void da_map(da *dap, void f(void *, void *), void *arg){
- char *pt = dap->base;
- while( pt != dap->end ){
- f(pt, arg);
- pt += item_size;
- }
-}
-
-#if INTERFACE
-
-#define RETURN(r) \
- { daps_map(mrs, mrs_end, free); return r; }
-
-#endif
-
+++ /dev/null
-
-#include "dbprintf.lib.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-
-int dbprintf(const char *format, ...){
- va_list args;
- va_start(args,format);
- int ret = vfprintf(stdout, format, args);
- fflush(stdout);
- va_end(args);
- return ret;
-}
+++ /dev/null
-/*
- 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
-void dispatch_f_mess(char *fname, int err, char *dispatchee){
- if(err == 0) return;
- fprintf(stderr, "%s: ", fname); // if fprintf gets an error, errno will be overwritten
- if(err > ERR_DISPATCH){
- fprintf(stderr, "dispatchee \"%s\" returned the error %d\n", dispatchee, err);
- return;
- }
- switch(err){
- case ERR_DISPATCH_NEGATIVE_RETURN_STATUS:
- fprintf(stderr, " dispatchee \"%s\" returned a negative status.", dispatchee);
- break;
- case ERR_DISPATCH_F_FORK:
- case ERR_DISPATCH_F_SETEUID:
- case ERR_DISPATCH_F_SETEGID:
- fputc(' ', stderr);
- perror(dispatchee);
- break;
- case ERR_DISPATCH_NULL_EXECUTABLE:
- fprintf(stderr, " executable was not specified");
- break;
- case ERR_DISPATCH_EXEC:
- // exec is running in another process when it fails, so we can't see the errno value it set
- fprintf(stderr, " exec of \"%s\" failed", dispatchee);
- break;
- default:
- fprintf(stderr, " returned undefined status when dispatching \"%s\"", dispatchee);
- }
- fputc('\n', stderr);
-}
-
-//--------------------------------------------------------------------------------
-// interface call point, dispatch a function
-int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){
- #ifdef DEBUG
- dbprintf("%s %s\n", "dispatch_f", fname);
- #endif
- pid_t pid = fork();
- if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
- 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
- int err;
- waitpid(pid, &err, 0);
- return err;
- }
-}
-
-//--------------------------------------------------------------------------------
-// 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
-int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){
- #ifdef DEBUG
- dbprintf("%s %s as euid:%u egid:%u\n", "dispatch_f_euid_egid", fname, euid, egid);
- #endif
- pid_t pid = fork();
- if( pid == -1 ) return ERR_DISPATCH_F_FORK;
- 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
- uint err;
- waitpid(pid, &err, 0);
- return err;
- }
-}
-
-//--------------------------------------------------------------------------------
-// interface call point, dispatch a executable
-int dispatch_exec(char **argv, char **envp){
- char *command;
- {
- if( !argv || !argv[0] ) return ERR_DISPATCH_NULL_EXECUTABLE;
- #ifdef DEBUG
- dbprintf("dispatch_exec:");
- char **apt = argv;
- while( *apt ){
- dbprintf(" %s",*apt);
- apt++;
- }
- dbprintf("\n");
- #endif
- command = argv[0];
- }
- pid_t pid = fork();
- if( pid == -1 ) return ERR_DISPATCH_F_FORK; // something went wrong and we are still in the parent process
- if( pid == 0 ){ // we are the child
- execvpe(command, argv, envp); // exec will only return if it has an error
- #ifdef DEBUG
- dbprintf("dispatch_exec: exec returned, perror message:");
- perror("dispatch_exec"); // our only chance to print this message, as this is the child process
- #endif
- fflush(stdout);
- exit(ERR_DISPATCH_EXEC);
- }else{ // we are the parent
- int err;
- waitpid(pid, &err, 0);
- return err;
- }
-}
-
-
+++ /dev/null
-/*
-mount all the subu user directories into master's subuland
-uses unmount to undo this
-
-*/
-#include "subu-bind-all.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
- if( argc != 1){
- fprintf(stderr, "%s does not take arguments\n",argv[0]);
- return SUBU_ERR_ARG_CNT;
- }
-
- int rc;
- sqlite3 *db;
- rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
- return SUBU_ERR_DB_FILE;
- }
-
- char *mess;
- rc = subu_bind_all(&mess, db);
- if(rc != 0){
- fprintf(stderr, "subu-bind: %s\n", mess);
- return rc;
- }
- return 0;
-}
+++ /dev/null
-/*
-mount a subu user directory into master's subuland
-uses unmount to undo this
-
-*/
-#include "subu-bind.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
- if( argc != 4){
- fprintf(stderr, "usage: %s masteru subu_username subuhome\n",argv[0]);
- return SUBU_ERR_ARG_CNT;
- }
-
- int rc;
- char *mess;
- rc = subu_bind(&mess, argv[1], argv[2], argv[3]);
- if(rc != 0){
- fprintf(stderr, "subu-bind: %s\n", mess);
- return rc;
- }
- return 0;
-}
+++ /dev/null
-
-#include "subu-common.lib.h"
-
-#if INTERFACE
-typedef unsigned int uint;
-/*
- Fedora 29's sss_cache is checking the inherited uid instead of the effective
- uid, so setuid root scripts will fail when calling sss_cache.
-
- Fedora 29's 'useradd' calls sss_cache, and useradd is called by our setuid root
- program subu-mk-0.
-*/
-#define BUG_SSS_CACHE_RUID 1
-#endif
-
-// char *DB_File = "/etc/subudb";
-char DB_File[] = "subudb";
-uint Subuhome_Perms = 0700;
-uint First_Max_Subunumber = 114;
-char Subuland_Extension[] = "/subuland/";
+++ /dev/null
-/*
- subu-mk-0 command
-
-*/
-#include "subu-mk-0.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
- char *command = argv[0];
- if( argc != 2 ){
- fprintf(stderr, "usage: %s subu", command);
- return SUBU_ERR_ARG_CNT;
- }
- char *subuname = argv[1];
-
- int rc;
- sqlite3 *db;
- rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "error when opening db, %s\n", DB_File);
- fprintf(stderr, "sqlite3 says: %s\n", sqlite3_errmsg(db));
- sqlite3_close(db);
- return SUBU_ERR_DB_FILE;
- }
-
- char *mess;
- rc = subu_mk_0(&mess, db, subuname);
- if( rc ){
- subu_err("subu_mk_0", rc, mess);
- free(mess);
- sqlite3_close(db);
- return rc;
- }
-
- rc = sqlite3_close(db);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-
-}
+++ /dev/null
-/*
- subu-mk-0 command
-
-*/
-#include "subu-rm-0.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
- char *command = argv[0];
- if( argc != 2 ){
- fprintf(stderr, "usage: %s subu", command);
- return SUBU_ERR_ARG_CNT;
- }
- char *subuname = argv[1];
-
- sqlite3 *db;
- {
- int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
- return SUBU_ERR_DB_FILE;
- }}
-
- {
- char *mess=0;
- int ret = subu_rm_0(&mess, db, subuname);
- subu_err("subu_rm_0", ret, mess);
- free(mess);
- return ret;
- }
-}
+++ /dev/null
-/*
- sqllite3 is used to maintain the db file, which is currently compiled
- in as /etc/subu.db, (or just subu.db for testing).
-
- masteru is the user who ran this script. The masteru name comes from getuid
- and /etc/passwd.
-
- subu is a subservient user. The subuname is passed in as an argument.
-
- subu-mk-0 synthesizes a new user user name s<number>, calls useradd to creat
- the new uswer account, and enters the relationship between masteru, subu, and
- s<number> in the db file. It is this relation in the db file that
- associates the subuname with the s<number> user.
-
- subu-rm-0 uses userdel to delete the related s<number> user account. It
- then removes the relaton from the db file.
-
- subu-mk-0 and subu-rm-0 are setuid root scripts.
-
-*/
-#include "subu.lib.h"
-
-// without this #define we get the warning: implicit declaration of function ‘seteuid’/‘setegid’
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#if INTERFACE
-#include <stdbool.h>
-#include <errno.h>
-#include <sqlite3.h>
-#endif
-
-//--------------------------------------------------------------------------------
-// dispatched command errors .. should add mkdir and rmdir ...
-//
-char *useradd_mess(int err){
- if(err <= 0) return NULL;
- char *mess;
- switch(err){
- case 1: mess = "can't update password file"; break;
- case 2: mess = "invalid command syntax"; break;
- case 3: mess = "invalid argument to option"; break;
- case 4: mess = "UID already in use (and no -o)"; break;
- case 5: mess = "undefined"; break;
- case 6: mess = "specified group doesn't exist"; break;
- case 7:
- case 8: mess = "undefined"; break;
- case 9: mess = "username already in use"; break;
- case 10: mess = "can't update group file:"; break;
- case 11: mess = "undefined"; break;
- case 12: mess = "can't create home directory"; break;
- case 13: mess = "undefined"; break;
- case 14: mess = "can't update SELinux user mapping"; break;
- default: mess = "undefined"; break;
- }
- return strdup(mess);
-}
-char *userdel_mess(int err){
- if(err <= 0) return NULL;
- char *mess;
- switch(err){
- case 1: mess = "can't update password file"; break;
- case 2: mess = "invalid command syntax"; break;
- case 3:
- case 4:
- case 5: mess = "undefined"; break;
- case 6: mess = "specified user doesn't exist"; break;
- case 7:
- case 8:
- case 9: mess = "undefined"; break;
- case 10: mess = "can't update group file:"; break;
- case 11: mess = "undefined"; break;
- case 12: mess = "can't remove home directory"; break;
- default: mess = "undefined"; break;
- }
- return strdup(mess);
-}
-
-
-//--------------------------------------------------------------------------------
-//
-#if INTERFACE
-#define SUBU_ERR_ARG_CNT 1
-#define SUBU_ERR_SETUID_ROOT 2
-#define SUBU_ERR_MALLOC 3
-#define SUBU_ERR_MKDIR_SUBUHOME 4
-#define SUBU_ERR_RMDIR_SUBUHOME 5
-#define SUBU_ERR_SUBUNAME_MALFORMED 6
-#define SUBU_ERR_HOMELESS 7
-#define SUBU_ERR_DB_FILE 8
-#define SUBU_ERR_SUBUHOME_EXISTS 9
-#define SUBU_ERR_BUG_SSS 10
-#define SUBU_ERR_FAILED_USERADD 11
-#define SUBU_ERR_FAILED_USERDEL 12
-#define SUBU_ERR_SUBU_NOT_FOUND 13
-#define SUBU_ERR_N 14
-#define SUBU_ERR_BIND 15
-#endif
-
-void subu_err(char *fname, int err, char *mess){
- if(!mess) mess = "";
- switch(err){
- case 0: return;
- case SUBU_ERR_ARG_CNT:
- if(mess[0])
- fprintf(stderr, "Incorrect number of arguments, %s", mess);
- else
- fprintf(stderr, "Incorrect number of arguments.", mess);
- break;
- case SUBU_ERR_SETUID_ROOT:
- fprintf(stderr, "This program must be run setuid root from a user account.");
- break;
- case SUBU_ERR_MALLOC:
- perror(fname);
- break;
- case SUBU_ERR_DB_FILE:
- fprintf(stderr, "error on %s", DB_File); // DB_File is in common
- fprintf(stderr, ": %s", mess);
- break;
- case SUBU_ERR_HOMELESS:
- fprintf(stderr,"Masteru, \"%s\", has no home directory", mess);
- break;
- case SUBU_ERR_SUBUNAME_MALFORMED:
- fprintf(stderr, "subuname, \"%s\" is not in [ _.-a-zA-Z0-9]*", mess);
- break;
- case SUBU_ERR_SUBUHOME_EXISTS:
- fprintf(stderr, "a file system object already exists at subuhome, \"%s\"\n", mess);
- break;
- case SUBU_ERR_MKDIR_SUBUHOME:
- fprintf(stderr, "masteru could not make subuhome, \"%s\"", mess);
- break;
- case SUBU_ERR_BUG_SSS:
- perror(fname);
- break;
- case SUBU_ERR_FAILED_USERADD:
- fprintf(stderr, "%s useradd failed\n", mess);
- break;
- default:
- fprintf(stderr, "unknown error code %d\n", err);
- }
- fputc('\n', stderr);
-}
-
-
-//--------------------------------------------------------------------------------
-// a well formed subuname
-// returns the length of the subuname, or -1
-//
-static int allowed_subuname(char **mess, char *subuname, size_t *subuname_len){
- char *ch = subuname;
- size_t i = 0;
- while(
- *ch
- &&
- ( *ch >= 'a' && *ch <= 'z'
- ||
- *ch >= 'A' && *ch <= 'Z'
- ||
- *ch >= '0' && *ch <= '9'
- ||
- *ch == '-'
- ||
- *ch == '_'
- ||
- *ch == '.'
- ||
- *ch == ' '
- )
- ){
- ch++;
- i++;
- }
- if( !*ch ){
- *subuname_len = i;
- return 0;
- }else{
- if(mess) *mess = strdup(subuname);
- return SUBU_ERR_SUBUNAME_MALFORMED;
- }
-}
-
-//--------------------------------------------------------------------------------
-// dispatched functions
-//
-static int masteru_mkdir_subuhome(void *arg){
- char *subuhome = (char *) arg;
- if( mkdir( subuhome, Subuhome_Perms ) == -1 ){ // find subuhome perms in common
- perror("masteru_mkdir_subuhome");
- return SUBU_ERR_MKDIR_SUBUHOME;
- }
- return 0;
-}
-static int masteru_rmdir_subuhome(void *arg){
- char *subuhome = (char *) arg;
- if( rmdir( subuhome ) == -1 ){ // find subuhome perms in common
- perror("masteru_rmdir_subuhome");
- return SUBU_ERR_RMDIR_SUBUHOME;
- }
- return 0;
-}
-
-//--------------------------------------------------------------------------------
-// build strings
-//
-static int mk_subu_username(char **mess, sqlite3 *db, char **subu_username){
- int rc,n;
- db_begin(db);
- if(
- (rc = subudb_number_get(db, &n))
- ||
- (rc = subudb_number_set(db, ++n))
- ){
- db_rollback(db);
- return SUBU_ERR_DB_FILE;
- }
- db_commit(db);
-
- size_t len = 0;
- FILE* name_stream = open_memstream(subu_username, &len);
- fprintf(name_stream, "s%d", n);
- fclose(name_stream);
- return 0;
-}
-
-// man page says that getpwuid strings may not be freed, I don't know how long until they
-// are overwritten, so I just make my own copies that can be freed
-static int uid_to_name_and_home(uid_t uid, char **name, char **home ){
- struct passwd *pw_record_pt = getpwuid(uid); // reading /etc/passwd
- *name = strdup(pw_record_pt->pw_name);
- *home = strdup(pw_record_pt->pw_dir);
- if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
- return 0;
-}
-
-static int username_to_home(char *name, char **home ){
- struct passwd *pw_record_pt = getpwnam(name); // reading /etc/passwd
- *home = strdup(pw_record_pt->pw_dir);
- if( !home || !home[0] || (*home)[0] == '(' ) return SUBU_ERR_HOMELESS;
- return 0;
-}
-
-static int mk_subuland(char *masteru_home, char **subuland){
- size_t masteru_home_len = strlen(masteru_home);
- char *Subuland_Extension = "/subuland/";
- size_t Subuland_Extension_len = strlen(Subuland_Extension);
- *subuland = (char *)malloc( masteru_home_len + Subuland_Extension_len + 1 );
- if(!*subuland) SUBU_ERR_MALLOC;
- strcpy(*subuland, masteru_home);
- strcpy(*subuland + masteru_home_len, Subuland_Extension);
- return 0;
-}
-
-static int mk_subuhome(char *subuland, char *subuname, char **subuhome){
- size_t subuland_len = strlen(subuland);
- size_t subuhome_len = subuland_len + strlen(subuname); // subuland has a trailing '/'
- *subuhome = (char *)malloc(subuhome_len + 1);
- if(!*subuhome) return SUBU_ERR_MALLOC;
- strcpy (*subuhome, subuland);
- strcpy (*subuhome + subuland_len, subuname);
- return 0;
-}
-
-
-
-//===============================================================================
-int subu_mk_0(char **mess, sqlite3 *db, char *subuname){
-
- int rc;
- if(mess)*mess = 0;
- MK_MRS;
-
- //--------------------------------------------------------------------------------
- size_t subuname_len;
- rc = allowed_subuname(mess, subuname, &subuname_len);
- if(rc) return rc;
- #ifdef DEBUG
- dbprintf("subuname is well formed\n");
- #endif
-
- //--------------------------------------------------------------------------------
- uid_t masteru_uid;
- gid_t masteru_gid;
- uid_t set_euid;
- gid_t set_egid;
- {
- masteru_uid = getuid();
- masteru_gid = getgid();
- set_euid = geteuid();
- set_egid = getegid();
- #ifdef DEBUG
- 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 ) return SUBU_ERR_SETUID_ROOT;
- }
-
- //--------------------------------------------------------------------------------
- char *masteru_name = 0;
- char *masteru_home = 0;
- char *subu_username = 0;
- char *subuland = 0;
- char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
- daps_push(mrs, mrs_end, &mrs_size, masteru_name);
- daps_push(mrs, mrs_end, &mrs_size, masteru_home);
- daps_push(mrs, mrs_end, &mrs_size, subu_username);
- daps_push(mrs, mrs_end, &mrs_size, subuland);
- daps_push(mrs, mrs_end, &mrs_size, subuhome);
- rc =
- uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
- ||
- mk_subu_username(mess, db, &subu_username)
- ||
- mk_subuland(masteru_home, &subuland)
- ||
- mk_subuhome(subuland, subuname, &subuhome)
- ;
- if(rc) RETURN(rc);
- #ifdef DEBUG
- dbprintf("subu_username, subuland, subuhome: \"%s\"\"%s\"\"%s\"\n", subu_username, subuland, subuhome);
- #endif
-
- //--------------------------------------------------------------------------------
- // By having masteru create the subuhome, we know that masteru has rights to
- // to access this directory. This will be the mount point for bindfs
- {
- struct stat st;
- if( stat(subuhome, &st) != -1 ){
- if(mess)*mess = strdup(subuhome);
- RETURN(SUBU_ERR_SUBUHOME_EXISTS);
- }
- int dispatch_err = dispatch_f_euid_egid
- (
- "masteru_mkdir_subuhome",
- masteru_mkdir_subuhome,
- (void *)subuhome,
- masteru_uid,
- masteru_gid
- );
- if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_MKDIR_SUBUHOME ){
- #ifdef DEBUG
- dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_mkdir_subuhome");
- #endif
- if(mess)*mess = strdup(subuhome);
- RETURN(SUBU_ERR_MKDIR_SUBUHOME);
- }
- }
- #ifdef DEBUG
- dbprintf("made directory \"%s\"\n", subuhome);
- #endif
-
- //--------------------------------------------------------------------------------
- // Make the subservient user account, i.e. the subu
- {
- #ifdef DEBUG
- dbprintf("making subu \"%s\" as user \"%s\"\n", subuname, 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 ) RETURN(SUBU_ERR_BUG_SSS);
- #endif
- char *command = "/usr/sbin/useradd";
- char *argv[3];
- argv[0] = command;
- argv[1] = subu_username;
- argv[2] = (char *) NULL;
- char *envp[1];
- envp[0] = (char *) NULL;
- int dispatch_err = dispatch_exec(argv, envp);
- if( dispatch_err != 0 ){
- #ifdef DEBUG
- dispatch_f_mess("dispatch_exec", dispatch_err, command);
- #endif
- // go back and remove the directory we made in subuland
- int dispatch_err_rmdir = dispatch_f_euid_egid
- (
- "masteru_rmdir_subuhome",
- masteru_rmdir_subuhome,
- (void *)subuhome,
- masteru_uid,
- masteru_gid
- );
- #ifdef DEBUG
- dispatch_f_mess("dispatch_f_euid_egid", dispatch_err_rmdir, "masteru_rmdir_subuhome");
- #endif
- if(mess)*mess = useradd_mess(dispatch_err);
- RETURN(SUBU_ERR_FAILED_USERADD);
- }
- #ifdef DEBUG
- dbprintf("added user \"%s\"\n", subu_username);
- #endif
- }
-
- //--------------------------------------------------------------------------------
- #ifdef DEBUG
- dbprintf("setting the masteru_name, subuname, subu_username relation\n");
- #endif
- {
- int rc = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
- if( rc != SQLITE_OK ){
- if(mess)*mess = strdup("insert of masteru subu relation failed");
- RETURN(SUBU_ERR_DB_FILE);
- }
- }
- #ifdef DEBUG
- dbprintf("finished subu-mk-0(%s)\n", subuname);
- #endif
- RETURN(0);
-}
-
-//================================================================================
-int subu_rm_0(char **mess, sqlite3 *db, char *subuname){
-
- int rc;
- if(mess)*mess = 0;
- MK_MRS;
-
- //--------------------------------------------------------------------------------
- size_t subuname_len;
- rc = allowed_subuname(mess, subuname, &subuname_len);
- if(rc) return rc;
- #ifdef DEBUG
- dbprintf("subuname is well formed\n");
- #endif
-
- //--------------------------------------------------------------------------------
- uid_t masteru_uid;
- gid_t masteru_gid;
- uid_t set_euid;
- gid_t set_egid;
- {
- masteru_uid = getuid();
- masteru_gid = getgid();
- set_euid = geteuid();
- set_egid = getegid();
- #ifdef DEBUG
- 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 ) return SUBU_ERR_SETUID_ROOT;
- }
-
- //--------------------------------------------------------------------------------
- // various strings that we will need
- char *masteru_name = 0;
- char *masteru_home = 0;
- char *subuland = 0;
- char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
- daps_push(mrs, mrs_end, &mrs_size, masteru_name);
- daps_push(mrs, mrs_end, &mrs_size, masteru_home);
- daps_push(mrs, mrs_end, &mrs_size, subuland);
- daps_push(mrs, mrs_end, &mrs_size, subuhome);
- rc =
- uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
- ||
- mk_subuland(masteru_home, &subuland)
- ||
- mk_subuhome(subuland, subuname, &subuhome)
- ;
- if(rc) RETURN(rc);
- #ifdef DEBUG
- dbprintf("masteru_home, subuhome: \"%s\", \"%s\"\n", masteru_home, subuhome);
- #endif
-
- //--------------------------------------------------------------------------------
- // removal from db
- char *subu_username = 0;
- daps_push(mrs, mrs_end, &mrs_size, subu_username);
-
- db_begin(db);
-
- rc = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
- if( rc != SQLITE_OK ){
- if(mess) *mess = strdup("subu requested for removal not found under this masteru in db file");
- rc = SUBU_ERR_SUBU_NOT_FOUND;
- db_rollback(db);
- RETURN(rc);
- }
- #ifdef DEBUG
- printf("subu_username: \"%s\"\n", subu_username);
- #endif
-
- rc = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
- if( rc != SQLITE_OK ){
- if(mess)*mess = strdup("removal of masteru subu relation failed");
- db_rollback(db);
- RETURN(SUBU_ERR_DB_FILE);
- }
- #ifdef DEBUG
- dbprintf("removed the masteru_name, subuname, subu_username relation\n");
- #endif
-
- rc = db_commit(db);
- if( rc != SQLITE_OK ){
- if(mess)*mess = strdup("removal of masteru subu relation in unknown state, exiting");
- RETURN(SUBU_ERR_DB_FILE);
- }
-
- // even after removing the last masteru subu relation, we still do not remove
- // the max subu count. Hence, a masteru will keep such for a life time.
-
-
- //--------------------------------------------------------------------------------
- // Only masteru can remove directories from masteru/subuland, so we switch to
- // masteru's uid to perform the rmdir.
- //
- {
- #ifdef DEBUG
- dbprintf("as masteru, removing the directory \"%s\"\n", subuhome);
- #endif
- int dispatch_err = dispatch_f_euid_egid
- (
- "masteru_rmdir_subuhome",
- masteru_rmdir_subuhome,
- (void *)subuhome,
- masteru_uid,
- masteru_gid
- );
- if( dispatch_err <= ERR_DISPATCH || dispatch_err == SUBU_ERR_RMDIR_SUBUHOME ){
- #ifdef DEBUG
- dispatch_f_mess("dispatch_f_euid_egid", dispatch_err, "masteru_rmdir_subuhome");
- #endif
- if(mess)*mess = strdup(subuhome);
- RETURN(SUBU_ERR_RMDIR_SUBUHOME);
- }
- }
-
- //--------------------------------------------------------------------------------
- // Delete the subservient user account
- {
- #ifdef DEBUG
- dbprintf("deleting user \"%s\"\n", 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 ){
- RETURN(SUBU_ERR_BUG_SSS);
- }
- #endif
- char *command = "/usr/sbin/userdel";
- char *argv[4];
- argv[0] = command;
- argv[1] = subu_username;
- argv[2] = "-r";
- argv[3] = (char *) NULL;
- char *envp[1];
- envp[0] = (char *) NULL;
- int dispatch_err = dispatch_exec(argv, envp);
- if( dispatch_err != 0 ){
- #ifdef DEBUG
- dispatch_f_mess("dispatch_exec", dispatch_err, command);
- #endif
- if(mess)*mess = userdel_mess(dispatch_err);
- RETURN(SUBU_ERR_FAILED_USERDEL);
- }
- #ifdef DEBUG
- dbprintf("deleted user \"%s\"\n", subu_username);
- #endif
- }
-
- #ifdef DEBUG
- dbprintf("finished subu-rm-0(%s)\n", subuname);
- #endif
- RETURN(0);
-}
-
-//================================================================================
-// identifies masteru, the bindfs maps each subu_user's home to its mount point
-// in subuland.
-int subu_bind(char **mess, char *masteru_name, char *subu_username, char *subuhome){
-
- int rc;
- if(mess)*mess = 0;
- MK_MRS;
-
- // lookup the subu_user_home
- char *subu_user_home = 0;
- daps_push(mrs, mrs_end, &mrs_size, subu_user_home);
- rc = username_to_home(subu_username, &subu_user_home);
- if( rc ){
- if(mess) *mess = strdup("in subu_bind, subu user home directory lookup in /etc/passwd failed.");
- RETURN(rc);
- }
-
- size_t len = 0;
- char *map = 0;
- daps_push(mrs, mrs_end, &mrs_size, map);
- FILE* map_stream = open_memstream(&map, &len);
- fprintf(map_stream, "--map=%s/%s:@%s/@%s", subu_username, masteru_name, subu_username, masteru_name);
- fclose(map_stream);
-
- char *command = "/usr/bin/bindfs";
- char *argv[5];
- argv[0] = command;
- argv[1] = map;
- argv[2] = subu_user_home;
- argv[3] = subuhome;
- argv[4] = (char *) NULL;
- char *envp[1];
- envp[0] = (char *) NULL;
- int dispatch_err = dispatch_exec(argv, envp);
- if( dispatch_err != 0 ){
- #ifdef DEBUG
- dispatch_f_mess(command, dispatch_err, "dispatch_exec");
- #endif
- if(mess)*mess = strdup("bind failed");
- RETURN(SUBU_ERR_BIND);
- }
- #ifdef DEBUG
- dbprintf("mapped \"%s\" as \"%s\"\n", subu_user_home, subuhome);
- #endif
- RETURN(0);
-}
-
-int subu_bind_all(char **mess, sqlite3 *db){
-
- int rc;
- if(mess)*mess = 0;
- MK_MRS;
-
- //--------------------------------------------------------------------------------
- uid_t masteru_uid;
- gid_t masteru_gid;
- uid_t set_euid;
- gid_t set_egid;
- {
- masteru_uid = getuid();
- masteru_gid = getgid();
- set_euid = geteuid();
- set_egid = getegid();
- #ifdef DEBUG
- 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 ) return SUBU_ERR_SETUID_ROOT;
- }
-
- //--------------------------------------------------------------------------------
- // various strings that we will need
- char *masteru_name = 0;
- char *masteru_home = 0;
- char *subuland = 0;
- daps_push(mrs, mrs_end, &mrs_size, masteru_name);
- daps_push(mrs, mrs_end, &mrs_size, masteru_home);
- daps_push(mrs, mrs_end, &mrs_size, subuland);
- rc =
- uid_to_name_and_home(masteru_uid, &masteru_name, &masteru_home)
- ||
- mk_subuland(masteru_home, &subuland)
- ;
- if(rc) RETURN(rc);
- #ifdef DEBUG
- if(masteru_name)
- dbprintf("masteru_name: \"%s\"", masteru_name);
- else
- dbprintf("masteru_name unknown");
- if(subuland)
- dbprintf("subuland: \"%s\"", subuland);
- else
- dbprintf("subuland unknown");
- dbprintf("\n");
- #endif
-
- //--------------------------------------------------------------------------------
- subudb_subu_element *sa;
- subudb_subu_element *sa_end;
- rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
- if( rc != SQLITE_OK ){
- if(mess)*mess = strdup("db access failed when fetching a list of subus");
- return rc;
- }
- if( sa == sa_end ) return 0; // no subus to bind
-
- // a limitation of our error reporting approach is that we can only
- // return one error, but here is a loop that might generate many
- char *subuhome = 0; // the name of the directory to put in subuland, not subu_user home dir
- uint rc_count = 0;
- subudb_subu_element *pt = sa;
- while( pt != sa_end ){
- rc = mk_subuhome(subuland, pt->subuname, &subuhome);
- #ifdef DEBUG
- if(subuhome)
- dbprintf("subuhome: \"%s\"\n", subuhome);
- else
- dbprintf("subuhome unknown \n");
- #endif
- if(!rc) rc = subu_bind(NULL, masteru_name, pt->subu_username, subuhome);
- if(rc) rc_count++;
- free(subuhome);
- subuhome=0;
- pt++;
- }
- if(rc_count==1){
- RETURN(rc);
- }
- if(rc_count > 1){
- *mess = strdup("multiple errors occured while binding subus");
- RETURN(SUBU_ERR_BIND);
- }
- RETURN(0);
-}
+++ /dev/null
-/*
-This command initializes the db file.
-
-*/
-#include "subudb-init.cli.h"
-#include <stdio.h>
-
-int main(){
- sqlite3 *db;
- if( sqlite3_open(DB_File, &db) != SQLITE_OK ){
- fprintf(stderr, "error exit, could not open db file \"%s\"\n", DB_File);
- return SUBU_ERR_DB_FILE;
- }
- db_begin(db);
- if( subudb_schema(db) != SQLITE_OK ){
- db_rollback(db);
- fprintf(stderr, "error exit, opened db file but could not build schema\n");
- return SUBU_ERR_DB_FILE;
- }
- db_commit(db);
- if( sqlite3_close(db) != SQLITE_OK ){
- fprintf(stderr, "error exit, could not close the db\n");
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-}
+++ /dev/null
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-number.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
- if( argc < 1 || argc > 2){
- fprintf(stderr, "usage: %s [n]\n",argv[0]);
- return SUBU_ERR_ARG_CNT;
- }
-
- int rc;
- sqlite3 *db;
- rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "error exit, could not open db file\n");
- sqlite3_close(db);
- return SUBU_ERR_DB_FILE;
- }
-
- // then arg[1] holds a number to set the max to
- if(argc == 2){
- long int i = strtol(argv[1], NULL, 10);
- if( i < 0 ){
- fprintf(stderr, "n must be positive\n");
- sqlite3_close(db);
- return SUBU_ERR_N;
- }
- if( i > INT_MAX ){
- fprintf(stderr, "n is too big, max supported by this program is %d\n", INT_MAX);
- sqlite3_close(db);
- return SUBU_ERR_N;
- }
- rc = subudb_number_set(db, i);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "couldn't set Max_Subunumber: %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_N;
- }
- }
-
- // read and print the current max
- int n;
- rc = subudb_number_get(db, &n);
- if( rc == SQLITE_OK ){
- printf("%d\n", n);
- }else{
- fprintf(stderr, "couldn't get Max_Subunumber: %s\n", sqlite3_errmsg(db));
- sqlite3_close(db);
- return SUBU_ERR_DB_FILE;
- }
- rc = sqlite3_close(db);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-
-}
+++ /dev/null
-/*
-get the username from the db file
-for testing subudb_Masteru_Subu_get_subu_username
-
-*/
-#include "subudb-rel-get.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
- if(argc != 3){
- fprintf(stderr, "usage: %s masteru_name subuname\n", argv[0]);
- return SUBU_ERR_ARG_CNT;
- }
-
- int rc;
- sqlite3 *db;
- rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
- return SUBU_ERR_DB_FILE;
- }
-
- char *masteru_name = argv[1];
- char *subuname = argv[2];
- char *subu_username;
-
- int ret = subudb_Masteru_Subu_get_subu_username(db, masteru_name, subuname, &subu_username);
- if( ret != SQLITE_DONE ){
- fprintf(stderr, "subudb_Masteru_Subu_get_subu_username indicates failure by returning %d\n",ret);
- fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- ret = sqlite3_close(db);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
- fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-}
+++ /dev/null
-/*
-puts a relation in the masteru/subu table
-
-*/
-#include "subudb-rel-put.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
- if(argc != 4){
- fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
- return 1;
- }
- char *masteru_name = argv[1];
- char *subuname = argv[2];
- char *subu_username = argv[3];
-
- sqlite3 *db;
- {
- int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
- return SUBU_ERR_DB_FILE;
- }}
-
- int ret = subudb_Masteru_Subu_put(db, masteru_name, subuname, subu_username);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "subudb_Masteru_Subu_put indicates failure by returning %d\n",ret);
- fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- ret = sqlite3_close(db);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
- fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-}
+++ /dev/null
-/*
-puts a relation in the masteru/subu table
-
-*/
-#include "subudb-rel-rm.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char **argv){
-
- if(argc != 4){
- fprintf(stderr, "expected: %s masteru_name subuname subu_username\n", argv[0]);
- return 1;
- }
- char *masteru_name = argv[1];
- char *subuname = argv[2];
- char *subu_username = argv[3];
-
- sqlite3 *db;
- {
- int ret = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "could not open db file \"%s\"\n", DB_File);
- return SUBU_ERR_DB_FILE;
- }}
-
- int ret = subudb_Masteru_Subu_rm(db, masteru_name, subuname, subu_username);
- if( ret != SQLITE_DONE ){
- fprintf(stderr, "subudb_Masteru_Subu_rm indicates failure by returning %d\n",ret);
- fprintf(stderr, "sqlite3 issues message, %s\n", sqlite3_errmsg(db));
- printf("put failed\n");
- return 2;
- }
- ret = sqlite3_close(db);
- if( ret != SQLITE_OK ){
- fprintf(stderr, "sqlite3_close(db) indicates failure by returning %d\n",ret);
- fprintf(stderr, "sqlite3 issues message: %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
-}
+++ /dev/null
-/*
-Set or get a new maximum subu number. Currently doesn't do the setting part.
-
-*/
-#include "subudb-subus.cli.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-int main(int argc, char **argv){
-
- if( argc != 2){
- fprintf(stderr, "usage: %s masteru_name\n",argv[0]);
- return SUBU_ERR_ARG_CNT;
- }
- char *masteru_name = argv[1];
-
- int rc;
- sqlite3 *db;
- rc = sqlite3_open_v2(DB_File, &db, SQLITE_OPEN_READWRITE, NULL);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "error exit, could not open db file\n");
- sqlite3_close(db);
- return SUBU_ERR_DB_FILE;
- }
-
- subudb_subu_element *sa;
- subudb_subu_element *sa_end;
- rc = subudb_Masteru_Subu_get_subus(db, masteru_name, &sa, &sa_end);
- if( rc == SQLITE_OK ){
- subudb_subu_element *pt = sa;
- while( pt != sa_end ){
- printf("%s %s\n", pt->subuname, pt->subu_username);
- pt++;
- }
- rc = sqlite3_close(db);
- if( rc != SQLITE_OK ){
- fprintf(stderr, "when closing db, %s\n", sqlite3_errmsg(db));
- return SUBU_ERR_DB_FILE;
- }
- return 0;
- }
- fprintf(stderr, "lookup failed %s\n", sqlite3_errmsg(db));
- sqlite3_close(db);
- return SUBU_ERR_DB_FILE;
-
-}
+++ /dev/null
-/*
-The db file is maintained in SQLite
-
-Because user names of are of limited length, subu user names are always named _s<number>.
-A separate table translates the numbers into the subu names.
-
-The first argument is the biggest subu number in the system, or one minus an
-starting point for subu numbering.
-
-currently a unit converted to base 10 will always fit in a 21 bit buffer.
-
-Each of these returns SQLITE_OK upon success
-*/
-#include "subudb.lib.h"
-
-#if INTERFACE
-#include <sqlite3.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-//--------------------------------------------------------------------------------
-// sqlite transactions don't nest. There is a way to use save points, but still
-// we can't just nest transactions. Instead use these wrappers around the whole
-// of something that needs to be in a transaction.
-int db_begin(sqlite3 *db){
- return sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
-}
-int db_commit(sqlite3 *db){
- return sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
-}
-int db_rollback(sqlite3 *db){
- return sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
-}
-
-//--------------------------------------------------------------------------------
-int subudb_schema(sqlite3 *db){
- int rc;
-
- { // build tables
- char sql[] =
- "CREATE TABLE Masteru_Subu(masteru_name TEXT, subuname TEXT, subu_username TEXT);"
- "CREATE TABLE Attribute_Int(attribute TEXT, value INT);"
- ;
- rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
- if(rc != SQLITE_OK) return rc;
- }
-
- { // data initialization
- char *sql = "INSERT INTO Attribute_Int (attribute, value) VALUES ('Max_Subunumber', ?1);";
- sqlite3_stmt *stmt;
- sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
- sqlite3_bind_int(stmt, 1, First_Max_Subunumber);
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- if( rc != SQLITE_DONE ) return rc;
- }
-
- return SQLITE_OK;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_number_get(sqlite3 *db, int *n){
- char *sql = "SELECT value FROM Attribute_Int WHERE attribute = 'Max_Subunumber';";
- sqlite3_stmt *stmt;
- sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
- int rc = sqlite3_step(stmt);
- if( rc == SQLITE_ROW ){
- *n = sqlite3_column_int(stmt,0);
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- if( rc != SQLITE_DONE ) return rc;
- return SQLITE_OK;
- }
- // should have a message return, suppose
- sqlite3_finalize(stmt);
- return SQLITE_NOTFOUND;
-}
-
-int subudb_number_set(sqlite3 *db, int n){
- int rc;
- char *sql = "UPDATE Attribute_Int SET value = ?1 WHERE attribute = 'Max_Subunumber';";
- sqlite3_stmt *stmt;
- sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
- sqlite3_bind_int(stmt, 1, n);
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- if( rc == SQLITE_DONE ) return SQLITE_OK;
- return rc;
-}
-
-//--------------------------------------------------------------------------------
-// put relation into Masteru_Subu table
-int subudb_Masteru_Subu_put(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
- char *sql = "INSERT INTO Masteru_Subu VALUES (?1, ?2, ?3);";
- sqlite3_stmt *stmt;
- sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
- sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
- sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
- sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
- int rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- if( rc == SQLITE_DONE ) return SQLITE_OK;
- return rc;
-}
-
-//--------------------------------------------------------------------------------
-int subudb_Masteru_Subu_get_subu_username(sqlite3 *db, char *masteru_name, char *subuname, char **subu_username){
- char *sql = "SELECT subu_username FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2;";
- size_t sql_len = strlen(sql);
- sqlite3_stmt *stmt;
- int rc;
- rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
- if( rc != SQLITE_OK ) return rc;
- sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
- sqlite3_bind_text(stmt, 2, subuname, strlen(subuname), SQLITE_STATIC);
- rc = sqlite3_step(stmt);
- if( rc == SQLITE_ROW ){
- const char *username = sqlite3_column_text(stmt, 0);
- *subu_username = strdup(username);
- }else{
- sqlite3_finalize(stmt);
- return rc; // woops this needs to return an error!, be sure it is not SQLITE_DONE
- }
- rc = sqlite3_step(stmt);
- if( rc == SQLITE_DONE ) return SQLITE_OK;
- return rc;
-}
-
-//--------------------------------------------------------------------------------
-
-// we return and array of subudb_subu_info
-#if INTERFACE
-struct subudb_subu_element{
- char *subuname;
- char *subu_username;
-};
-#endif
-static void subu_element_alloc(subudb_subu_element **base, size_t *s){
- da_alloc((void *)base, s, sizeof(subudb_subu_element));
-}
-void subu_element_free(subudb_subu_element *base, subudb_subu_element *end_pt){
- subudb_subu_element *pt = base;
- while( pt != end_pt ){
- free(pt->subuname);
- free(pt->subu_username);
- pt++;
- }
- free(base);
-}
-
-int subudb_Masteru_Subu_get_subus
-(
- sqlite3 *db,
- char *masteru_name,
- subudb_subu_element **sa_pt,
- subudb_subu_element **sa_end_pt
-){
- char *sql = "SELECT subuname, subu_username"
- " FROM Masteru_Subu"
- " WHERE masteru_name = ?1;";
- size_t sql_len = strlen(sql);
- sqlite3_stmt *stmt;
- int rc;
- rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
- if( rc != SQLITE_OK ) return rc;
- sqlite3_bind_text(stmt, 1, masteru_name, strlen(masteru_name), SQLITE_STATIC);
-
- size_t subu_element_size;
- subudb_subu_element *subu_element;
- subu_element_alloc(&subu_element, &subu_element_size);
- subudb_subu_element *pt = subu_element;
- rc = sqlite3_step(stmt);
- while( rc == SQLITE_ROW ){
- if( da_bound(subu_element, pt, subu_element_size) )
- da_expand((void **)&subu_element, (void **)&pt, &subu_element_size);
- pt->subuname = strdup(sqlite3_column_text(stmt, 0));
- pt->subu_username = strdup(sqlite3_column_text(stmt, 1));
- rc = sqlite3_step(stmt);
- pt++;
- }
- sqlite3_finalize(stmt);
- if( rc != SQLITE_DONE ){
- return rc; // woops this needs to return an error!, be sure it is not SQLITE_DONE
- }
- *sa_pt = subu_element;
- *sa_end_pt = pt;
- return SQLITE_OK;
-}
-
-
-//--------------------------------------------------------------------------------
-int subudb_Masteru_Subu_rm(sqlite3 *db, char *masteru_name, char *subuname, char *subu_username){
- char *sql = "DELETE FROM Masteru_Subu WHERE masteru_name = ?1 AND subuname = ?2 AND subu_username = ?3;";
- size_t sql_len = strlen(sql);
- sqlite3_stmt *stmt;
- int rc;
- rc = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
- if( rc != SQLITE_OK ) return rc;
- sqlite3_bind_text(stmt, 1, masteru_name, -1, SQLITE_STATIC);
- sqlite3_bind_text(stmt, 2, subuname, -1, SQLITE_STATIC);
- sqlite3_bind_text(stmt, 3, subu_username, -1, SQLITE_STATIC);
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- if( rc == SQLITE_DONE ) return SQLITE_OK;
- return rc;
-}
+++ /dev/null
-#!/usr/bin/python
-# see the help option for syntax
-# this script must be run from root or sudo
-#
-# on Fedora 29 os.getresuid returned all zeros for a script run from sudo.
-# Hence, I am using the environment variable SUDO_USER
-
-import getpass
-import os
-import sys
-import libuser
-from __future__ import print_function
-
-command = os.path.base(argv[0])
-
-#--------------------------------------------------------------------------------
-# utilities
-#
-def prn(str):
- print(str,end='')
-
-#--------------------------------------------------------------------------------
-# help
-#
-def help():
- print( command +
-""" [=help] [=version] [shell=<shell>][owner=<owner-username>] [subu=]<subu-username>
-Makes a subservient user.
-If no arguments are given, or if =help is given, this message is printed.
-When this command is invoked through sudo, $SUDO_USER is taken as the owner's username.
-Otherwise, when invoked directly from root, the owner= option must be provided.
-The subu-username argument is the username for the new subservient user
-The the new subu home directory is created in /home/owner/subu/.
-Facls are set to give the owner access to the new subu's home directory.
-The shell option is not implemented yet. Probably need a number of other options also.
-"""
- )
-
-def version():
- print(" version 0")
-
-#--------------------------------------------------------------------------------
-# a manager for handling error messages
-#
-class class_err:
-"""
-An error record has the form [flag, message, args]
- class is fatal, warning, info [currently not implemented]
- flag is true if an error has occured [need to change this to a count]
- args is an array of strings to be given after the error message is printed.
-
-The dict holds named error records.
-
-register() is used to name and place error records in the dict. register() is
-typically called multiple times to initialize and error instance.
-
-tattle() is used by the program at run time in order to signal errors.
-
-has_error() returns true if tattle was ever called
-
-report() prints an error report. When errors have occured this
-
-vector() [unimplemented] returns a bit vector with one bit per fatal error
-record, in the order they appear in the dictionary. The bit is set if the error
-ever occured.
-
-We check for as many errors as is convenient to do so rather than stopping on
-the first error.
-"""
-
- # field offsets into the error record
- flag_dex = 0;
- message_dex = 1;
- args_dex = 2;
-
- def __init__(self):
- self.total_cnt = 0
- self.dict = {}
-
- def register(name, message):
- self.dict[name] = [False, message, []]
-
- def tattle(name, *args):
- self.total_cnt += 1
- if name in self.dict:
- self.dict[name][0] = True
- self.dict[name][2].extend(args)
-
- def report():
- if self.total_cnt:
- for k,v in self.dict.items():
- if v[self.flag_dex]:
- print(v[self.message_dex],end='')
- args = v[self.args_dex]
- if length(args) :
- print(args[0],end='')
- for arg in args[1:]:
- print( " " + arg, end='')
- print()
-
-#--------------------------------------------------------------------------------
-# parse the command line
-#
-err.register(
- 'impossible_split',
- "It is not possible, yet this token split into other than one or two pieces: "
- )
-err.register(
- 'lone_delim',
- "No spaces should appear around the '=' delimiter."
- )
-
-args = sys.argv[1:]
-if len(args) == 0 :
- version()
- help()
- exit(1)
-
-#create a dictionary based on the command line arguments
-arg_dict = {}
-subu_cnt = 0
-delim = '='
-for token in args:
- token_pair = split(token, delim);
- if len(token_pair) == 1 : #means there was no '=' in the token
- arg_dict['subu'] = token_pair
- subu_cnt++
- elif len(token_pair) == 2 :
- if token_pair[0] == '' and token_pair[1] == '' :
- err.tattle('lone_delim')
- elif token_pair[1] == '' : # then has trailing delim, will treat the same as a leading delim
- arg_dict[token_pair[0]] = None
- elif token_pair[0] == '' : # then has leading delim
- arg_dict[token_pair[1]] = None
- else:
- arg_dict[token_pair[0]] = token_pair[1]
- else:
- err.tattle('impossible_split', token)
-
-if not arg_dict or arg_dict.get('help'):
- help()
- err.report()
- exit(1)
-
-if arg_dict.get('version'):
- version()
-
-#--------------------------------------------------------------------------------
-# check that the command line arguments are well formed.
-#
-err.register(
- 'too_many_args',
- command + " takes at most one non-option argument, but we counted: "
- )
-err.register(
- 'no_subu'
- command + " missing subservient username."
- )
-err.register(
- 'bad_username'
- "Usernames match ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$, but found: "
- )
-err.register(
- 'unknown_option'
- command + " doesn't implement option: "
- )
-
-subu = arg_dict.get('subu')
-if subu_cnt > 1:
- err.tattle('too_many_args')
-elif not subu
- err.tattle('no_subu')
-elif not re.match("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$", subu)
- err.tattle('bad_username', subu)
-
-for k in arg_dict:
- if k not in ['help', 'version', 'shell', 'owner', 'subu'] :
- err.tattle('unkown_option', k)
-
-if arg_dict.get('shell') :
- print "shell option aint implemented yet"
-
-
-
-#--------------------------------------------------------------------------------
-# check that we have root privilege
-#
-err.register(
- 'not_root'
- command + "requires root privilege"
- )
-
-uid = os.getuid()
-if uid != 0 :
- err.tattle('not root')
-
-username = getpass.getuser()
-sudo_caller_username = os.environ.get('SUDO_USER')
-
-if !sudo_caller_username
- if username not == "root":
- err.tattle('not_root')
- elif:
- owner
-
-
- def has_error(*errs):
- return self.cnt > 0
-
-
-
-#-----
-
-
-
-
-#--------------------------------------------------------------------------------
-# pull out the owner_dir and subu_dir
-#
-admin= libuser.admin()
-
-err_arg_form = class_err()
-err_arg_form.register('too_many', "too many semicolon delineated parts in")
-
-owner_parts = args[0].split(":")
-subu_parts = args[1].split(":")
-
-owner_user_name = owner_parts[0]
-if not owner_user_name:
- err_arg_form.tattle('owner_user_name_missing', args[0])
-else:
- owner_user = admin.lookupUserByName(owner_user_name)
- if owner_user == None:
- err_arg_form.tattle('no_such_user_name', owner_user_name)
- else:
-
-
-subu_user_name = subu_parts[0]
-
-
-if length(owner_parts) > 2:
- err_arg_form.tattle('too_many', args[0])
-elif length(owner_parts) == 2:
- owner_dir = owner_parts[1]
-else # get the home directory
-
-
-
-
-
-#--------------------------------------------------------------------------------
-# set the home directory
-#
-if len(args) > args_dir_index:
- dir = args[args_dir_index]
-else:
- dir = os.getcwd()
-
-home = dir + "/" + name
-home_flag = not os.path.exists(home)
-
-#--------------------------------------------------------------------------------
-# create the user, setfacls
-#
-err_cnt = 0
-name_available_flag = False
-
-if name_flag:
- admin = libuser.admin()
- name_available_flag = name not in admin.enumeratedUsers()
-
-if owner_flag and name_flag and name_available_flag and home_flag :
- user = admin.initUser(name)
- user[libuser.HOMEDIRECTORY] = home
- if opt_shell : user[libuser.SHELL] = opt_shell
- admin.addUser(user)
- #setfacl -m d:u:plato:rwx,u:plato:rwx directory
- setfacl = "setfacl -m d:u:" + name + ":rwx,u:" + name + ":rwx " + home
- exit(0)
-
-#--------------------------------------------------------------------------------
-# error return
-# .. need to grab the return code from setfacl above and delete the user if it fails
-#
-err_flags = 0
-if not owner_flag :
- err_flags |= 2**2
- print "missing owning username argument"
-if not name_flag :
- err_flags |= 2**3
- print name + "missing subservient username argument"
-if not name_available_flag :
- err_flags |= 2**4
- print name + "specified subservient username already exists"
-if not home_flag :
- err_flags |= 2**5
- print "user home directory already exists"
-
-exit(err_flags)
--- /dev/null
+/*
+looks for
+
+#tranche filename ...
+
+Starting at column 1 of each line. Upon finding that, it copies all following lines
+into filename, until reaching a line that has:
+
+#endtranche
+
+
+*/