From: Thomas Walker Lynch Date: Thu, 28 Mar 2019 01:11:15 +0000 (+0100) Subject: new structure in prep for using tranche X-Git-Url: https://git.reasoningtechnology.com/style/rt_dark_doc.css?a=commitdiff_plain;h=4e4b6683c8be2c859180f6784436f343664a2bf2;p=subu new structure in prep for using tranche --- diff --git a/da/makefile b/da/makefile new file mode 100644 index 0000000..67fbdb9 --- /dev/null +++ b/da/makefile @@ -0,0 +1,21 @@ +# da/makefile + +SHELL=/bin/bash +MAKE= + +-include makefile-flags + +.PHONY: all +all: version dep lib exec + +.PHONY: lib +lib: + $(MAKE) $@ + cp src/da.lib.h include/da.h + +%:: + $(MAKE) $@ + + + + diff --git a/da/makefile-flags b/da/makefile-flags new file mode 100644 index 0000000..d732652 --- /dev/null +++ b/da/makefile-flags @@ -0,0 +1,35 @@ + +MODULE=da + +# 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, EXECDIR, INCDIR 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=deprecated +DOCDIR=doc +EXECDIR=exec +INCDIR=include +LIBDIR=lib +SRCDIR=src +TESTDIR=test +TMPDIR=tmp +TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) +TRYDIR=try + +# compiler and flags +C=gcc +CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB +#CFLAGS=-std=gnu11 -fPIC -I. -Werror +LINKFLAGS=-Llib -lda + +MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc +#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc + + diff --git a/da/src/da.lib.c b/da/src/da.lib.c new file mode 100644 index 0000000..0956d7e --- /dev/null +++ b/da/src/da.lib.c @@ -0,0 +1,132 @@ +/* +Dynamic Array + +*/ + +#include "da.lib.h" + +#include +#include +#include + +//-------------------------------------------------------------------------------- +// 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. + +void da_alloc(Da *dap, size_t element_size){ + dap->element_size = element_size; + dap->size = 4 * element_size; + dap->base = malloc(dap->size); + dap->end = dap->base; +} +void da_free(Da *dap){ + free(dap->base); + dap->size = 0; +} +void da_rewind(Da *dap){ + dap->end = dap->base; +} + +bool da_empty(Da *dap){ + return dap->end == dap->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; +} + +// 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){ + char *old_base = dap->base; + size_t end_offset = dap->end - old_base; + size_t new_size = dap->size << 1; + char *new_base = malloc( new_size ); + memcpy( new_base, old_base, end_offset + dap->element_size); + free(old_base); + dap->base = new_base; + dap->end = new_base + end_offset; + dap->size = new_size; + return old_base; +} + +// 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){ + return dap->end >= dap->base + dap->size; +} + +void da_push(Da *dap, void *element){ + if( dap->end >= dap->base + dap->size ) da_expand(dap); + memcpy(dap->end, element, dap->element_size); + dap->end += dap->element_size; +} + +bool da_pop(Da *dap, void *element){ + bool flag = dap->end >= dap->base + dap->element_size; + if( flag ){ + dap->end -= dap->element_size; + if(element) memcpy(element, dap->end, dap->element_size); + } + return flag; +} + +char *da_index(Da *dap, size_t i){ + size_t offset = i * dap->element_size; + char *pt = dap->base + offset; + return pt; +} + +// passed in f(element_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->element_size; + } +} + +// da_lists are sometimes used as resource managers +static void da_free_element(void *pt, void *closure){ + free(*(char **)pt); // free does not care about the pointer type +} + +void da_free_elements(Da *dap){ + da_map(dap, da_free_element, NULL); + da_rewind(dap); +} + +// for the case of an array of strings +void da_strings_puts(Da *dap){ + char *pt = dap->base; + while( pt != dap->end ){ + puts(*(char **)pt); + pt += dap->element_size; + } +} + + +// Puts text from a line into buffer *dap. Does not push EOF or '\n' into the +// buffer. Returns the old_base so that external pointers can be rebased. +// It is possible that the the base hasn't changed. Use feof(FILE *stream) to +// test for EOF; +char *da_fgets(Da *dap, FILE *file){ + char *old_base = dap->base; + int c = fgetc(file); + while( c != EOF && c != '\n' ){ + da_push(dap, &c); + c = fgetc(file); + } + int terminator = 0; + da_push(dap, &terminator); + return old_base; +} diff --git a/da/src/da.lib.h b/da/src/da.lib.h new file mode 100644 index 0000000..6d3c43b --- /dev/null +++ b/da/src/da.lib.h @@ -0,0 +1,33 @@ +#ifndef DA_LIB_H +#define DA_LIB_H +#include +#include +#include + +typedef struct Da{ + char *base; + char *end; // one byte/one element off the end of the array + size_t size; // size >= (end - base) + 1; + size_t element_size; +} Da; + +#define RETURN(dap, r) \ + { da_map(dap, da_free, NULL); return r; } + +void da_alloc(Da *dap, size_t element_size); +void da_free(Da *dap); +void da_rewind(Da *dap); +char *da_expand(Da *dap); +void da_rebase(Da *dap, char *old_base, void *pta); +bool da_endq(Da *dap, void *pt); +bool da_boundq(Da *dap); +void da_push(Da *dap, void *element); +bool da_pop(Da *dap, void *element); +char *da_index(Da *dap, size_t i); +void da_map(Da *dap, void f(void *, void *), void *closure); +void da_free_elements(Da *dap); +void da_strings_puts(Da *dap); +char *da_fgets(Da *dap, FILE *fd); + +#endif + diff --git a/da/test/makefile b/da/test/makefile new file mode 100644 index 0000000..dbd6be0 --- /dev/null +++ b/da/test/makefile @@ -0,0 +1,15 @@ +# da/test + +SHELL=/bin/bash + +-include makefile-flags + +.PHONY: all +all: version deps lib exec + +%:: + $(MAKE) $@ + + + + diff --git a/da/test/makefile-dep b/da/test/makefile-dep new file mode 100644 index 0000000..cf61fb9 --- /dev/null +++ b/da/test/makefile-dep @@ -0,0 +1,5 @@ +./test_da.lib.o: test_da.lib.c ../include/da.h test_da.lib.h +./test_da.cli.o: test_da.cli.c test_da.lib.h + +./test_da : ./test_da.cli.o ./libtest.a + gcc -o ./test_da ./test_da.cli.o -L. -L../lib -ltest -lda diff --git a/da/test/makefile-flags b/da/test/makefile-flags new file mode 100644 index 0000000..d916748 --- /dev/null +++ b/da/test/makefile-flags @@ -0,0 +1,33 @@ + +MODULE=test + +# 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= +EXECDIR=. +INCDIR=. +LIBDIR=. +SRCDIR=. +TESTDIR= +TMPDIR=. +TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) +TRYDIR= + +# compiler and flags +C=gcc +CFLAGS=-std=gnu11 -fPIC -I../include -ggdb -Werror -DDEBUG -DDEBUGDB +#CFLAGS=-std=gnu11 -fPIC -I../include -Werror +LINKFLAGS=-L. -L../lib -ltest -lda + +MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc +#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc diff --git a/da/test/results b/da/test/results new file mode 100644 index 0000000..9e59b33 --- /dev/null +++ b/da/test/results @@ -0,0 +1 @@ +passed all 4 tests diff --git a/da/test/test.dat b/da/test/test.dat new file mode 100644 index 0000000..6b4b5bd --- /dev/null +++ b/da/test/test.dat @@ -0,0 +1,3 @@ +this is a test +ends without a newline +(setq mode-require-final-newline nil) \ No newline at end of file diff --git a/da/test/test_da.cli.c b/da/test/test_da.cli.c new file mode 100644 index 0000000..bee5a6c --- /dev/null +++ b/da/test/test_da.cli.c @@ -0,0 +1,46 @@ + +#include +#include +#include "test_da.lib.h" + +int main(){ + bool da_0_passed = test_da_0(); + + unsigned int passed = 0; + unsigned int failed = 0; + + // enumeration of tests + typedef bool (*test_fun)(); + test_fun tests[] = {test_da_0, test_da_1, test_da_2, test_da_3, NULL}; + char *test_names[] = {"test_da_0", "test_da_1", "test_da_2", "test_da_3", NULL}; + + // call tests + test_fun *tfp = tests; + char **tnp = test_names; + while(*tfp){ + if( !(*tfp)() ){ + failed++; + if(*tnp) + printf("%s failed\n", *tnp); + else + fprintf(stderr, "internal error, no test_names[] entry for test\n"); + }else + passed++; + tfp++; + tnp++; + } + + // summarize results + + if( passed == 0 && failed == 0) + printf("no tests ran\n"); + else if( passed == 0 ) + printf("failed all %u tests\n", failed); + else if( failed == 0 ) + printf("passed all %u tests\n", passed); + else + printf("failed %u of %u tests\n", failed, passed + failed); + + if( passed == 0 || failed != 0 ) return 1; + return 0; +} diff --git a/da/test/test_da.cli.o b/da/test/test_da.cli.o new file mode 100644 index 0000000..d28221c Binary files /dev/null and b/da/test/test_da.cli.o differ diff --git a/da/test/test_da.lib.c b/da/test/test_da.lib.c new file mode 100644 index 0000000..88a94c7 --- /dev/null +++ b/da/test/test_da.lib.c @@ -0,0 +1,130 @@ +/* +Tests for Da. + +*/ + +#include +#include +#include +#include + +#include "test_da.lib.h" + +// tests push +bool test_da_0(){ + Da da; + da_alloc(&da, sizeof(int)); // leaves room for 4 ints + int i = 0; + int *pt = (int *)da.base; + // will double, 4 -> 8, then double 8 -> 16 + while( i < 10 ){ + da_push(&da, &i); + i++; + pt++; + } + + bool f0 = da.size == sizeof(int) * 16; + bool f1 = 10 == (da.end - da.base) / sizeof(int); + bool f2 = true; + pt = (int *)da.base; + i = 0; + while( i < 10 ){ + f2 = f2 && *pt == i && !da_endq(&da, pt); + i++; + pt++; + } + bool f3 = da_endq(&da, pt); + + return f0 && f1 && f2 && f3; +} + +// tests manual expansion +bool test_da_1(){ + Da da; + da_alloc(&da, sizeof(int)); // leaves room for 4 ints + int i = 0; + int *pt = (int *)da.base; + // will double, 4 -> 8, then double 8 -> 16 + while( i < 10 ){ + da.end += da.element_size; + if( da_boundq(&da) ){ + char *old_base = da_expand(&da); + da_rebase(&da, old_base, &pt); + } + *pt = i; + i++; + pt++; + } + + bool f0 = da.size == sizeof(int) * 16; + bool f1 = 10 == (da.end - da.base) / sizeof(int); + bool f2 = true; + pt = (int *)da.base; + i = 0; + while( i < 10 ){ + f2 = f2 && *pt == i && !da_endq(&da, pt); + i++; + pt++; + } + bool f3 = da_endq(&da, pt); + + return f0 && f1 && f2 && f3; +} + +// da_fgets +bool test_da_2(){ + + FILE *fd = fopen("test.dat","r"); + + Da da; + da_alloc(&da, sizeof(char)); + + da_fgets(&da, fd); + bool f0 = !strcmp(da.base, "this is a test"); + + char *old_base; + da_pop(&da, NULL); // pop the prior null terminator + char *s1 = da.end; + old_base = da_fgets(&da,fd); + da_rebase(&da, old_base, &s1); + bool f1 = !strcmp(s1, "ends without a newline"); + + da_pop(&da, NULL); // pop the prior null terminator + char *s2 = da.end; + old_base = da_fgets(&da,fd); + da_rebase(&da, old_base, &s2); + bool f2 = !strcmp(s2, "(setq mode-require-final-newline nil)"); + + bool f3 = !strcmp(da.base, "this is a testends without a newline(setq mode-require-final-newline nil)"); + + fclose(fd); + return f0 && f1 && f2 && f3; +} + +// da_fgets +bool test_da_3(){ + + FILE *fd = fopen("test.dat","r"); + + Da da; + da_alloc(&da, sizeof(int)); + + int i = 5; + da_push(&da, &i); + i++; + da_push(&da, &i); + i++; + da_push(&da, &i); + + int j; + bool f0 = da_pop(&da, &j) && j == 7; + bool f1 = da_pop(&da, &j) && j == 6; + bool f2 = da_pop(&da, NULL); + bool f3 = !da_pop(&da, &j); + + return f0 && f1 && f2 && f3; +} + + + + diff --git a/da/test/test_da.lib.h b/da/test/test_da.lib.h new file mode 100644 index 0000000..686b0d0 --- /dev/null +++ b/da/test/test_da.lib.h @@ -0,0 +1,9 @@ +#ifndef DA_LIB_H +#define DA_LIB_H + +bool test_da_0(); +bool test_da_1(); +bool test_da_2(); +bool test_da_3(); + +#endif diff --git a/da/test/test_da.lib.o b/da/test/test_da.lib.o new file mode 100644 index 0000000..2a03683 Binary files /dev/null and b/da/test/test_da.lib.o differ diff --git a/db/0_makefile b/db/0_makefile new file mode 100644 index 0000000..b8c7b9d --- /dev/null +++ b/db/0_makefile @@ -0,0 +1,40 @@ +# 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) $@ + + + + diff --git a/db/0_makefile-flags b/db/0_makefile-flags new file mode 100644 index 0000000..0da8b61 --- /dev/null +++ b/db/0_makefile-flags @@ -0,0 +1,31 @@ + +# 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 + +LIBFILE=$(LIBDIR)/libsubu.a + diff --git a/db/1_doc/return-from-transaction.txt b/db/1_doc/return-from-transaction.txt new file mode 100644 index 0000000..b7f8cbb --- /dev/null +++ b/db/1_doc/return-from-transaction.txt @@ -0,0 +1,15 @@ + +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. diff --git a/db/dbprintf.lib.c b/db/dbprintf.lib.c new file mode 100644 index 0000000..d9d236b --- /dev/null +++ b/db/dbprintf.lib.c @@ -0,0 +1,14 @@ + +#include "dbprintf.lib.h" + +#include +#include + +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; +} diff --git a/dispatch/makefile b/dispatch/makefile new file mode 100644 index 0000000..175b683 --- /dev/null +++ b/dispatch/makefile @@ -0,0 +1,14 @@ +# src-dispatch/makefile + +SHELL=/bin/bash + +-include makefile-flags + +all: version dep lib + +%:: + $(MAKE) $@ + + + + diff --git a/dispatch/makefile-flags b/dispatch/makefile-flags new file mode 100644 index 0000000..48cadc2 --- /dev/null +++ b/dispatch/makefile-flags @@ -0,0 +1,20 @@ + +# 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 + +# compiler and flags +C=gcc +CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB +#CFLAGS=-std=gnu11 -fPIC -I. -Werror + +LINKFLAGS=-L1_lib -lda + +MODULE=dispatch + +MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_trc +#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_trc + diff --git a/dispatch/src/dispatch.lib.c b/dispatch/src/dispatch.lib.c new file mode 100644 index 0000000..e34d020 --- /dev/null +++ b/dispatch/src/dispatch.lib.c @@ -0,0 +1,166 @@ +#tranche tmp/dispatch.trc.c + +#tranche include/dispatch.h +/* + Runs a command or function as its own process. + + The return status integer 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. + +*/ +#ifndef DISPATCH_LIB_H +#define DISPATCH_LIB_H +#include +#include + +#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 + +// 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 +}; +#tranche-end + +#include "dispatch.h" + +// we need the declaration for uid_t etc. +// without this #define execvpe is undefined +#define _GNU_SOURCE + +#include +#include +#include +#include + +#tranche include/dispatch.h +void dispatch_f_mess(char *fname, int err, char *dispatchee); +#tranche-end +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 +#tranche include/dispatch.h +int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg); +#tranche-end +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 +#tranche include/dispatch.h +int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid); +#tranche-end +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 +#tranche include/dispatch.h +int dispatch_exec(char **argv, char **envp); +#tranche-end +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; + } +} + +#tranche-end diff --git a/doc/dir-structure.txt b/doc/dir-structure.txt index 668b909..b385074 100644 --- a/doc/dir-structure.txt +++ b/doc/dir-structure.txt @@ -1,6 +1,9 @@ ~ is the project directory +-------------------------------------------------------------------------------- +most subdirectories are source modules + -------------------------------------------------------------------------------- ~/tools @@ -27,29 +30,7 @@ Typically the install target copies material in the staging area to system locations. -------------------------------------------------------------------------------- -~/src - -The prefixed numbered directories are overhead for building the src code. - -src/1_tests these are programs that typically must pass before the compiled -code may be staged. Tests typically make use of the library in 2_lib and -the header files in 2_include. - -src/1_try a free area for the programmer to try things out. For example when -learning a language. Programs and code left in this directory might be interesting -to newcomers. - -src/2_bin these are cli executables that have been created by the makefile -and will be staged after testing - -src/2_include interface header files to be released with the lib. These might -be different from the build header files found in the src dir. - -src/2_lib holds libraries being tested. Currently each src directory only -builds one library. - -3_documents these are for developers working on src. A user manual might -be under development. +~/ diff --git a/makefile b/makefile index c8d9a4e..ddad312 100755 --- a/makefile +++ b/makefile @@ -1,13 +1,15 @@ -SRCDIRS= $(wildcard src-*) -MAKEABLE=$(shell \ - find src-*\ - -mindepth 1 \ - \( -name '?_makefile' -o -name 'makefile' -o -name 'Makefile' \)\ - -printf "%h\n"\ - | grep -v deprecated | grep -v doc | sort -u | sed ':a;N;$!ba;s/\n/ /g' \ -) - -all : +#MAKEABLE=$(shell \ +# find .\ +# \( -name 'makefile' -o -name 'Makefile' \)\ +# -printf "%h\n"\ +# | grep -v deprecated | grep -v doc | sort -u | sed ':a;N;$!ba;s/\n/ /g' \ +#) + +MAKEABLE= da da/test tranche + +.PHONY: all info clean dist-clean + +all: $(foreach dir, $(MAKEABLE), \ make -C $$dir -make -C $$dir stage @@ -17,10 +19,11 @@ info: @echo "SRCDIRS:" $(SRCDIRS) @echo "MAKEABLE:" $(MAKEABLE) -clean : +clean: for dir in $(MAKEABLE); do pushd $$dir; make clean; popd; done -dist-clean : clean +dist-clean : + for dir in $(MAKEABLE); do pushd $$dir; make dist-clean; popd; done for i in $(wildcard stage/lib/*); do rm $$i; done for i in $(wildcard stage/inc/*); do rm $$i; done for i in $(wildcard stage/bin/*); do rm $$i; done diff --git a/src-0/0_makefile b/src-0/0_makefile deleted file mode 100644 index b8c7b9d..0000000 --- a/src-0/0_makefile +++ /dev/null @@ -1,40 +0,0 @@ -# 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) $@ - - - - diff --git a/src-0/0_makefile-flags b/src-0/0_makefile-flags deleted file mode 100644 index 0da8b61..0000000 --- a/src-0/0_makefile-flags +++ /dev/null @@ -1,31 +0,0 @@ - -# 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 - -LIBFILE=$(LIBDIR)/libsubu.a - diff --git a/src-0/1_deprecated/dispatch_exec.lib.c b/src-0/1_deprecated/dispatch_exec.lib.c deleted file mode 100644 index 024bff8..0000000 --- a/src-0/1_deprecated/dispatch_exec.lib.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - fork/execs/wait the command passed in argv[0]; - Returns -1 upon failure. - - The wstatus returned from wait() might be either the error returned by exec - when it failed, or the return value from the command. An arbitary command is - passed in, so we don't know what its return values might be. Consquently, we - have no way of multiplexing a unique exec error code with the command return - value within wstatus. If the prorgrammer knows the return values of the - command passed in, and wants better behavior, he or she can spin a special - version of dispatch for that command. -*/ -#include "dispatch_exec.lib.h" - -// without this #define execvpe is undefined -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - - - -int dispatch_exec(char **argv, char **envp){ - if( !argv || !argv[0] ){ - fprintf(stderr, "argv[0] null. Null command passed into dispatch().\n"); - return -1; - } - #ifdef DEBUG - dbprintf("dispatching exec, args follow:\n"); - char **apt = argv; - while( *apt ){ - dbprintf("\t%s",*apt); - apt++; - } - dbprintf("\n"); - #endif - char *command = argv[0]; - pid_t pid = fork(); - if( pid == -1 ){ - fprintf(stderr, "fork() failed in dispatch().\n"); - return -1; - } - if( pid == 0 ){ // we are the child - execvpe(command, argv, envp); - // exec will only return if it has an error .. - perror(command); - return -1; - }else{ // we are the parent - int wstatus; - waitpid(pid, &wstatus, 0); - if(wstatus) - return -1; - else - return 0; - } -} diff --git a/src-0/1_deprecated/dispatch_f.lib.c b/src-0/1_deprecated/dispatch_f.lib.c deleted file mode 100644 index 5c199f5..0000000 --- a/src-0/1_deprecated/dispatch_f.lib.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - Forks a new process and runs the a function in that new process. I.e. it 'spawns' a function. - - f must have the specified prototype. I.e. it accepts one void pointer and - returns a positive integer. (Negative integers are used for dispatch error codes.) - - dispatch_f_euid_egid changes to the new euid and egid before running the function. - - If the change to in euid/egid fails, the forked process exits with a negative status. - If the function has an error, it returns a positive status. A status of zero means - that all went well. - - Because f is running in a separate process, the return status is the only means - of communication going back to the calling process. - - -*/ -#define _GNU_SOURCE - -#include "dispatch_f.lib.h" -// we need the declaration for uid_t etc. -// without this #define execvpe is undefined -#define _GNU_SOURCE - -#include -#include -#include -#include - -#if INTERFACE -#include -#include -#endif - -//-------------------------------------------------------------------------------- -// dispatch_f_ctx class -// -#if INTERFACE -#define ERR_NEGATIVE_RETURN_STATUS -1 -#define ERR_DISPATCH_F_FORK -2 -#define ERR_DISPATCH_F_SETEUID -3 -#define ERR_DISPATCH_F_SETEGID -4 - -// both name and fname are static allocations -struct dispatch_f_ctx{ - char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid") - char *dispatchee; // name of the function being dispatched - int err; - int status; // return value from the function -}; -#endif -dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){ - dispatch_f_ctx *ctxp = malloc(sizeof(dispatch_f_ctx)); - ctxp->dispatcher = name; - ctxp->dispatchee = fname; - ctxp->err = 0; - return ctxp; -} -void dispatch_f_ctx_free(dispatch_f_ctx *ctxp){ - // no dynamic variables to be freed in ctx - free(ctxp); -} -void dispatch_f_mess(struct dispatch_f_ctx *ctxp){ - if(ctxp->err == 0) return; - switch(ctxp->err){ - case ERR_NEGATIVE_RETURN_STATUS: - fprintf(stderr, "%s, function \"%s\" broke contract with a negative return value.", ctxp->dispatcher, ctxp->dispatchee); - break; - case ERR_DISPATCH_F_FORK: - case ERR_DISPATCH_F_SETEUID: - case ERR_DISPATCH_F_SETEGID: - fprintf(stderr, "%s, ", ctxp->dispatcher); - perror(ctxp->dispatcher); - break; - } - fputc('\n', stderr); -} - -//-------------------------------------------------------------------------------- -// interface call point -dispatch_f_ctx *dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){ - dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f", fname); - #ifdef DEBUG - dbprintf("%s %s\n", ctxp->dispatcher, ctxp->dispatchee); - #endif - pid_t pid = fork(); - if( pid == -1 ){ - ctxp->err = ERR_DISPATCH_F_FORK; // we are still in the parent process - return ctxp; - } - if( pid == 0 ){ // we are the child - int status = (*f)(f_arg); // we require that f return a zero or positive value - if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; - exit(status); - }else{ // we are the parent - waitpid(pid, &(ctxp->status), 0); - return ctxp; - } -} - -//-------------------------------------------------------------------------------- -// interface call point -dispatch_f_ctx *dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){ - dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f_euid_egid", fname); - #ifdef DEBUG - dbprintf("%s %s as euid:%u egid:%u\n", ctxp->dispatcher, ctxp->dispatchee, euid, egid); - #endif - pid_t pid = fork(); - if( pid == -1 ){ - ctxp->err = ERR_DISPATCH_F_FORK; - return ctxp; - } - if( pid == 0 ){ // we are the child - int status; - if( seteuid(euid) == -1 ) - status = ERR_DISPATCH_F_SETEUID; - else if( setegid(egid) == -1 ) - status = ERR_DISPATCH_F_SETEGID; - else{ - status = (*f)(f_arg); - if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; - exit(status); - } - }else{ // we are the parent - waitpid(pid, &(ctxp->status), 0); - return ctxp; - } -} - - diff --git a/src-0/1_deprecated/dispatch_useradd.lib.c b/src-0/1_deprecated/dispatch_useradd.lib.c deleted file mode 100644 index 7b75291..0000000 --- a/src-0/1_deprecated/dispatch_useradd.lib.c +++ /dev/null @@ -1,68 +0,0 @@ -/* -There is no C library interface to useradd(8), but if there were, this function -would be found there instead. - -*/ -#include "dispatch_useradd.lib.h" - -#include -#include -#include -#include -#include - -#if INTERFACE -#include -#include -#define ERR_DISPATCH_USERADD_ARGC 1 -#define ERR_DISPATCH_USERADD_DISPATCH 2 -#define ERR_DISPATCH_USERADD_PWREC 3 -struct dispatch_useradd_ret_t{ - uint error; - struct passwd *pw_record; -}; -#endif - - -// we have a contract with the caller that argv[1] is always the subuname -struct dispatch_useradd_ret_t dispatch_useradd(char **argv, char **envp){ - struct dispatch_useradd_ret_t ret; - { - if( !argv || !argv[0] || !argv[1]){ - fprintf(stderr,"useradd() needs a first argument as the name of the user to be made"); - ret.error = ERR_DISPATCH_USERADD_ARGC; - ret.pw_record = NULL; - return ret; - } - - char *subu_name; - { - subu_name = argv[1]; - if( dispatch_exec(argv, envp) == -1 ){ - fprintf(stderr,"%s failed\n", argv[0]); - ret.error = ERR_DISPATCH_USERADD_DISPATCH; - ret.pw_record = NULL; - return ret; - }} - - { - struct passwd *pw_record = getpwnam(subu_name); - uint count = 1; - while( !pw_record && count <= 3 ){ - #ifdef DEBUG - printf("try %u, getpwnam failed, trying again\n", count); - #endif - sleep(1); - pw_record = getpwnam(subu_name); - count++; - } - if( !pw_record ){ - ret.error = ERR_DISPATCH_USERADD_PWREC; - ret.pw_record = NULL; - return ret; - } - ret.error = 0; - ret.pw_record = pw_record; - return ret; - }}} - diff --git a/src-0/1_deprecated/subu-rm-0.lib.c b/src-0/1_deprecated/subu-rm-0.lib.c deleted file mode 100644 index ccad437..0000000 --- a/src-0/1_deprecated/subu-rm-0.lib.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - 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 -#include -#include -#include -#include -#include -#include -#include - -#if INTERFACE -#include -#include -#include -#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; -} diff --git a/src-0/1_deprecated/subudb-number-next.cli.c b/src-0/1_deprecated/subudb-number-next.cli.c deleted file mode 100644 index 3373173..0000000 --- a/src-0/1_deprecated/subudb-number-next.cli.c +++ /dev/null @@ -1,45 +0,0 @@ -/* -Set or get a new maximum subu number. Currently doesn't do the setting part. - -*/ -#include "subudb-number-next.cli.h" -#include -#include -#include - -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; -} diff --git a/src-0/1_doc/to_do.txt b/src-0/1_doc/to_do.txt deleted file mode 100644 index 0b989cc..0000000 --- a/src-0/1_doc/to_do.txt +++ /dev/null @@ -1,38 +0,0 @@ -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. diff --git a/src-0/1_tests/0_makefile b/src-0/1_tests/0_makefile deleted file mode 100644 index 67cea25..0000000 --- a/src-0/1_tests/0_makefile +++ /dev/null @@ -1,32 +0,0 @@ -# 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) $@ - - - - diff --git a/src-0/1_tests/0_makefile_flags b/src-0/1_tests/0_makefile_flags deleted file mode 100644 index 8818691..0000000 --- a/src-0/1_tests/0_makefile_flags +++ /dev/null @@ -1,31 +0,0 @@ - -# 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 - -LIBFILE=$(LIBDIR)/libtests.a - diff --git a/src-0/1_tests/1_tmp/makefile_deps b/src-0/1_tests/1_tmp/makefile_deps deleted file mode 100644 index 9486ae8..0000000 --- a/src-0/1_tests/1_tmp/makefile_deps +++ /dev/null @@ -1,4 +0,0 @@ -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 diff --git a/src-0/1_tests/da.cli.c b/src-0/1_tests/da.cli.c deleted file mode 100644 index 910a15e..0000000 --- a/src-0/1_tests/da.cli.c +++ /dev/null @@ -1,50 +0,0 @@ -/* -Tests for da. - -*/ - -#include -#include - -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; - -} diff --git a/src-0/1_tests/libtests.a b/src-0/1_tests/libtests.a deleted file mode 100644 index 8b277f0..0000000 --- a/src-0/1_tests/libtests.a +++ /dev/null @@ -1 +0,0 @@ -! diff --git a/src-0/1_tmp/da.lib.h b/src-0/1_tmp/da.lib.h deleted file mode 100644 index 4702189..0000000 --- a/src-0/1_tmp/da.lib.h +++ /dev/null @@ -1,23 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -#include -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 diff --git a/src-0/1_tmp/dbprintf.lib.h b/src-0/1_tmp/dbprintf.lib.h deleted file mode 100644 index 3056cf6..0000000 --- a/src-0/1_tmp/dbprintf.lib.h +++ /dev/null @@ -1,3 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -int dbprintf(const char *format,...); diff --git a/src-0/1_tmp/dispatch.lib.h b/src-0/1_tmp/dispatch.lib.h deleted file mode 100644 index 07e2271..0000000 --- a/src-0/1_tmp/dispatch.lib.h +++ /dev/null @@ -1,24 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -#include -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 diff --git a/src-0/1_tmp/subu-bind-all.cli.h b/src-0/1_tmp/subu-bind-all.cli.h deleted file mode 100644 index 7e52675..0000000 --- a/src-0/1_tmp/subu-bind-all.cli.h +++ /dev/null @@ -1,9 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -#include -#include -int subu_bind_all(char **mess,sqlite3 *db); -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; -#define SUBU_ERR_ARG_CNT 1 diff --git a/src-0/1_tmp/subu-bind.cli.h b/src-0/1_tmp/subu-bind.cli.h deleted file mode 100644 index af12d61..0000000 --- a/src-0/1_tmp/subu-bind.cli.h +++ /dev/null @@ -1,7 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -#include -#include -int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome); -#define SUBU_ERR_ARG_CNT 1 diff --git a/src-0/1_tmp/subu-common.lib.h b/src-0/1_tmp/subu-common.lib.h deleted file mode 100644 index cfdc520..0000000 --- a/src-0/1_tmp/subu-common.lib.h +++ /dev/null @@ -1,9 +0,0 @@ -/* This 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 diff --git a/src-0/1_tmp/subu-mk-0.cli.h b/src-0/1_tmp/subu-mk-0.cli.h deleted file mode 100644 index 487b509..0000000 --- a/src-0/1_tmp/subu-mk-0.cli.h +++ /dev/null @@ -1,10 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -#include -#include -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 diff --git a/src-0/1_tmp/subu-rm-0.cli.h b/src-0/1_tmp/subu-rm-0.cli.h deleted file mode 100644 index 070bfe8..0000000 --- a/src-0/1_tmp/subu-rm-0.cli.h +++ /dev/null @@ -1,10 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -#include -#include -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 diff --git a/src-0/1_tmp/subu.lib.h b/src-0/1_tmp/subu.lib.h deleted file mode 100644 index 69c5da7..0000000 --- a/src-0/1_tmp/subu.lib.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -typedef unsigned int uint; -#include -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 -#include -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 -#include -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 -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 diff --git a/src-0/1_tmp/subudb-init.cli.h b/src-0/1_tmp/subudb-init.cli.h deleted file mode 100644 index 4435103..0000000 --- a/src-0/1_tmp/subudb-init.cli.h +++ /dev/null @@ -1,11 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -int db_commit(sqlite3 *db); -int db_rollback(sqlite3 *db); -int subudb_schema(sqlite3 *db); -int db_begin(sqlite3 *db); -#include -#include -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; diff --git a/src-0/1_tmp/subudb-number.cli.h b/src-0/1_tmp/subudb-number.cli.h deleted file mode 100644 index c130fbb..0000000 --- a/src-0/1_tmp/subudb-number.cli.h +++ /dev/null @@ -1,11 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -int subudb_number_get(sqlite3 *db,int *n); -int subudb_number_set(sqlite3 *db,int n); -#include -#include -#define SUBU_ERR_N 14 -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; -#define SUBU_ERR_ARG_CNT 1 diff --git a/src-0/1_tmp/subudb-rel-get.cli.h b/src-0/1_tmp/subudb-rel-get.cli.h deleted file mode 100644 index 4f335be..0000000 --- a/src-0/1_tmp/subudb-rel-get.cli.h +++ /dev/null @@ -1,9 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username); -#include -#include -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; -#define SUBU_ERR_ARG_CNT 1 diff --git a/src-0/1_tmp/subudb-rel-put.cli.h b/src-0/1_tmp/subudb-rel-put.cli.h deleted file mode 100644 index 243b3a9..0000000 --- a/src-0/1_tmp/subudb-rel-put.cli.h +++ /dev/null @@ -1,8 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); -#include -#include -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; diff --git a/src-0/1_tmp/subudb-rel-rm.cli.h b/src-0/1_tmp/subudb-rel-rm.cli.h deleted file mode 100644 index 595427f..0000000 --- a/src-0/1_tmp/subudb-rel-rm.cli.h +++ /dev/null @@ -1,8 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); -#include -#include -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; diff --git a/src-0/1_tmp/subudb-subus.cli.h b/src-0/1_tmp/subudb-subus.cli.h deleted file mode 100644 index 16310b7..0000000 --- a/src-0/1_tmp/subudb-subus.cli.h +++ /dev/null @@ -1,14 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -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 -#include -#define SUBU_ERR_DB_FILE 8 -extern char DB_File[]; -#define SUBU_ERR_ARG_CNT 1 diff --git a/src-0/1_tmp/subudb.lib.h b/src-0/1_tmp/subudb.lib.h deleted file mode 100644 index be73823..0000000 --- a/src-0/1_tmp/subudb.lib.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This file was automatically generated. Do not edit! */ -#undef INTERFACE -#include -int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); -#include -#include -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 diff --git a/src-0/1_try/split.c b/src-0/1_try/split.c deleted file mode 100644 index 6d4c6ac..0000000 --- a/src-0/1_try/split.c +++ /dev/null @@ -1,20 +0,0 @@ -/* -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 diff --git a/src-0/1_try/split_arg.c b/src-0/1_try/split_arg.c deleted file mode 100644 index 6d4c6ac..0000000 --- a/src-0/1_try/split_arg.c +++ /dev/null @@ -1,20 +0,0 @@ -/* -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 diff --git a/src-0/1_try/subudb b/src-0/1_try/subudb deleted file mode 100644 index e69de29..0000000 diff --git a/src-0/1_try/voidptr.c b/src-0/1_try/voidptr.c deleted file mode 100644 index bd9c3e5..0000000 --- a/src-0/1_try/voidptr.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -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 - -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; -} diff --git a/src-0/common.lib.c b/src-0/common.lib.c deleted file mode 100644 index 9ce5a27..0000000 --- a/src-0/common.lib.c +++ /dev/null @@ -1,20 +0,0 @@ - -#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/"; diff --git a/src-0/db.lib.c b/src-0/db.lib.c deleted file mode 100644 index 17a5419..0000000 --- a/src-0/db.lib.c +++ /dev/null @@ -1,192 +0,0 @@ -/* -The db file is maintained in SQLite - -Because user names of are of limited length, subu user names are always named _s. -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 -#endif - -#include -#include -#include -#include - -//-------------------------------------------------------------------------------- -// 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; -} diff --git a/src-0/subu-bind-all.cli.c b/src-0/subu-bind-all.cli.c deleted file mode 100644 index e942909..0000000 --- a/src-0/subu-bind-all.cli.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -mount all the subu user directories into master's subuland -uses unmount to undo this - -*/ -#include "subu-bind-all.cli.h" -#include -#include - -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; -} diff --git a/src-0/subu-bind.cli.c b/src-0/subu-bind.cli.c deleted file mode 100644 index f315823..0000000 --- a/src-0/subu-bind.cli.c +++ /dev/null @@ -1,25 +0,0 @@ -/* -mount a subu user directory into master's subuland -uses unmount to undo this - -*/ -#include "subu-bind.cli.h" -#include -#include - -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; -} diff --git a/src-0/subu-mk-0.cli.c b/src-0/subu-mk-0.cli.c deleted file mode 100644 index af0888b..0000000 --- a/src-0/subu-mk-0.cli.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - subu-mk-0 command - -*/ -#include "subu-mk-0.cli.h" -#include -#include - -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; - -} diff --git a/src-0/subu-rm-0.cli.c b/src-0/subu-rm-0.cli.c deleted file mode 100644 index a7e5926..0000000 --- a/src-0/subu-rm-0.cli.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - subu-mk-0 command - -*/ -#include "subu-rm-0.cli.h" -#include -#include - -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; - } -} diff --git a/src-0/subu.lib.c b/src-0/subu.lib.c deleted file mode 100644 index 988bd28..0000000 --- a/src-0/subu.lib.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - 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, calls useradd to creat - the new uswer account, and enters the relationship between masteru, subu, and - s in the db file. It is this relation in the db file that - associates the subuname with the s user. - - subu-rm-0 uses userdel to delete the related s 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 -#include -#include -#include -#include -#include -#include -#include - -#if INTERFACE -#include -#include -#include -#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); -} diff --git a/src-0/subudb-init.cli.c b/src-0/subudb-init.cli.c deleted file mode 100644 index 714c7e4..0000000 --- a/src-0/subudb-init.cli.c +++ /dev/null @@ -1,26 +0,0 @@ -/* -This command initializes the db file. - -*/ -#include "subudb-init.cli.h" -#include - -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; -} diff --git a/src-0/subudb-number.cli.c b/src-0/subudb-number.cli.c deleted file mode 100644 index 60304e3..0000000 --- a/src-0/subudb-number.cli.c +++ /dev/null @@ -1,63 +0,0 @@ -/* -Set or get a new maximum subu number. Currently doesn't do the setting part. - -*/ -#include "subudb-number.cli.h" -#include -#include -#include - -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; - -} diff --git a/src-0/subudb-rel-get.cli.c b/src-0/subudb-rel-get.cli.c deleted file mode 100644 index 9828b15..0000000 --- a/src-0/subudb-rel-get.cli.c +++ /dev/null @@ -1,42 +0,0 @@ -/* -get the username from the db file -for testing subudb_Masteru_Subu_get_subu_username - -*/ -#include "subudb-rel-get.cli.h" -#include -#include - -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; -} diff --git a/src-0/subudb-rel-put.cli.c b/src-0/subudb-rel-put.cli.c deleted file mode 100644 index b19896e..0000000 --- a/src-0/subudb-rel-put.cli.c +++ /dev/null @@ -1,40 +0,0 @@ -/* -puts a relation in the masteru/subu table - -*/ -#include "subudb-rel-put.cli.h" -#include -#include - -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; -} diff --git a/src-0/subudb-rel-rm.cli.c b/src-0/subudb-rel-rm.cli.c deleted file mode 100644 index 3d15ca9..0000000 --- a/src-0/subudb-rel-rm.cli.c +++ /dev/null @@ -1,41 +0,0 @@ -/* -puts a relation in the masteru/subu table - -*/ -#include "subudb-rel-rm.cli.h" -#include -#include - -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; -} diff --git a/src-0/subudb-subus.cli.c b/src-0/subudb-subus.cli.c deleted file mode 100644 index be3af20..0000000 --- a/src-0/subudb-subus.cli.c +++ /dev/null @@ -1,47 +0,0 @@ -/* -Set or get a new maximum subu number. Currently doesn't do the setting part. - -*/ -#include "subudb-subus.cli.h" -#include -#include -#include - -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; - -} diff --git a/src-da/0_makefile b/src-da/0_makefile deleted file mode 100644 index 9835402..0000000 --- a/src-da/0_makefile +++ /dev/null @@ -1,18 +0,0 @@ -# src-da/0_makefile - -SHELL=/bin/bash - --include 0_makefile-flags - -all: version deps lib execs - -lib: - $(MAKE) $@ - cp da.lib.h 1_include/da.h - -%:: - $(MAKE) $@ - - - - diff --git a/src-da/0_makefile-flags b/src-da/0_makefile-flags deleted file mode 100644 index 6860d2f..0000000 --- a/src-da/0_makefile-flags +++ /dev/null @@ -1,37 +0,0 @@ - -# 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 -INCDIR=1_include -LIBDIR=1_lib -TESTDIR=1_tests -TMPDIR=1_tmp -TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) -TRYDIR=1_try - -# compiler and flags -C=gcc -CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB -#CFLAGS=-std=gnu11 -fPIC -I. -Werror -LINKFLAGS=-L1_lib -lda - -CC= - -LIBFILE=libda.a -INCFILE=da.h - -MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc -#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc - - diff --git a/src-da/1_include/da.h b/src-da/1_include/da.h deleted file mode 100644 index 6d3c43b..0000000 --- a/src-da/1_include/da.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef DA_LIB_H -#define DA_LIB_H -#include -#include -#include - -typedef struct Da{ - char *base; - char *end; // one byte/one element off the end of the array - size_t size; // size >= (end - base) + 1; - size_t element_size; -} Da; - -#define RETURN(dap, r) \ - { da_map(dap, da_free, NULL); return r; } - -void da_alloc(Da *dap, size_t element_size); -void da_free(Da *dap); -void da_rewind(Da *dap); -char *da_expand(Da *dap); -void da_rebase(Da *dap, char *old_base, void *pta); -bool da_endq(Da *dap, void *pt); -bool da_boundq(Da *dap); -void da_push(Da *dap, void *element); -bool da_pop(Da *dap, void *element); -char *da_index(Da *dap, size_t i); -void da_map(Da *dap, void f(void *, void *), void *closure); -void da_free_elements(Da *dap); -void da_strings_puts(Da *dap); -char *da_fgets(Da *dap, FILE *fd); - -#endif - diff --git a/src-da/1_tests/0_makefile b/src-da/1_tests/0_makefile deleted file mode 100644 index 8b6f67c..0000000 --- a/src-da/1_tests/0_makefile +++ /dev/null @@ -1,14 +0,0 @@ -# src-da/1_tests/0_makefile - -SHELL=/bin/bash - --include 0_makefile-flags - -all: version deps lib execs - -%:: - $(MAKE) $@ - - - - diff --git a/src-da/1_tests/0_makefile-flags b/src-da/1_tests/0_makefile-flags deleted file mode 100644 index 50cc00a..0000000 --- a/src-da/1_tests/0_makefile-flags +++ /dev/null @@ -1,33 +0,0 @@ - -# 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=. -INCDIR=. -LIBDIR=. -TESTDIR=. -TMPDIR=1_tmp -TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) -TRYDIR= - - -# compiler and flags -C=gcc -CFLAGS=-std=gnu11 -fPIC -I. -I../1_include -ggdb -Werror -DDEBUG -DDEBUGDB -#CFLAGS=-std=gnu11 -fPIC -I. -I../1_include -Werror -LINKFLAGS=-L. -L../1_lib -ltests -lda - -LIBFILE=libtests.a - -MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc -#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc diff --git a/src-da/1_tests/results b/src-da/1_tests/results deleted file mode 100644 index 9e59b33..0000000 --- a/src-da/1_tests/results +++ /dev/null @@ -1 +0,0 @@ -passed all 4 tests diff --git a/src-da/1_tests/test.dat b/src-da/1_tests/test.dat deleted file mode 100644 index 6b4b5bd..0000000 --- a/src-da/1_tests/test.dat +++ /dev/null @@ -1,3 +0,0 @@ -this is a test -ends without a newline -(setq mode-require-final-newline nil) \ No newline at end of file diff --git a/src-da/1_tests/test_da.cli.c b/src-da/1_tests/test_da.cli.c deleted file mode 100644 index bee5a6c..0000000 --- a/src-da/1_tests/test_da.cli.c +++ /dev/null @@ -1,46 +0,0 @@ - -#include -#include -#include "test_da.lib.h" - -int main(){ - bool da_0_passed = test_da_0(); - - unsigned int passed = 0; - unsigned int failed = 0; - - // enumeration of tests - typedef bool (*test_fun)(); - test_fun tests[] = {test_da_0, test_da_1, test_da_2, test_da_3, NULL}; - char *test_names[] = {"test_da_0", "test_da_1", "test_da_2", "test_da_3", NULL}; - - // call tests - test_fun *tfp = tests; - char **tnp = test_names; - while(*tfp){ - if( !(*tfp)() ){ - failed++; - if(*tnp) - printf("%s failed\n", *tnp); - else - fprintf(stderr, "internal error, no test_names[] entry for test\n"); - }else - passed++; - tfp++; - tnp++; - } - - // summarize results - - if( passed == 0 && failed == 0) - printf("no tests ran\n"); - else if( passed == 0 ) - printf("failed all %u tests\n", failed); - else if( failed == 0 ) - printf("passed all %u tests\n", passed); - else - printf("failed %u of %u tests\n", failed, passed + failed); - - if( passed == 0 || failed != 0 ) return 1; - return 0; -} diff --git a/src-da/1_tests/test_da.lib.c b/src-da/1_tests/test_da.lib.c deleted file mode 100644 index 88a94c7..0000000 --- a/src-da/1_tests/test_da.lib.c +++ /dev/null @@ -1,130 +0,0 @@ -/* -Tests for Da. - -*/ - -#include -#include -#include -#include - -#include "test_da.lib.h" - -// tests push -bool test_da_0(){ - Da da; - da_alloc(&da, sizeof(int)); // leaves room for 4 ints - int i = 0; - int *pt = (int *)da.base; - // will double, 4 -> 8, then double 8 -> 16 - while( i < 10 ){ - da_push(&da, &i); - i++; - pt++; - } - - bool f0 = da.size == sizeof(int) * 16; - bool f1 = 10 == (da.end - da.base) / sizeof(int); - bool f2 = true; - pt = (int *)da.base; - i = 0; - while( i < 10 ){ - f2 = f2 && *pt == i && !da_endq(&da, pt); - i++; - pt++; - } - bool f3 = da_endq(&da, pt); - - return f0 && f1 && f2 && f3; -} - -// tests manual expansion -bool test_da_1(){ - Da da; - da_alloc(&da, sizeof(int)); // leaves room for 4 ints - int i = 0; - int *pt = (int *)da.base; - // will double, 4 -> 8, then double 8 -> 16 - while( i < 10 ){ - da.end += da.element_size; - if( da_boundq(&da) ){ - char *old_base = da_expand(&da); - da_rebase(&da, old_base, &pt); - } - *pt = i; - i++; - pt++; - } - - bool f0 = da.size == sizeof(int) * 16; - bool f1 = 10 == (da.end - da.base) / sizeof(int); - bool f2 = true; - pt = (int *)da.base; - i = 0; - while( i < 10 ){ - f2 = f2 && *pt == i && !da_endq(&da, pt); - i++; - pt++; - } - bool f3 = da_endq(&da, pt); - - return f0 && f1 && f2 && f3; -} - -// da_fgets -bool test_da_2(){ - - FILE *fd = fopen("test.dat","r"); - - Da da; - da_alloc(&da, sizeof(char)); - - da_fgets(&da, fd); - bool f0 = !strcmp(da.base, "this is a test"); - - char *old_base; - da_pop(&da, NULL); // pop the prior null terminator - char *s1 = da.end; - old_base = da_fgets(&da,fd); - da_rebase(&da, old_base, &s1); - bool f1 = !strcmp(s1, "ends without a newline"); - - da_pop(&da, NULL); // pop the prior null terminator - char *s2 = da.end; - old_base = da_fgets(&da,fd); - da_rebase(&da, old_base, &s2); - bool f2 = !strcmp(s2, "(setq mode-require-final-newline nil)"); - - bool f3 = !strcmp(da.base, "this is a testends without a newline(setq mode-require-final-newline nil)"); - - fclose(fd); - return f0 && f1 && f2 && f3; -} - -// da_fgets -bool test_da_3(){ - - FILE *fd = fopen("test.dat","r"); - - Da da; - da_alloc(&da, sizeof(int)); - - int i = 5; - da_push(&da, &i); - i++; - da_push(&da, &i); - i++; - da_push(&da, &i); - - int j; - bool f0 = da_pop(&da, &j) && j == 7; - bool f1 = da_pop(&da, &j) && j == 6; - bool f2 = da_pop(&da, NULL); - bool f3 = !da_pop(&da, &j); - - return f0 && f1 && f2 && f3; -} - - - - diff --git a/src-da/1_tests/test_da.lib.h b/src-da/1_tests/test_da.lib.h deleted file mode 100644 index 686b0d0..0000000 --- a/src-da/1_tests/test_da.lib.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef DA_LIB_H -#define DA_LIB_H - -bool test_da_0(); -bool test_da_1(); -bool test_da_2(); -bool test_da_3(); - -#endif diff --git a/src-da/da.lib.c b/src-da/da.lib.c deleted file mode 100644 index 0956d7e..0000000 --- a/src-da/da.lib.c +++ /dev/null @@ -1,132 +0,0 @@ -/* -Dynamic Array - -*/ - -#include "da.lib.h" - -#include -#include -#include - -//-------------------------------------------------------------------------------- -// 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. - -void da_alloc(Da *dap, size_t element_size){ - dap->element_size = element_size; - dap->size = 4 * element_size; - dap->base = malloc(dap->size); - dap->end = dap->base; -} -void da_free(Da *dap){ - free(dap->base); - dap->size = 0; -} -void da_rewind(Da *dap){ - dap->end = dap->base; -} - -bool da_empty(Da *dap){ - return dap->end == dap->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; -} - -// 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){ - char *old_base = dap->base; - size_t end_offset = dap->end - old_base; - size_t new_size = dap->size << 1; - char *new_base = malloc( new_size ); - memcpy( new_base, old_base, end_offset + dap->element_size); - free(old_base); - dap->base = new_base; - dap->end = new_base + end_offset; - dap->size = new_size; - return old_base; -} - -// 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){ - return dap->end >= dap->base + dap->size; -} - -void da_push(Da *dap, void *element){ - if( dap->end >= dap->base + dap->size ) da_expand(dap); - memcpy(dap->end, element, dap->element_size); - dap->end += dap->element_size; -} - -bool da_pop(Da *dap, void *element){ - bool flag = dap->end >= dap->base + dap->element_size; - if( flag ){ - dap->end -= dap->element_size; - if(element) memcpy(element, dap->end, dap->element_size); - } - return flag; -} - -char *da_index(Da *dap, size_t i){ - size_t offset = i * dap->element_size; - char *pt = dap->base + offset; - return pt; -} - -// passed in f(element_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->element_size; - } -} - -// da_lists are sometimes used as resource managers -static void da_free_element(void *pt, void *closure){ - free(*(char **)pt); // free does not care about the pointer type -} - -void da_free_elements(Da *dap){ - da_map(dap, da_free_element, NULL); - da_rewind(dap); -} - -// for the case of an array of strings -void da_strings_puts(Da *dap){ - char *pt = dap->base; - while( pt != dap->end ){ - puts(*(char **)pt); - pt += dap->element_size; - } -} - - -// Puts text from a line into buffer *dap. Does not push EOF or '\n' into the -// buffer. Returns the old_base so that external pointers can be rebased. -// It is possible that the the base hasn't changed. Use feof(FILE *stream) to -// test for EOF; -char *da_fgets(Da *dap, FILE *file){ - char *old_base = dap->base; - int c = fgetc(file); - while( c != EOF && c != '\n' ){ - da_push(dap, &c); - c = fgetc(file); - } - int terminator = 0; - da_push(dap, &terminator); - return old_base; -} diff --git a/src-da/da.lib.h b/src-da/da.lib.h deleted file mode 100644 index 6d3c43b..0000000 --- a/src-da/da.lib.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef DA_LIB_H -#define DA_LIB_H -#include -#include -#include - -typedef struct Da{ - char *base; - char *end; // one byte/one element off the end of the array - size_t size; // size >= (end - base) + 1; - size_t element_size; -} Da; - -#define RETURN(dap, r) \ - { da_map(dap, da_free, NULL); return r; } - -void da_alloc(Da *dap, size_t element_size); -void da_free(Da *dap); -void da_rewind(Da *dap); -char *da_expand(Da *dap); -void da_rebase(Da *dap, char *old_base, void *pta); -bool da_endq(Da *dap, void *pt); -bool da_boundq(Da *dap); -void da_push(Da *dap, void *element); -bool da_pop(Da *dap, void *element); -char *da_index(Da *dap, size_t i); -void da_map(Da *dap, void f(void *, void *), void *closure); -void da_free_elements(Da *dap); -void da_strings_puts(Da *dap); -char *da_fgets(Da *dap, FILE *fd); - -#endif - diff --git a/src-db/0_makefile b/src-db/0_makefile deleted file mode 100644 index b8c7b9d..0000000 --- a/src-db/0_makefile +++ /dev/null @@ -1,40 +0,0 @@ -# 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) $@ - - - - diff --git a/src-db/0_makefile-flags b/src-db/0_makefile-flags deleted file mode 100644 index 0da8b61..0000000 --- a/src-db/0_makefile-flags +++ /dev/null @@ -1,31 +0,0 @@ - -# 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 - -LIBFILE=$(LIBDIR)/libsubu.a - diff --git a/src-db/1_doc/return-from-transaction.txt b/src-db/1_doc/return-from-transaction.txt deleted file mode 100644 index b7f8cbb..0000000 --- a/src-db/1_doc/return-from-transaction.txt +++ /dev/null @@ -1,15 +0,0 @@ - -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. diff --git a/src-db/dbprintf.lib.c b/src-db/dbprintf.lib.c deleted file mode 100644 index d9d236b..0000000 --- a/src-db/dbprintf.lib.c +++ /dev/null @@ -1,14 +0,0 @@ - -#include "dbprintf.lib.h" - -#include -#include - -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; -} diff --git a/src-dispatch/0_makefile b/src-dispatch/0_makefile deleted file mode 100644 index 9835402..0000000 --- a/src-dispatch/0_makefile +++ /dev/null @@ -1,18 +0,0 @@ -# src-da/0_makefile - -SHELL=/bin/bash - --include 0_makefile-flags - -all: version deps lib execs - -lib: - $(MAKE) $@ - cp da.lib.h 1_include/da.h - -%:: - $(MAKE) $@ - - - - diff --git a/src-dispatch/0_makefile-flags b/src-dispatch/0_makefile-flags deleted file mode 100644 index 6641e4a..0000000 --- a/src-dispatch/0_makefile-flags +++ /dev/null @@ -1,35 +0,0 @@ - -# 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 -INCDIR=1_include -LIBDIR=1_lib -TESTDIR=1_tests -TMPDIR=1_tmp -TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) -TRYDIR=1_try - -# compiler and flags -C=gcc -CFLAGS=-std=gnu11 -fPIC -I. -ggdb -Werror -DDEBUG -DDEBUGDB -#CFLAGS=-std=gnu11 -fPIC -I. -Werror - -LINKFLAGS=-L1_lib -lda - -LIBFILE=libdispatch.a -INCFILE=dispatch.h - -MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc -#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc - diff --git a/src-dispatch/dispatch.src.c b/src-dispatch/dispatch.src.c deleted file mode 100644 index 632ae51..0000000 --- a/src-dispatch/dispatch.src.c +++ /dev/null @@ -1,166 +0,0 @@ -#tranche dispatch.lib.cc - -#tranche dispatch.lib.h -/* - Runs a command or function as its own process. - - The return status integer 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. - -*/ -#ifndef DISPATCH_LIB_H -#define DISPATCH_LIB_H -#include -#include - -#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 - -// 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 -}; -#tranche-end - -#include "dispatch.lib.h" - -// we need the declaration for uid_t etc. -// without this #define execvpe is undefined -#define _GNU_SOURCE - -#include -#include -#include -#include - -#tranche dispatch.lib.h -void dispatch_f_mess(char *fname, int err, char *dispatchee); -#tranche-end -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 -#tranche dispatch.lib.h -int dispatch_f(char *fname, int (*f)(void *arg), void *f_arg); -#tranche-end -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 -#tranche dispatch.lib.h -int dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid); -#tranche-end -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 -#tranche dispatch.lib.h -int dispatch_exec(char **argv, char **envp); -#tranche-end -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; - } -} - -#tranche-end diff --git a/src-py/subu-mk.py b/src-py/subu-mk.py deleted file mode 100644 index 203fab4..0000000 --- a/src-py/subu-mk.py +++ /dev/null @@ -1,299 +0,0 @@ -#!/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=][owner=] [subu=] -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) diff --git a/src-tranche/0_makefile b/src-tranche/0_makefile deleted file mode 100644 index 107d319..0000000 --- a/src-tranche/0_makefile +++ /dev/null @@ -1,18 +0,0 @@ -# src-da/0_makefile - -SHELL=/bin/bash - --include 0_makefile-flags - -all: version deps lib execs - -lib: - $(MAKE) $@ - cp tranche.lib.h 1_include/tranche.h - -%:: - $(MAKE) $@ - - - - diff --git a/src-tranche/0_makefile-flags b/src-tranche/0_makefile-flags deleted file mode 100644 index e37767f..0000000 --- a/src-tranche/0_makefile-flags +++ /dev/null @@ -1,45 +0,0 @@ - -# 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 -INCDIR=1_include -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. -I$(PROJECT_SUBU)/stage/include -ggdb -Werror -DDEBUG -DDEBUGDB -#CFLAGS=-std=gnu11 -fPIC -I. -Werror -LINKFLAGS=-L1_lib -L$(PROJECT_SUBU)/stage/lib -lda -ltranche - -LIBFILE=libtranche.a -INCFILE=tranche.h - -MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc - -# files used by the compiler -SOURCES_LIB= $(wildcard *.lib.c) -SOURCES_CLI= $(wildcard *.cli.c) -SOURCES= $(SOURCES_LIB) $(SOURCES_CLI) - -HFILES = $(wildcard *.lib.h) $(wildcard *.cli.h) - -OBJECTS_LIB= $(patsubst %.c, %.o, $(SOURCES_LIB)) -OBJECTS_CLI= $(patsubst %.c, %.o, $(SOURCES_CLI)) -OBJECTS= $(OBJECTS_LIB) $(OBJECTS_CLI) - -EXECS= $(sort $(patsubst %.cli.c, %, $(wildcard *.cli.c))) diff --git a/src-tranche/1_deprecated/0_makefile b/src-tranche/1_deprecated/0_makefile deleted file mode 100644 index b8c7b9d..0000000 --- a/src-tranche/1_deprecated/0_makefile +++ /dev/null @@ -1,40 +0,0 @@ -# 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) $@ - - - - diff --git a/src-tranche/1_deprecated/0_makefile-flags b/src-tranche/1_deprecated/0_makefile-flags deleted file mode 100644 index 0da8b61..0000000 --- a/src-tranche/1_deprecated/0_makefile-flags +++ /dev/null @@ -1,31 +0,0 @@ - -# 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 - -LIBFILE=$(LIBDIR)/libsubu.a - diff --git a/src-tranche/1_doc/todo.txt b/src-tranche/1_doc/todo.txt deleted file mode 100644 index 1494e66..0000000 --- a/src-tranche/1_doc/todo.txt +++ /dev/null @@ -1,11 +0,0 @@ - -2019-03-22T13:37:23Z -1. indentation - - the first non blank line after the #tranche keyword sets the indentation - level for the following text. When echoing to the output file - remove that many leading spaces. - - Hmm, or allow options among the tranche parameters, -indent 3 or - -indent ' '. - diff --git a/src-tranche/1_include/tranche.h b/src-tranche/1_include/tranche.h deleted file mode 100644 index 27990a6..0000000 --- a/src-tranche/1_include/tranche.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef TRANCHE_LIB_H -#define TRANCHE_LIB_H - -int tranche_send(FILE *src, Da *arg_fds); - - - -#endif diff --git a/src-tranche/1_tests/0_makefile b/src-tranche/1_tests/0_makefile deleted file mode 100644 index 8b6f67c..0000000 --- a/src-tranche/1_tests/0_makefile +++ /dev/null @@ -1,14 +0,0 @@ -# src-da/1_tests/0_makefile - -SHELL=/bin/bash - --include 0_makefile-flags - -all: version deps lib execs - -%:: - $(MAKE) $@ - - - - diff --git a/src-tranche/1_tests/0_makefile-flags b/src-tranche/1_tests/0_makefile-flags deleted file mode 100644 index c990581..0000000 --- a/src-tranche/1_tests/0_makefile-flags +++ /dev/null @@ -1,33 +0,0 @@ - -# 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=. -INCDIR=. -LIBDIR=. -TESTDIR=. -TMPDIR=1_tmp -TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) -TRYDIR= - - -# compiler and flags -CC=gcc -CFLAGS=-std=gnu11 -fPIC -I. -I../1_include -ggdb -Werror -DDEBUG -DDEBUGDB -#CFLAGS=-std=gnu11 -fPIC -I. -I../1_include -Werror -LINKFLAGS=-L. -L../1_lib -ltests -lda - -LIBFILE=libtranche.a -MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc - - diff --git a/src-tranche/1_tests/test1.dat b/src-tranche/1_tests/test1.dat deleted file mode 100644 index b03df3f..0000000 --- a/src-tranche/1_tests/test1.dat +++ /dev/null @@ -1,23 +0,0 @@ - -#tranche test11.dat test12.dat -The little red hen said to Mick, no thank you not today sir. -And then all the barnes animals shouted out in glee. -No more misery! -#tranche test13.dat -apple banana pear -kiwi -#tranche-end -cows -and cats -#tranche-end - -the between space - -#tranche test14.dat -int float if while -do -function -#tranche-end - -#tranche test15.dat -#tranche-end \ No newline at end of file diff --git a/src-tranche/1_tests/test1.sh b/src-tranche/1_tests/test1.sh deleted file mode 100644 index c1140ca..0000000 --- a/src-tranche/1_tests/test1.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -x -./tranche test1.dat >test1stdout.dat -diff test11.dat test11.dat.expected -diff test12.dat test12.dat.expected -diff test13.dat test13.dat.expected -diff test14.dat test14.dat.expected -diff test15.dat test15.dat.expected -diff test1stdout.dat test1stdout.dat.expected -rm test11.dat test12.dat test13.dat test14.dat test15.dat test1stdout.dat - diff --git a/src-tranche/1_tests/test11.dat.expected b/src-tranche/1_tests/test11.dat.expected deleted file mode 100644 index 2c2904a..0000000 --- a/src-tranche/1_tests/test11.dat.expected +++ /dev/null @@ -1,5 +0,0 @@ -The little red hen said to Mick, no thank you not today sir. -And then all the barnes animals shouted out in glee. -No more misery! -cows -and cats diff --git a/src-tranche/1_tests/test12.dat.expected b/src-tranche/1_tests/test12.dat.expected deleted file mode 100644 index 2c2904a..0000000 --- a/src-tranche/1_tests/test12.dat.expected +++ /dev/null @@ -1,5 +0,0 @@ -The little red hen said to Mick, no thank you not today sir. -And then all the barnes animals shouted out in glee. -No more misery! -cows -and cats diff --git a/src-tranche/1_tests/test13.dat.expected b/src-tranche/1_tests/test13.dat.expected deleted file mode 100644 index 81fb20c..0000000 --- a/src-tranche/1_tests/test13.dat.expected +++ /dev/null @@ -1,2 +0,0 @@ -apple banana pear -kiwi diff --git a/src-tranche/1_tests/test14.dat.expected b/src-tranche/1_tests/test14.dat.expected deleted file mode 100644 index 0d8b89b..0000000 --- a/src-tranche/1_tests/test14.dat.expected +++ /dev/null @@ -1,3 +0,0 @@ -int float if while -do -function diff --git a/src-tranche/1_tests/test15.dat.expected b/src-tranche/1_tests/test15.dat.expected deleted file mode 100644 index e69de29..0000000 diff --git a/src-tranche/1_tests/test1stdout.dat.expected b/src-tranche/1_tests/test1stdout.dat.expected deleted file mode 100644 index 4e519ff..0000000 --- a/src-tranche/1_tests/test1stdout.dat.expected +++ /dev/null @@ -1,5 +0,0 @@ - - -the between space - - diff --git a/src-tranche/1_tests/tranche b/src-tranche/1_tests/tranche deleted file mode 120000 index acf4a6f..0000000 --- a/src-tranche/1_tests/tranche +++ /dev/null @@ -1 +0,0 @@ -../1_execs/tranche \ No newline at end of file diff --git a/src-tranche/tranche.cli.c b/src-tranche/tranche.cli.c deleted file mode 100644 index 8df4337..0000000 --- a/src-tranche/tranche.cli.c +++ /dev/null @@ -1,25 +0,0 @@ - -#include -#include -#include -#include "tranche.lib.h" - -int main(int argc, char **argv, char **envp){ - if(argc != 2){ - fprintf(stderr, "usage: %s \n",argv[0]); - return 1; - } - FILE *file = fopen(argv[1], "r"); - if(!file){ - fprintf(stderr,"could not open file %s\n", argv[1]); - return 2; - } - Da targets; - da_alloc(&targets, sizeof(int)); - int fd = STDOUT_FILENO; - da_push(&targets, &fd); - tranche_send(file, &targets); - da_free(&targets); - fclose(file); - return 0; -} diff --git a/src-tranche/tranche.lib.c b/src-tranche/tranche.lib.c deleted file mode 100644 index 4679dbe..0000000 --- a/src-tranche/tranche.lib.c +++ /dev/null @@ -1,143 +0,0 @@ -/* -The purpose of this tools is to facilitate putting prototypes (declarations) next -to implementations (definitions) in a single source file of a C/C++ programs. - -Splits a single source file into multiple files. Scans through the single -source file looking for lines of the form: - - #tranche filename ... - -With the # as the first non-space character on the line, and only filename -following the tag. Upon finding such a line, copies all following lines into the -listed files, until reaching the end marker: - - #endtranche - -A next improvement of this file would be to support variables to be passed in -for the file names. As it stands, changing the file name requires editing -the source file. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -//-------------------------------------------------------------------------------- -// parsing - -char newline = '\n'; -char terminator = 0; - -char tranche_begin_tag[] = "#tranche"; -size_t tranche_begin_tag_len = 8; - -char tranche_end_tag[] = "#tranche-end"; -size_t tranche_end_tag_len = 12; - -// given a line -// returns beginning of file name list -static char *is_tranche_begin(char *pt){ - while( *pt && isspace(*pt) ) pt++; - if(!*pt) return NULL; - if( strncmp(pt, tranche_begin_tag, tranche_begin_tag_len) ) return NULL; - return pt + tranche_begin_tag_len; -} - -static char *is_tranche_end(char *pt){ - while( *pt && isspace(*pt) ) pt++; - if(!*pt) return NULL; - if( strncmp(pt, tranche_end_tag, tranche_end_tag_len) ) return NULL; - return pt + tranche_end_tag_len; -} - -static bool parse_file_list(Da *file_names, char *pt0){ - char *pt1; - while( *pt0 && isspace(*pt0) ) pt0++; - pt1 = pt0; - while( *pt0 ){ - while( *pt1 && !isspace(*pt1) ) pt1++; - char *file_name = strndup(pt0, pt1 - pt0); - da_push(file_names, &file_name); - while( *pt1 && isspace(*pt1) ) pt1++; - pt0 = pt1; - } -} - - - -//-------------------------------------------------------------------------------- -// da_map calls - -static void tranche_open_fd(void *fnp, void *closure){ - char *file_name = *(char **)fnp; - Da *fdap = (Da *)closure; - int fd = open(file_name, O_CREAT | O_TRUNC | O_WRONLY, 0666); - if(fd == -1){ - fprintf(stderr, "Could not open file %s\n", file_name); - return; - } - da_push(fdap, &fd); - return; -} -static void tranche_open_fds(Da *fnap, Da *fdap){ - da_map(fnap, tranche_open_fd, fdap); -} - -static void tranche_close_fd(void *fdp, void *closure){ - close(*(int *)fdp); -} -static void tranche_close_fds(Da *fdap){ - da_map(fdap, tranche_close_fd, NULL); - da_rewind(fdap); -} - -static void tranche_puts(void *fdp, void *string){ - write(*(int *)fdp, string, strlen(string)); -} -static void tranche_puts_all(Da *fdap, char *string){ - da_map(fdap, tranche_puts, string); -} - - - -//-------------------------------------------------------------------------------- -// we have a little problem if the user tries to tranche two things to the same file .. -int tranche_send(FILE *src, Da *arg_fdap){ - char *pt; - Da line; - Da file_name_arr; - Da fda; - da_alloc(&line, sizeof(char)); - da_alloc(&file_name_arr, sizeof(char *)); - da_alloc(&fda, sizeof(int)); - - while( !feof(src) ){ - da_fgets(&line, src); - if( is_tranche_end(line.base) ) break; - pt = is_tranche_begin(line.base); - if(pt){ // then this line is the start of a nested tranche block - parse_file_list(&file_name_arr, pt); - tranche_open_fds(&file_name_arr, &fda); - da_free_elements(&file_name_arr); - tranche_send(src, &fda); - tranche_close_fds(&fda); - }else{ - da_pop(&line, NULL); // pop the terminating zero - da_push(&line, &newline); - da_push(&line, &terminator); - tranche_puts_all(arg_fdap, line.base); - } - da_rewind(&line); - } - - da_free(&line); - da_free(&file_name_arr); - da_free(&fda); - return 0; -} diff --git a/src-tranche/tranche.lib.h b/src-tranche/tranche.lib.h deleted file mode 100644 index 27990a6..0000000 --- a/src-tranche/tranche.lib.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef TRANCHE_LIB_H -#define TRANCHE_LIB_H - -int tranche_send(FILE *src, Da *arg_fds); - - - -#endif diff --git a/subu-0/0_makefile b/subu-0/0_makefile new file mode 100644 index 0000000..b8c7b9d --- /dev/null +++ b/subu-0/0_makefile @@ -0,0 +1,40 @@ +# 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) $@ + + + + diff --git a/subu-0/0_makefile-flags b/subu-0/0_makefile-flags new file mode 100644 index 0000000..0da8b61 --- /dev/null +++ b/subu-0/0_makefile-flags @@ -0,0 +1,31 @@ + +# 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 + +LIBFILE=$(LIBDIR)/libsubu.a + diff --git a/subu-0/1_deprecated/dispatch_exec.lib.c b/subu-0/1_deprecated/dispatch_exec.lib.c new file mode 100644 index 0000000..024bff8 --- /dev/null +++ b/subu-0/1_deprecated/dispatch_exec.lib.c @@ -0,0 +1,60 @@ +/* + fork/execs/wait the command passed in argv[0]; + Returns -1 upon failure. + + The wstatus returned from wait() might be either the error returned by exec + when it failed, or the return value from the command. An arbitary command is + passed in, so we don't know what its return values might be. Consquently, we + have no way of multiplexing a unique exec error code with the command return + value within wstatus. If the prorgrammer knows the return values of the + command passed in, and wants better behavior, he or she can spin a special + version of dispatch for that command. +*/ +#include "dispatch_exec.lib.h" + +// without this #define execvpe is undefined +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + + + +int dispatch_exec(char **argv, char **envp){ + if( !argv || !argv[0] ){ + fprintf(stderr, "argv[0] null. Null command passed into dispatch().\n"); + return -1; + } + #ifdef DEBUG + dbprintf("dispatching exec, args follow:\n"); + char **apt = argv; + while( *apt ){ + dbprintf("\t%s",*apt); + apt++; + } + dbprintf("\n"); + #endif + char *command = argv[0]; + pid_t pid = fork(); + if( pid == -1 ){ + fprintf(stderr, "fork() failed in dispatch().\n"); + return -1; + } + if( pid == 0 ){ // we are the child + execvpe(command, argv, envp); + // exec will only return if it has an error .. + perror(command); + return -1; + }else{ // we are the parent + int wstatus; + waitpid(pid, &wstatus, 0); + if(wstatus) + return -1; + else + return 0; + } +} diff --git a/subu-0/1_deprecated/dispatch_f.lib.c b/subu-0/1_deprecated/dispatch_f.lib.c new file mode 100644 index 0000000..5c199f5 --- /dev/null +++ b/subu-0/1_deprecated/dispatch_f.lib.c @@ -0,0 +1,130 @@ +/* + Forks a new process and runs the a function in that new process. I.e. it 'spawns' a function. + + f must have the specified prototype. I.e. it accepts one void pointer and + returns a positive integer. (Negative integers are used for dispatch error codes.) + + dispatch_f_euid_egid changes to the new euid and egid before running the function. + + If the change to in euid/egid fails, the forked process exits with a negative status. + If the function has an error, it returns a positive status. A status of zero means + that all went well. + + Because f is running in a separate process, the return status is the only means + of communication going back to the calling process. + + +*/ +#define _GNU_SOURCE + +#include "dispatch_f.lib.h" +// we need the declaration for uid_t etc. +// without this #define execvpe is undefined +#define _GNU_SOURCE + +#include +#include +#include +#include + +#if INTERFACE +#include +#include +#endif + +//-------------------------------------------------------------------------------- +// dispatch_f_ctx class +// +#if INTERFACE +#define ERR_NEGATIVE_RETURN_STATUS -1 +#define ERR_DISPATCH_F_FORK -2 +#define ERR_DISPATCH_F_SETEUID -3 +#define ERR_DISPATCH_F_SETEGID -4 + +// both name and fname are static allocations +struct dispatch_f_ctx{ + char *dispatcher; // name of the dispatch function (currently "dispatch_f" or "dispatch_f_euid_egid") + char *dispatchee; // name of the function being dispatched + int err; + int status; // return value from the function +}; +#endif +dispatch_f_ctx *dispatch_f_ctx_mk(char *name, char *fname){ + dispatch_f_ctx *ctxp = malloc(sizeof(dispatch_f_ctx)); + ctxp->dispatcher = name; + ctxp->dispatchee = fname; + ctxp->err = 0; + return ctxp; +} +void dispatch_f_ctx_free(dispatch_f_ctx *ctxp){ + // no dynamic variables to be freed in ctx + free(ctxp); +} +void dispatch_f_mess(struct dispatch_f_ctx *ctxp){ + if(ctxp->err == 0) return; + switch(ctxp->err){ + case ERR_NEGATIVE_RETURN_STATUS: + fprintf(stderr, "%s, function \"%s\" broke contract with a negative return value.", ctxp->dispatcher, ctxp->dispatchee); + break; + case ERR_DISPATCH_F_FORK: + case ERR_DISPATCH_F_SETEUID: + case ERR_DISPATCH_F_SETEGID: + fprintf(stderr, "%s, ", ctxp->dispatcher); + perror(ctxp->dispatcher); + break; + } + fputc('\n', stderr); +} + +//-------------------------------------------------------------------------------- +// interface call point +dispatch_f_ctx *dispatch_f(char *fname, int (*f)(void *arg), void *f_arg){ + dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f", fname); + #ifdef DEBUG + dbprintf("%s %s\n", ctxp->dispatcher, ctxp->dispatchee); + #endif + pid_t pid = fork(); + if( pid == -1 ){ + ctxp->err = ERR_DISPATCH_F_FORK; // we are still in the parent process + return ctxp; + } + if( pid == 0 ){ // we are the child + int status = (*f)(f_arg); // we require that f return a zero or positive value + if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; + exit(status); + }else{ // we are the parent + waitpid(pid, &(ctxp->status), 0); + return ctxp; + } +} + +//-------------------------------------------------------------------------------- +// interface call point +dispatch_f_ctx *dispatch_f_euid_egid(char *fname, int (*f)(void *arg), void *f_arg, uid_t euid, gid_t egid){ + dispatch_f_ctx *ctxp = dispatch_f_ctx_mk("dispatch_f_euid_egid", fname); + #ifdef DEBUG + dbprintf("%s %s as euid:%u egid:%u\n", ctxp->dispatcher, ctxp->dispatchee, euid, egid); + #endif + pid_t pid = fork(); + if( pid == -1 ){ + ctxp->err = ERR_DISPATCH_F_FORK; + return ctxp; + } + if( pid == 0 ){ // we are the child + int status; + if( seteuid(euid) == -1 ) + status = ERR_DISPATCH_F_SETEUID; + else if( setegid(egid) == -1 ) + status = ERR_DISPATCH_F_SETEGID; + else{ + status = (*f)(f_arg); + if( status < 0 ) status = ERR_NEGATIVE_RETURN_STATUS; + exit(status); + } + }else{ // we are the parent + waitpid(pid, &(ctxp->status), 0); + return ctxp; + } +} + + diff --git a/subu-0/1_deprecated/dispatch_useradd.lib.c b/subu-0/1_deprecated/dispatch_useradd.lib.c new file mode 100644 index 0000000..7b75291 --- /dev/null +++ b/subu-0/1_deprecated/dispatch_useradd.lib.c @@ -0,0 +1,68 @@ +/* +There is no C library interface to useradd(8), but if there were, this function +would be found there instead. + +*/ +#include "dispatch_useradd.lib.h" + +#include +#include +#include +#include +#include + +#if INTERFACE +#include +#include +#define ERR_DISPATCH_USERADD_ARGC 1 +#define ERR_DISPATCH_USERADD_DISPATCH 2 +#define ERR_DISPATCH_USERADD_PWREC 3 +struct dispatch_useradd_ret_t{ + uint error; + struct passwd *pw_record; +}; +#endif + + +// we have a contract with the caller that argv[1] is always the subuname +struct dispatch_useradd_ret_t dispatch_useradd(char **argv, char **envp){ + struct dispatch_useradd_ret_t ret; + { + if( !argv || !argv[0] || !argv[1]){ + fprintf(stderr,"useradd() needs a first argument as the name of the user to be made"); + ret.error = ERR_DISPATCH_USERADD_ARGC; + ret.pw_record = NULL; + return ret; + } + + char *subu_name; + { + subu_name = argv[1]; + if( dispatch_exec(argv, envp) == -1 ){ + fprintf(stderr,"%s failed\n", argv[0]); + ret.error = ERR_DISPATCH_USERADD_DISPATCH; + ret.pw_record = NULL; + return ret; + }} + + { + struct passwd *pw_record = getpwnam(subu_name); + uint count = 1; + while( !pw_record && count <= 3 ){ + #ifdef DEBUG + printf("try %u, getpwnam failed, trying again\n", count); + #endif + sleep(1); + pw_record = getpwnam(subu_name); + count++; + } + if( !pw_record ){ + ret.error = ERR_DISPATCH_USERADD_PWREC; + ret.pw_record = NULL; + return ret; + } + ret.error = 0; + ret.pw_record = pw_record; + return ret; + }}} + diff --git a/subu-0/1_deprecated/subu-rm-0.lib.c b/subu-0/1_deprecated/subu-rm-0.lib.c new file mode 100644 index 0000000..ccad437 --- /dev/null +++ b/subu-0/1_deprecated/subu-rm-0.lib.c @@ -0,0 +1,381 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include + +#if INTERFACE +#include +#include +#include +#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; +} diff --git a/subu-0/1_deprecated/subudb-number-next.cli.c b/subu-0/1_deprecated/subudb-number-next.cli.c new file mode 100644 index 0000000..3373173 --- /dev/null +++ b/subu-0/1_deprecated/subudb-number-next.cli.c @@ -0,0 +1,45 @@ +/* +Set or get a new maximum subu number. Currently doesn't do the setting part. + +*/ +#include "subudb-number-next.cli.h" +#include +#include +#include + +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; +} diff --git a/subu-0/1_doc/to_do.txt b/subu-0/1_doc/to_do.txt new file mode 100644 index 0000000..0b989cc --- /dev/null +++ b/subu-0/1_doc/to_do.txt @@ -0,0 +1,38 @@ +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. diff --git a/subu-0/1_tests/0_makefile b/subu-0/1_tests/0_makefile new file mode 100644 index 0000000..67cea25 --- /dev/null +++ b/subu-0/1_tests/0_makefile @@ -0,0 +1,32 @@ +# 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) $@ + + + + diff --git a/subu-0/1_tests/0_makefile_flags b/subu-0/1_tests/0_makefile_flags new file mode 100644 index 0000000..8818691 --- /dev/null +++ b/subu-0/1_tests/0_makefile_flags @@ -0,0 +1,31 @@ + +# 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 + +LIBFILE=$(LIBDIR)/libtests.a + diff --git a/subu-0/1_tests/1_tmp/makefile_deps b/subu-0/1_tests/1_tmp/makefile_deps new file mode 100644 index 0000000..9486ae8 --- /dev/null +++ b/subu-0/1_tests/1_tmp/makefile_deps @@ -0,0 +1,4 @@ +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 diff --git a/subu-0/1_tests/da.cli.c b/subu-0/1_tests/da.cli.c new file mode 100644 index 0000000..910a15e --- /dev/null +++ b/subu-0/1_tests/da.cli.c @@ -0,0 +1,50 @@ +/* +Tests for da. + +*/ + +#include +#include + +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; + +} diff --git a/subu-0/1_tests/libtests.a b/subu-0/1_tests/libtests.a new file mode 100644 index 0000000..8b277f0 --- /dev/null +++ b/subu-0/1_tests/libtests.a @@ -0,0 +1 @@ +! diff --git a/subu-0/1_tmp/da.lib.h b/subu-0/1_tmp/da.lib.h new file mode 100644 index 0000000..4702189 --- /dev/null +++ b/subu-0/1_tmp/da.lib.h @@ -0,0 +1,23 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +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 diff --git a/subu-0/1_tmp/dbprintf.lib.h b/subu-0/1_tmp/dbprintf.lib.h new file mode 100644 index 0000000..3056cf6 --- /dev/null +++ b/subu-0/1_tmp/dbprintf.lib.h @@ -0,0 +1,3 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +int dbprintf(const char *format,...); diff --git a/subu-0/1_tmp/dispatch.lib.h b/subu-0/1_tmp/dispatch.lib.h new file mode 100644 index 0000000..07e2271 --- /dev/null +++ b/subu-0/1_tmp/dispatch.lib.h @@ -0,0 +1,24 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +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 diff --git a/subu-0/1_tmp/subu-bind-all.cli.h b/subu-0/1_tmp/subu-bind-all.cli.h new file mode 100644 index 0000000..7e52675 --- /dev/null +++ b/subu-0/1_tmp/subu-bind-all.cli.h @@ -0,0 +1,9 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +#include +int subu_bind_all(char **mess,sqlite3 *db); +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; +#define SUBU_ERR_ARG_CNT 1 diff --git a/subu-0/1_tmp/subu-bind.cli.h b/subu-0/1_tmp/subu-bind.cli.h new file mode 100644 index 0000000..af12d61 --- /dev/null +++ b/subu-0/1_tmp/subu-bind.cli.h @@ -0,0 +1,7 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +#include +int subu_bind(char **mess,char *masteru_name,char *subu_username,char *subuhome); +#define SUBU_ERR_ARG_CNT 1 diff --git a/subu-0/1_tmp/subu-common.lib.h b/subu-0/1_tmp/subu-common.lib.h new file mode 100644 index 0000000..cfdc520 --- /dev/null +++ b/subu-0/1_tmp/subu-common.lib.h @@ -0,0 +1,9 @@ +/* This 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 diff --git a/subu-0/1_tmp/subu-mk-0.cli.h b/subu-0/1_tmp/subu-mk-0.cli.h new file mode 100644 index 0000000..487b509 --- /dev/null +++ b/subu-0/1_tmp/subu-mk-0.cli.h @@ -0,0 +1,10 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +#include +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 diff --git a/subu-0/1_tmp/subu-rm-0.cli.h b/subu-0/1_tmp/subu-rm-0.cli.h new file mode 100644 index 0000000..070bfe8 --- /dev/null +++ b/subu-0/1_tmp/subu-rm-0.cli.h @@ -0,0 +1,10 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +#include +#include +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 diff --git a/subu-0/1_tmp/subu.lib.h b/subu-0/1_tmp/subu.lib.h new file mode 100644 index 0000000..69c5da7 --- /dev/null +++ b/subu-0/1_tmp/subu.lib.h @@ -0,0 +1,66 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +typedef unsigned int uint; +#include +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 +#include +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 +#include +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 +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 diff --git a/subu-0/1_tmp/subudb-init.cli.h b/subu-0/1_tmp/subudb-init.cli.h new file mode 100644 index 0000000..4435103 --- /dev/null +++ b/subu-0/1_tmp/subudb-init.cli.h @@ -0,0 +1,11 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +int db_commit(sqlite3 *db); +int db_rollback(sqlite3 *db); +int subudb_schema(sqlite3 *db); +int db_begin(sqlite3 *db); +#include +#include +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; diff --git a/subu-0/1_tmp/subudb-number.cli.h b/subu-0/1_tmp/subudb-number.cli.h new file mode 100644 index 0000000..c130fbb --- /dev/null +++ b/subu-0/1_tmp/subudb-number.cli.h @@ -0,0 +1,11 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +int subudb_number_get(sqlite3 *db,int *n); +int subudb_number_set(sqlite3 *db,int n); +#include +#include +#define SUBU_ERR_N 14 +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; +#define SUBU_ERR_ARG_CNT 1 diff --git a/subu-0/1_tmp/subudb-rel-get.cli.h b/subu-0/1_tmp/subudb-rel-get.cli.h new file mode 100644 index 0000000..4f335be --- /dev/null +++ b/subu-0/1_tmp/subudb-rel-get.cli.h @@ -0,0 +1,9 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +int subudb_Masteru_Subu_get_subu_username(sqlite3 *db,char *masteru_name,char *subuname,char **subu_username); +#include +#include +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; +#define SUBU_ERR_ARG_CNT 1 diff --git a/subu-0/1_tmp/subudb-rel-put.cli.h b/subu-0/1_tmp/subudb-rel-put.cli.h new file mode 100644 index 0000000..243b3a9 --- /dev/null +++ b/subu-0/1_tmp/subudb-rel-put.cli.h @@ -0,0 +1,8 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +int subudb_Masteru_Subu_put(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); +#include +#include +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; diff --git a/subu-0/1_tmp/subudb-rel-rm.cli.h b/subu-0/1_tmp/subudb-rel-rm.cli.h new file mode 100644 index 0000000..595427f --- /dev/null +++ b/subu-0/1_tmp/subudb-rel-rm.cli.h @@ -0,0 +1,8 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); +#include +#include +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; diff --git a/subu-0/1_tmp/subudb-subus.cli.h b/subu-0/1_tmp/subudb-subus.cli.h new file mode 100644 index 0000000..16310b7 --- /dev/null +++ b/subu-0/1_tmp/subudb-subus.cli.h @@ -0,0 +1,14 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +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 +#include +#define SUBU_ERR_DB_FILE 8 +extern char DB_File[]; +#define SUBU_ERR_ARG_CNT 1 diff --git a/subu-0/1_tmp/subudb.lib.h b/subu-0/1_tmp/subudb.lib.h new file mode 100644 index 0000000..be73823 --- /dev/null +++ b/subu-0/1_tmp/subudb.lib.h @@ -0,0 +1,27 @@ +/* This file was automatically generated. Do not edit! */ +#undef INTERFACE +#include +int subudb_Masteru_Subu_rm(sqlite3 *db,char *masteru_name,char *subuname,char *subu_username); +#include +#include +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 diff --git a/subu-0/1_try/split.c b/subu-0/1_try/split.c new file mode 100644 index 0000000..6d4c6ac --- /dev/null +++ b/subu-0/1_try/split.c @@ -0,0 +1,20 @@ +/* +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 diff --git a/subu-0/1_try/split_arg.c b/subu-0/1_try/split_arg.c new file mode 100644 index 0000000..6d4c6ac --- /dev/null +++ b/subu-0/1_try/split_arg.c @@ -0,0 +1,20 @@ +/* +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 diff --git a/subu-0/1_try/subudb b/subu-0/1_try/subudb new file mode 100644 index 0000000..e69de29 diff --git a/subu-0/1_try/voidptr.c b/subu-0/1_try/voidptr.c new file mode 100644 index 0000000..bd9c3e5 --- /dev/null +++ b/subu-0/1_try/voidptr.c @@ -0,0 +1,48 @@ +/* +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 + +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; +} diff --git a/subu-0/common.lib.c b/subu-0/common.lib.c new file mode 100644 index 0000000..9ce5a27 --- /dev/null +++ b/subu-0/common.lib.c @@ -0,0 +1,20 @@ + +#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/"; diff --git a/subu-0/db.lib.c b/subu-0/db.lib.c new file mode 100644 index 0000000..17a5419 --- /dev/null +++ b/subu-0/db.lib.c @@ -0,0 +1,192 @@ +/* +The db file is maintained in SQLite + +Because user names of are of limited length, subu user names are always named _s. +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 +#endif + +#include +#include +#include +#include + +//-------------------------------------------------------------------------------- +// 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; +} diff --git a/subu-0/subu-bind-all.cli.c b/subu-0/subu-bind-all.cli.c new file mode 100644 index 0000000..e942909 --- /dev/null +++ b/subu-0/subu-bind-all.cli.c @@ -0,0 +1,31 @@ +/* +mount all the subu user directories into master's subuland +uses unmount to undo this + +*/ +#include "subu-bind-all.cli.h" +#include +#include + +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; +} diff --git a/subu-0/subu-bind.cli.c b/subu-0/subu-bind.cli.c new file mode 100644 index 0000000..f315823 --- /dev/null +++ b/subu-0/subu-bind.cli.c @@ -0,0 +1,25 @@ +/* +mount a subu user directory into master's subuland +uses unmount to undo this + +*/ +#include "subu-bind.cli.h" +#include +#include + +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; +} diff --git a/subu-0/subu-mk-0.cli.c b/subu-0/subu-mk-0.cli.c new file mode 100644 index 0000000..af0888b --- /dev/null +++ b/subu-0/subu-mk-0.cli.c @@ -0,0 +1,43 @@ +/* + subu-mk-0 command + +*/ +#include "subu-mk-0.cli.h" +#include +#include + +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; + +} diff --git a/subu-0/subu-rm-0.cli.c b/subu-0/subu-rm-0.cli.c new file mode 100644 index 0000000..a7e5926 --- /dev/null +++ b/subu-0/subu-rm-0.cli.c @@ -0,0 +1,32 @@ +/* + subu-mk-0 command + +*/ +#include "subu-rm-0.cli.h" +#include +#include + +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; + } +} diff --git a/subu-0/subu.lib.c b/subu-0/subu.lib.c new file mode 100644 index 0000000..988bd28 --- /dev/null +++ b/subu-0/subu.lib.c @@ -0,0 +1,713 @@ +/* + 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, calls useradd to creat + the new uswer account, and enters the relationship between masteru, subu, and + s in the db file. It is this relation in the db file that + associates the subuname with the s user. + + subu-rm-0 uses userdel to delete the related s 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 +#include +#include +#include +#include +#include +#include +#include + +#if INTERFACE +#include +#include +#include +#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); +} diff --git a/subu-0/subudb-init.cli.c b/subu-0/subudb-init.cli.c new file mode 100644 index 0000000..714c7e4 --- /dev/null +++ b/subu-0/subudb-init.cli.c @@ -0,0 +1,26 @@ +/* +This command initializes the db file. + +*/ +#include "subudb-init.cli.h" +#include + +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; +} diff --git a/subu-0/subudb-number.cli.c b/subu-0/subudb-number.cli.c new file mode 100644 index 0000000..60304e3 --- /dev/null +++ b/subu-0/subudb-number.cli.c @@ -0,0 +1,63 @@ +/* +Set or get a new maximum subu number. Currently doesn't do the setting part. + +*/ +#include "subudb-number.cli.h" +#include +#include +#include + +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; + +} diff --git a/subu-0/subudb-rel-get.cli.c b/subu-0/subudb-rel-get.cli.c new file mode 100644 index 0000000..9828b15 --- /dev/null +++ b/subu-0/subudb-rel-get.cli.c @@ -0,0 +1,42 @@ +/* +get the username from the db file +for testing subudb_Masteru_Subu_get_subu_username + +*/ +#include "subudb-rel-get.cli.h" +#include +#include + +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; +} diff --git a/subu-0/subudb-rel-put.cli.c b/subu-0/subudb-rel-put.cli.c new file mode 100644 index 0000000..b19896e --- /dev/null +++ b/subu-0/subudb-rel-put.cli.c @@ -0,0 +1,40 @@ +/* +puts a relation in the masteru/subu table + +*/ +#include "subudb-rel-put.cli.h" +#include +#include + +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; +} diff --git a/subu-0/subudb-rel-rm.cli.c b/subu-0/subudb-rel-rm.cli.c new file mode 100644 index 0000000..3d15ca9 --- /dev/null +++ b/subu-0/subudb-rel-rm.cli.c @@ -0,0 +1,41 @@ +/* +puts a relation in the masteru/subu table + +*/ +#include "subudb-rel-rm.cli.h" +#include +#include + +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; +} diff --git a/subu-0/subudb-subus.cli.c b/subu-0/subudb-subus.cli.c new file mode 100644 index 0000000..be3af20 --- /dev/null +++ b/subu-0/subudb-subus.cli.c @@ -0,0 +1,47 @@ +/* +Set or get a new maximum subu number. Currently doesn't do the setting part. + +*/ +#include "subudb-subus.cli.h" +#include +#include +#include + +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; + +} diff --git a/subu-1/subu-mk.py b/subu-1/subu-mk.py new file mode 100644 index 0000000..203fab4 --- /dev/null +++ b/subu-1/subu-mk.py @@ -0,0 +1,299 @@ +#!/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=][owner=] [subu=] +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) diff --git a/tools/bin/make b/tools/bin/make deleted file mode 100755 index 3345aba..0000000 --- a/tools/bin/make +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -mf=( ?_makefile ) -if [ -f "$mf" ]; then - /usr/bin/make -f "$mf" "$@" -else - /usr/bin/make "$@" -fi - - - diff --git a/tools/bin/tranche b/tools/bin/tranche new file mode 100755 index 0000000..eb63c28 Binary files /dev/null and b/tools/bin/tranche differ diff --git a/tools/lib/makefile_cc b/tools/lib/makefile_cc index 6bef9cc..bcf2475 100755 --- a/tools/lib/makefile_cc +++ b/tools/lib/makefile_cc @@ -1,37 +1,38 @@ +#should add test that incdir is not pwd before deleting the include file in +#dist-clean currently make is looking for module.h while the include file is +#always module.lib.h so the lib include is not getting clobbered + SHELL=/bin/bash -# files used by the compiler -C_SOURCES_LIB= $(wildcard *.lib.c) -C_SOURCES_CLI= $(wildcard *.cli.c) -C_SOURCES= $(C_SOURCES_LIB) $(C_SOURCES_CLI) - -CC_SOURCES_LIB= $(wildcard *.lib.cc) -CC_SOURCES_CLI= $(wildcard *.cli.cc) -CC_SOURCES= $(CC_SOURCES_LIB) $(CC_SOURCES_CLI) - -OBJECTS_LIB=$(sort\ - $(patsubst %.c, %.o, $(C_SOURCES_LIB))\ - $(patsubst %.cc, %.o, $(CC_SOURCES_LIB))\ - ) -OBJECTS_CLI=$(sort\ - $(patsubst %.c, %.o, $(C_SOURCES_CLI))\ - $(patsubst %.cc, %.o, $(CC_SOURCES_CLI))\ - ) -OBJECTS= $(OBJECTS_LIB) $(OBJECTS_CLI) - -EXECS= $(sort \ - $(patsubst %.cli.c, %, $(wildcard *.cli.c))\ - $(patsubst %.cli.cc, %, $(wildcard *.cli.cc))\ - ) +# these are the sources edited by the programmer +C_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.c) +C_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.c) +CC_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc) +CC_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.cc) + +#remove the suffix to get base name +C_BASE_LIB= $(sort $(patsubst %.lib.c, %, $(notdir $(C_SOURCE_LIB)))) +C_BASE_CLI= $(sort $(patsubst %.cli.c, %, $(notdir $(C_SOURCE_CLI)))) +CC_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CC_SOURCE_LIB)))) +CC_BASE_CLI= $(sort $(patsubst %.cli.cc, %, $(notdir $(CC_SOURCE_CLI)))) + +# two sets of object files, one for the lib, and one for the command line interface progs +OBJECT_LIB= $(patsubst %, $(TMPDIR)/%.lib.o, $(C_BASE_LIB) $(CC_BASE_LIB)) +OBJECT_CLI= $(patsubst %, $(TMPDIR)/%.cli.o, $(C_BASE_CLI) $(CC_BASE_CLI)) + +# executables are made from CLI sources +EXEC= $(patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI)) #otherwise make provides default values for these C= CC= --include 0_makefile-flags +DEPFILE=$(TMPDIR)/makefile-dep +LIBFILE=$(LIBDIR)/lib$(MODULE).a +INCFILE=$(INCDIR)/$(MODULE).h -DEPSFILE=$(TMPDIR)/makefile_deps +-include makefile-flags # a single space literal, for example if you wanted to subsitute commas to # spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send @@ -39,11 +40,12 @@ DEPSFILE=$(TMPDIR)/makefile_deps blank := space :=$(blank) $(blank) +.PHONY: all +all: version dep lib exec -all: version deps lib execs - +.PHONY: version version: - @echo makefile version 3.0 + @echo makefile version 4.0 @echo "PWD: " $(PWD) @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST) @echo "C: " $(C) @@ -52,103 +54,115 @@ version: @echo "CCFLAGS: " $(CCFLAGS) @echo "LINKFLAGS: " $(LINKFLAGS) +.PHONY: info info: - @echo "DEPDIR: " $(DEPDIR) + @echo "DEPRDIR: " $(DEPRDIR) @echo "DOCDIR: " $(DOCDIR) - @echo "EXECSDIR: " $(EXECSDIR) + @echo "EXECDIR: " $(EXECDIR) @echo "INCDIR: " $(INCDIR) @echo "LIBDIR: " $(LIBDIR) @echo "TESTDIR: " $(TESTDIR) @echo "TMPDIR: " $(TMPDIR) @echo "TOOLSDIR: " $(TOOLSDIR) @echo "TRYDIR: " $(TRYDIR) - @echo "DEPSFILE: " $(DEPSFILE) + @echo "DEPFILE: " $(DEPFILE) @echo "LIBFILE: " $(LIBFILE) - @echo "C_SOURCES_LIB: " $(C_SOURCES_LIB) - @echo "C_SOURCES_CLI: " $(C_SOURCES_CLI) - @echo "C_SOURCES: " $(C_SOURCES) - @echo "CC_SOURCES_LIB: " $(CC_SOURCES_LIB) - @echo "CC_SOURCES_CLI: " $(CC_SOURCES_CLI) - @echo "CC_SOURCES: " $(CC_SOURCES) - @echo "OBJECTS_LIB: " $(OBJECTS_LIB) - @echo "OBJECTS_CLI: " $(OBJECTS_CLI) - @echo "OBJECTS: " $(OBJECTS) - @echo "EXECS: " $(EXECS) + @echo "INCFILE: " $(INCFILE) + @echo "C_SOURCE_LIB: " $(C_SOURCE_LIB) + @echo "C_SOURCE_CLI: " $(C_SOURCE_CLI) + @echo "CC_SOURCE_LIB: " $(CC_SOURCE_LIB) + @echo "CC_SOURCE_CLI: " $(CC_SOURCE_CLI) + @echo "C_BASE_LIB: " $(C_BASE_LIB) + @echo "C_BASE_CLI: " $(C_BASE_CLI) + @echo "CC_BASE_LIB: " $(CC_BASE_LIB) + @echo "CC_BASE_CLI: " $(CC_BASE_CLI) + @echo "OBJECT_LIB: " $(OBJECT_LIB) + @echo "OBJECT_CLI: " $(OBJECT_CLI) + @echo "EXEC: " $(EXEC) # should be safe to run this in an already setup or partially setup directory +.PHONY: setup setup: - if [ ! -e $(DEPRDIR) ]; then mkdir $(DEPRDIR); fi - if [ ! -e $(DOCDIR) ]; then mkdir $(DOCDIR); fi - if [ ! -e $(EXECSDIR) ]; then mkdir $(EXECSDIR); fi - if [ ! -e $(INCDIR) ]; then mkdir $(INCDIR); fi - if [ ! -e $(LIBDIR) ]; then mkdir $(LIBDIR); fi - if [ ! -e $(TESTDIR) ]; then mkdir $(TESTDIR); fi - if [ ! -e $(TMPDIR) ]; then mkdir $(TMPDIR); fi - if [ ! -e $(TRYDIR) ]; then mkdir $(TRYDIR); fi - -deps: + [ ! -e $(DEPRDIR) ] && mkdir $(DEPRDIR) || true + [ ! -e $(DOCDIR) ] && mkdir $(DOCDIR) || true + [ ! -e $(EXECDIR) ] && mkdir $(EXECDIR) || true + [ ! -e $(INCDIR) ] && mkdir $(INCDIR) || true + [ ! -e $(LIBDIR) ] && mkdir $(LIBDIR) || true + [ ! -e $(SRCDIR) ] && mkdir $(SRCDIR) || true + [ ! -e $(TESTDIR) ] && mkdir $(TESTDIR) || true + [ ! -e $(TMPDIR) ] && mkdir $(TMPDIR) || true + [ ! -e $(TRYDIR) ] && mkdir $(TRYDIR) || true + +#better to put the dependency generation into a loop on the source file and specify -MT for the target +#also should be redirecting only stdout so stderr messages will be displayed >>1 depfile +.PHONY: dep +dep: @if [ -z "$(CC)" ]; then\ if [ -z "$C()" ]; then\ echo "No compiler specified";\ exit 1;\ else\ echo "C compiler only deps" ;\ - $(C) $(CFLAGS) -MM $(C_SOURCES) 1> $(DEPSFILE);\ + $(C) $(CFLAGS) -MM $(C_SOURCE_LIB) $(C_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\ echo "deps for C linking";\ - for i in $(EXECS) ; do\ - $(ECHO) >> $(DEPSFILE);\ - $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\ - $(ECHO) " $(C) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\ + for i in $(C_BASE_CLI) ; do\ + $(ECHO) >> $(DEPFILE);\ + $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\ + $(ECHO) " $(C) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\ done;\ fi;\ else\ - $(CC) $(CCFLAGS) -MM $(CC_SOURCES) 1> $(DEPSFILE);\ + $(CC) $(CCFLAGS) -MM $(CC_SOURCE_LIB) $(CC_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\ if [ -z "$C()" ]; then\ echo "CC compiler only deps" ;\ else\ echo "CC and C mixed compile deps" ;\ - $(C) $(CFLAGS) -MM $(C_SOURCES) 1>> $(DEPSFILE);\ + $(C) $(CFLAGS) -MM $(C_SOURCE_LIB) $(C_SOURCE_CLI) | sed 's|^.*\.o|$(TMPDIR)/&|' > $(DEPFILE);\ fi;\ echo "deps for CC linking";\ - for i in $(EXECS) ; do\ - $(ECHO) >> $(DEPSFILE);\ - $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\ - $(ECHO) " $(CC) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\ + for i in $(CC_BASE_CLI) $(C_BASE_CLI) ; do\ + $(ECHO) >> $(DEPFILE);\ + $(ECHO) "$(EXECDIR)/$$i : $(TMPDIR)/$$i.cli.o $(LIBFILE)" >> $(DEPFILE);\ + $(ECHO) " $(CC) -o $(EXECDIR)/$$i $(TMPDIR)/$$i.cli.o $(LINKFLAGS)" >> $(DEPFILE);\ done;\ fi -lib: - make $(LIBDIR)/$(LIBFILE) +.PHONY: lib +lib: $(LIBFILE) -$(LIBDIR)/$(LIBFILE) : $(OBJECTS_LIB) - if [ ! -e $(DEPSFILE) ]; then make deps; fi - ar rcs $(LIBDIR)/$(LIBFILE) $(OBJECTS_LIB) +$(LIBFILE): $(OBJECT_LIB) + ar rcs $(LIBFILE) $(OBJECT_LIB) -execs: $(LIBDIR)/$(LIBFILE) - make sub_execs +.PHONY: exec +exec: $(LIBFILE) + make sub_exec -sub_execs: $(patsubst %, $(EXECSDIR)/%, $(EXECS)) +.PHONY: sub_exec +sub_exec: $(EXEC) +.PHONY: stage stage: - if [ -f $(LIBDIR)/$(LIBFILE) ]; then cp $(LIBDIR)/$(LIBFILE) $(PROJECT_SUBU)/stage/lib; fi - if [ -f $(INCDIR)/$(INCFILE) ]; then cp $(INCDIR)/$(INCFILE) $(PROJECT_SUBU)/stage/include; fi - -cp $(EXECSDIR)/* $(PROJECT_SUBU)/stage/bin + [ -f $(LIBFILE) ] && cp $(LIBFILE) $(PROJECT_SUBU)/stage/lib || true + [ -f $(INCFILE) ] && cp $(INCFILE) $(PROJECT_SUBU)/stage/include || true + [ $(shell ls -A $(EXECDIR)) ] && cp $(EXECDIR)/* $(PROJECT_SUBU)/stage/bin || true +.PHONY: clean clean: - for i in $(wildcard *~); do mv $$i $(TMPDIR); done - for i in $(wildcard *.lib.o) $(wildcard *.cli.o); do rm $$i; done - for i in $(EXECS); do if [ -e $(EXECSDIR)/$$i ]; then rm $(EXECSDIR)/$$i; fi; done - if [ -f $(LIBDIR)/$(LIBFILE) ]; then rm $(LIBDIR)/$(LIBFILE); fi - if [ -f $(DEPSFILE) ]; then rm $(DEPSFILE); fi + for i in $(wildcard tmp/*); do rm $$i || true; done + +.PHONY: dist-clean +dist-clean: clean + for i in $(EXEC); do [ -e $$i ] && rm $$i || true; done + rm $(INCFILE) || true + rm $(LIBFILE) || true --include $(DEPSFILE) +-include $(DEPFILE) -# recipe for making object files: -# -%.o : %.c - $(C) $(CFLAGS) -c $< +# recipes -%.o : %.cc - $(CC) $(CCFLAGS) -c $< +$(TMPDIR)/%.o : $(SRCDIR)/%.c + $(C) $(CFLAGS) -o $@ -c $< +$(TMPDIR)/%.o : $(SRCDIR)/%.cc + $(CC) $(CCFLAGS) -o $@ -c $< diff --git a/tools/lib/makefile_trc b/tools/lib/makefile_trc new file mode 100644 index 0000000..1edc8b3 --- /dev/null +++ b/tools/lib/makefile_trc @@ -0,0 +1,188 @@ + +# We should read the tranche sources and see what files they output, and then +# build the deps accordingly, but this makefile is more primitive approach. +# Here the programmer must have one output .c file or .cc file per input tranche +# file and it must be name .{lib,cli}.{c,cc} and the {.c,.cc} output +# tranche must be named .trc.{c,cc} + +# will re-orgnaize the directory structure .. will name the src-da .. etc. to the +# name of the module, then have a source dir inside that has only the stuff +# programmer's edit, then get rid of the numbers + +SHELL=/bin/bash + +#LIDBIR, EXECDIR, 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=deprecated +DOCDIR=doc +EXECDIR=exec +INCDIR=include +LIBDIR=lib +SRCDIR=src +TESTDIR=test +TMPDIR=tmp +TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) +TRYDIR=try + +LIBFILE=$(LIBDIR)/lib$(MODULE).a +INCFILE=$(MODULE).h + +# these are the sources edited by the programmer +C_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.c) +C_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.c) +CC_SOURCE_LIB= $(wildcard $(SRCDIR)/*.lib.cc) +CC_SOURCE_CLI= $(wildcard $(SRCDIR)/*.cli.cc) + +#remove the suffix to get base name +C_BASE_LIB= $(sort $(patsubst %.lib.c, %, $(notdir $(C_SOURCE_LIB)))) +C_BASE_CLI= $(sort $(patsubst %.cli.c, %, $(notdir $(C_SOURCE_CLI)))) +CC_BASE_LIB= $(sort $(patsubst %.lib.cc, %, $(notdir $(CC_SOURCE_LIB)))) +CC_BASE_CLI= $(sort $(patsubst %.cli.cc, %, $(notdir $(CC_SOURCE_CLI)))) + +# the progreammer must name the c and cc tranches accordingly: +C_TRC_LIB= $(patasubst %, $(TMPDIR)/%.trc.c, C_BASE_LIB) +C_TRC_CLI= $(patasubst %, $(TMPDIR)/%.trc.c, C_BASE_CLI) +CC_TRC_LIB= $(patasubst %, $(TMPDIR)/%.trc.cc, CC_BASE_LIB) +CC_TRC_CLI= $(patasubst %, $(TMPDIR)/%.trc.cc, CC_BASE_CLI) + +# two sets of object files, one for the lib, and one for the command line interface progs +OBJECT_LIB= $(patsubst %, $(TMDIR)/%.o, $(C_BASE_LIB) $(CC_BASE_LIB)) +OBJECT_CLI= $(patsubst %, $(TMDIR)/%.o, $(C_BASE_CLI) $(CC_BASE_CLI)) + +# executables are made from CLI sources +EXEC= (patsubst %, $(EXECDIR)/%, $(C_BASE_CLI) $(CC_BASE_CLI)) + +#otherwise make provides default values for these +C= +CC= + +-include makefile-flags + +DEPFILE=$(TMPDIR)/makefile_dep + +# a single space literal, for example if you wanted to subsitute commas to +# spaces: $(subst $(space),;,$(string)) we ran into this out of a need to send +# multiple separate command arguments to a shell script from one variable value +blank := +space :=$(blank) $(blank) + +all: version deps lib execs + +version: + @echo makefile version 3.0 + @echo "PWD: " $(PWD) + @echo "MAKEFILE_LIST: " $(MAKEFILE_LIST) + @echo "C: " $(C) + @echo "CFLAGS: " $(CFLAGS) + @echo "CC: " $(CC) + @echo "CCFLAGS: " $(CCFLAGS) + @echo "LINKFLAGS: " $(LINKFLAGS) + +info: + @echo "DEPDIR: " $(DEPDIR) + @echo "DOCDIR: " $(DOCDIR) + @echo "EXECSDIR: " $(EXECSDIR) + @echo "INCDIR: " $(INCDIR) + @echo "LIBDIR: " $(LIBDIR) + @echo "TESTDIR: " $(TESTDIR) + @echo "TMPDIR: " $(TMPDIR) + @echo "TOOLSDIR: " $(TOOLSDIR) + @echo "TRYDIR: " $(TRYDIR) + @echo "DEPSFILE: " $(DEPSFILE) + @echo "LIBFILE: " $(LIBFILE) + @echo "TRC_TRC: " $(TRC_TRC) + @echo "C_BASE_LIB: " $(C_BASE_LIB) + @echo "C_BASE_CLI: " $(C_BASE_CLI) + @echo "CC_BASE_LIB: " $(CC_BASE_LIB) + @echo "CC_BASE_CLI: " $(CC_BASE_CLI) + +# should be safe to run this in an already setup or partially setup directory +setup: + if [ ! -e $(DEPRDIR) ]; then mkdir $(DEPRDIR); fi + if [ ! -e $(DOCDIR) ]; then mkdir $(DOCDIR); fi + if [ ! -e $(EXECSDIR) ]; then mkdir $(EXECSDIR); fi + if [ ! -e $(INCDIR) ]; then mkdir $(INCDIR); fi + if [ ! -e $(LIBDIR) ]; then mkdir $(LIBDIR); fi + if [ ! -e $(SRCDIR) ]; then mkdir $(SRCDIR); fi + if [ ! -e $(TESTDIR) ]; then mkdir $(TESTDIR); fi + if [ ! -e $(TMPDIR) ]; then mkdir $(TMPDIR); fi + if [ ! -e $(TRYDIR) ]; then mkdir $(TRYDIR); fi + +dep: $(C_TRC_LIB) $(C_TRC_CLI) $(CC_TRC_LIB) $(CC_TRC_CLI) + if [ -z "$(CC)" ]; then\ + if [ -z "$C()" ]; then\ + echo "No compiler specified";\ + exit 1;\ + else\ + echo "C compiler only deps" ;\ + $(C) $(CFLAGS) -MM $(C_TRC_LIB) $(C_TRC_CLI) 1> $(DEPSFILE);\ + echo "deps for C linking";\ + for i in $(EXECS) ; do\ + $(ECHO) >> $(DEPSFILE);\ + $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\ + $(ECHO) " $(C) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\ + done;\ + fi;\ + else\ + $(CC) $(CCFLAGS) -MM $(CC_TRC_LIB) $(CC_TRC_CLI) 1> $(DEPSFILE);\ + if [ -z "$C()" ]; then\ + echo "CC compiler only deps" ;\ + else\ + echo "CC and C mixed compile deps" ;\ + $(C) $(CFLAGS) -MM $(C_TRC_LIB) $(C_TRC_CLI) 1>> $(DEPSFILE);\ + fi;\ + echo "deps for CC linking";\ + for i in $(EXECS) ; do\ + $(ECHO) >> $(DEPSFILE);\ + $(ECHO) "$(EXECSDIR)/$$i : $$i.cli.o $(LIBDIR)/$(LIBFILE)" >> $(DEPSFILE);\ + $(ECHO) " $(CC) -o $(EXECSDIR)/$$i $$i.cli.o $(LINKFLAGS)" >> $(DEPSFILE);\ + done;\ + fi + +lib: + make $(LIBDIR)/$(LIBFILE) + +$(LIBDIR)/$(LIBFILE) : $(OBJECTS_LIB) + ar rcs $(LIBDIR)/$(LIBFILE) $(OBJECTS_LIB) + +exec: $(LIBDIR)/$(LIBFILE) + make sub_exec + +sub_exec: $(patsubst %, $(EXECSDIR)/%, $(EXECS)) + +stage: + if [ -f $(LIBDIR)/$(LIBFILE) ]; then cp $(LIBDIR)/$(LIBFILE) $(PROJECT_SUBU)/stage/lib; fi + if [ -f $(INCDIR)/$(INCFILE) ]; then cp $(INCDIR)/$(INCFILE) $(PROJECT_SUBU)/stage/include; fi + -cp $(EXECSDIR)/* $(PROJECT_SUBU)/stage/bin + +clean: + for i in $(wildcard *~); do mv $$i $(TMPDIR); done + for i in $(wildcard *.lib.o) $(wildcard *.cli.o); do rm $$i; done + for i in $(EXECS); do if [ -e $(EXECSDIR)/$$i ]; then rm $(EXECSDIR)/$$i; fi; done + if [ -f $(LIBDIR)/$(LIBFILE) ]; then rm $(LIBDIR)/$(LIBFILE); fi + if [ -f $(DEPSFILE) ]; then rm $(DEPSFILE); fi + +-include $(DEPSFILE) + +# recipes +# +%.trc.c : %.lib.c + $(TRANCHE) $< + +%.trc.c : %.cli.c + $(TRANCHE) $< + +%.trc.cc : %.lib.cc + $(TRANCHE) $< + +%.trc.cc : %.cli.cc + $(TRANCHE) $< + +%.o : %.c + $(C) $(CFLAGS) -c $< + +%.o : %.cc + $(CC) $(CCFLAGS) -c $< + diff --git a/tranche/deprecated/0_makefile b/tranche/deprecated/0_makefile new file mode 100644 index 0000000..b8c7b9d --- /dev/null +++ b/tranche/deprecated/0_makefile @@ -0,0 +1,40 @@ +# 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) $@ + + + + diff --git a/tranche/deprecated/0_makefile-flags b/tranche/deprecated/0_makefile-flags new file mode 100644 index 0000000..0da8b61 --- /dev/null +++ b/tranche/deprecated/0_makefile-flags @@ -0,0 +1,31 @@ + +# 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 + +LIBFILE=$(LIBDIR)/libsubu.a + diff --git a/tranche/doc/todo.txt b/tranche/doc/todo.txt new file mode 100644 index 0000000..1494e66 --- /dev/null +++ b/tranche/doc/todo.txt @@ -0,0 +1,11 @@ + +2019-03-22T13:37:23Z +1. indentation + + the first non blank line after the #tranche keyword sets the indentation + level for the following text. When echoing to the output file + remove that many leading spaces. + + Hmm, or allow options among the tranche parameters, -indent 3 or + -indent ' '. + diff --git a/tranche/makefile b/tranche/makefile new file mode 100644 index 0000000..4c20d5e --- /dev/null +++ b/tranche/makefile @@ -0,0 +1,22 @@ +# tranche/makefile + +SHELL=/bin/bash + +-include makefile-flags + +.PHONY: all version deps lib exec +all: version deps lib exec + +lib: + $(MAKE) $@ + cp src/tranche.lib.h include/tranche.h + +exec: + $(MAKE) $@ + +%:: + $(MAKE) $@ + + + + diff --git a/tranche/makefile-flags b/tranche/makefile-flags new file mode 100644 index 0000000..68f6296 --- /dev/null +++ b/tranche/makefile-flags @@ -0,0 +1,31 @@ +MODULE=tranche + +# 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, EXECDIR, INCDIR 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=deprecated +DOCDIR=doc +EXECDIR=exec +INCDIR=include +LIBDIR=lib +SRCDIR=src +TESTDIR=test +TMPDIR=tmp +TOOLSDIR=$(realpath $(PROJECT_SUBU)/tools) +TRYDIR=try + +C=gcc +CFLAGS=-std=gnu11 -fPIC -I. -I../stage/include -ggdb -Werror -DDEBUG -DDEBUGDB +#CFLAGS=-std=gnu11 -fPIC -I. -Werror +LINKFLAGS=-Llib -L../stage/lib/ -lda -ltranche + +MAKE=/usr/bin/make --no-print-directory -f $(PROJECT_SUBU)/tools/lib/makefile_cc +#MAKE=/usr/bin/make -f $(PROJECT_SUBU)/tools/lib/makefile_cc diff --git a/tranche/src/tranche.cli.c b/tranche/src/tranche.cli.c new file mode 100644 index 0000000..8df4337 --- /dev/null +++ b/tranche/src/tranche.cli.c @@ -0,0 +1,25 @@ + +#include +#include +#include +#include "tranche.lib.h" + +int main(int argc, char **argv, char **envp){ + if(argc != 2){ + fprintf(stderr, "usage: %s \n",argv[0]); + return 1; + } + FILE *file = fopen(argv[1], "r"); + if(!file){ + fprintf(stderr,"could not open file %s\n", argv[1]); + return 2; + } + Da targets; + da_alloc(&targets, sizeof(int)); + int fd = STDOUT_FILENO; + da_push(&targets, &fd); + tranche_send(file, &targets); + da_free(&targets); + fclose(file); + return 0; +} diff --git a/tranche/src/tranche.lib.c b/tranche/src/tranche.lib.c new file mode 100644 index 0000000..9b824d3 --- /dev/null +++ b/tranche/src/tranche.lib.c @@ -0,0 +1,146 @@ +/* +The purpose of this tools is to facilitate putting prototypes (declarations) next +to implementations (definitions) in a single source file of a C/C++ programs. + +Splits a single source file into multiple files. Scans through the single +source file looking for lines of the form: + + #tranche-begin filename ... + +With the # as the first non-space character on the line, and only filename +following the tag. Upon finding such a line, copies all following lines into the +listed files, until reaching the end marker: + + #tranche-end + +A next improvement of this file would be to support variables to be passed in +for the file names. As it stands, changing the file name requires editing +the source file. + +Files are opened for create or append, so opening to the same file will append +to the end. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +//-------------------------------------------------------------------------------- +// parsing + +char newline = '\n'; +char terminator = 0; + +char tranche_begin_tag[] = "#tranche"; +size_t tranche_begin_tag_len = 8; + +char tranche_end_tag[] = "#tranche-end"; +size_t tranche_end_tag_len = 12; + +// given a line +// returns beginning of file name list +static char *is_tranche_begin(char *pt){ + while( *pt && isspace(*pt) ) pt++; + if(!*pt) return NULL; + if( strncmp(pt, tranche_begin_tag, tranche_begin_tag_len) ) return NULL; + return pt + tranche_begin_tag_len; +} + +static char *is_tranche_end(char *pt){ + while( *pt && isspace(*pt) ) pt++; + if(!*pt) return NULL; + if( strncmp(pt, tranche_end_tag, tranche_end_tag_len) ) return NULL; + return pt + tranche_end_tag_len; +} + +static bool parse_file_list(Da *file_names, char *pt0){ + char *pt1; + while( *pt0 && isspace(*pt0) ) pt0++; + pt1 = pt0; + while( *pt0 ){ + while( *pt1 && !isspace(*pt1) ) pt1++; + char *file_name = strndup(pt0, pt1 - pt0); + da_push(file_names, &file_name); + while( *pt1 && isspace(*pt1) ) pt1++; + pt0 = pt1; + } +} + + + +//-------------------------------------------------------------------------------- +// da_map calls + +static void tranche_open_fd(void *fnp, void *closure){ + char *file_name = *(char **)fnp; + Da *fdap = (Da *)closure; + int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, 0666); + if(fd == -1){ + fprintf(stderr, "Could not open file %s\n", file_name); + return; + } + da_push(fdap, &fd); + return; +} +static void tranche_open_fds(Da *fnap, Da *fdap){ + da_map(fnap, tranche_open_fd, fdap); +} + +static void tranche_close_fd(void *fdp, void *closure){ + close(*(int *)fdp); +} +static void tranche_close_fds(Da *fdap){ + da_map(fdap, tranche_close_fd, NULL); + da_rewind(fdap); +} + +static void tranche_puts(void *fdp, void *string){ + write(*(int *)fdp, string, strlen(string)); +} +static void tranche_puts_all(Da *fdap, char *string){ + da_map(fdap, tranche_puts, string); +} + + + +//-------------------------------------------------------------------------------- +// we have a little problem if the user tries to tranche two things to the same file .. +int tranche_send(FILE *src, Da *arg_fdap){ + char *pt; + Da line; + Da file_name_arr; + Da fda; + da_alloc(&line, sizeof(char)); + da_alloc(&file_name_arr, sizeof(char *)); + da_alloc(&fda, sizeof(int)); + + while( !feof(src) ){ + da_fgets(&line, src); + if( is_tranche_end(line.base) ) break; + pt = is_tranche_begin(line.base); + if(pt){ // then this line is the start of a nested tranche block + parse_file_list(&file_name_arr, pt); + tranche_open_fds(&file_name_arr, &fda); + da_free_elements(&file_name_arr); + tranche_send(src, &fda); + tranche_close_fds(&fda); + }else{ + da_pop(&line, NULL); // pop the terminating zero + da_push(&line, &newline); + da_push(&line, &terminator); + tranche_puts_all(arg_fdap, line.base); + } + da_rewind(&line); + } + + da_free(&line); + da_free(&file_name_arr); + da_free(&fda); + return 0; +} diff --git a/tranche/src/tranche.lib.h b/tranche/src/tranche.lib.h new file mode 100644 index 0000000..27990a6 --- /dev/null +++ b/tranche/src/tranche.lib.h @@ -0,0 +1,8 @@ +#ifndef TRANCHE_LIB_H +#define TRANCHE_LIB_H + +int tranche_send(FILE *src, Da *arg_fds); + + + +#endif diff --git a/tranche/test/test1.dat b/tranche/test/test1.dat new file mode 100644 index 0000000..b03df3f --- /dev/null +++ b/tranche/test/test1.dat @@ -0,0 +1,23 @@ + +#tranche test11.dat test12.dat +The little red hen said to Mick, no thank you not today sir. +And then all the barnes animals shouted out in glee. +No more misery! +#tranche test13.dat +apple banana pear +kiwi +#tranche-end +cows +and cats +#tranche-end + +the between space + +#tranche test14.dat +int float if while +do +function +#tranche-end + +#tranche test15.dat +#tranche-end \ No newline at end of file diff --git a/tranche/test/test1.sh b/tranche/test/test1.sh new file mode 100644 index 0000000..c1140ca --- /dev/null +++ b/tranche/test/test1.sh @@ -0,0 +1,10 @@ +#!/bin/bash -x +./tranche test1.dat >test1stdout.dat +diff test11.dat test11.dat.expected +diff test12.dat test12.dat.expected +diff test13.dat test13.dat.expected +diff test14.dat test14.dat.expected +diff test15.dat test15.dat.expected +diff test1stdout.dat test1stdout.dat.expected +rm test11.dat test12.dat test13.dat test14.dat test15.dat test1stdout.dat + diff --git a/tranche/test/test11.dat.expected b/tranche/test/test11.dat.expected new file mode 100644 index 0000000..2c2904a --- /dev/null +++ b/tranche/test/test11.dat.expected @@ -0,0 +1,5 @@ +The little red hen said to Mick, no thank you not today sir. +And then all the barnes animals shouted out in glee. +No more misery! +cows +and cats diff --git a/tranche/test/test12.dat.expected b/tranche/test/test12.dat.expected new file mode 100644 index 0000000..2c2904a --- /dev/null +++ b/tranche/test/test12.dat.expected @@ -0,0 +1,5 @@ +The little red hen said to Mick, no thank you not today sir. +And then all the barnes animals shouted out in glee. +No more misery! +cows +and cats diff --git a/tranche/test/test13.dat.expected b/tranche/test/test13.dat.expected new file mode 100644 index 0000000..81fb20c --- /dev/null +++ b/tranche/test/test13.dat.expected @@ -0,0 +1,2 @@ +apple banana pear +kiwi diff --git a/tranche/test/test14.dat.expected b/tranche/test/test14.dat.expected new file mode 100644 index 0000000..0d8b89b --- /dev/null +++ b/tranche/test/test14.dat.expected @@ -0,0 +1,3 @@ +int float if while +do +function diff --git a/tranche/test/test15.dat.expected b/tranche/test/test15.dat.expected new file mode 100644 index 0000000..e69de29 diff --git a/tranche/test/test1stdout.dat.expected b/tranche/test/test1stdout.dat.expected new file mode 100644 index 0000000..4e519ff --- /dev/null +++ b/tranche/test/test1stdout.dat.expected @@ -0,0 +1,5 @@ + + +the between space + + diff --git a/tranche/test/test2.c.expected b/tranche/test/test2.c.expected new file mode 100644 index 0000000..a4876a1 --- /dev/null +++ b/tranche/test/test2.c.expected @@ -0,0 +1,10 @@ + + +#include "test2.h" + + +int f(int x){ + return x; +} + + diff --git a/tranche/test/test2.h.expected b/tranche/test/test2.h.expected new file mode 100644 index 0000000..fdc4d72 --- /dev/null +++ b/tranche/test/test2.h.expected @@ -0,0 +1,4 @@ +#ifndef TEST2_H +#define TEST2_H +int f(int x); +#endif diff --git a/tranche/test/test2.trc.c b/tranche/test/test2.trc.c new file mode 100644 index 0000000..ff7d696 --- /dev/null +++ b/tranche/test/test2.trc.c @@ -0,0 +1,23 @@ + +#tranche test2.c + +#tranche test2.h +#ifndef TEST2_H +#define TEST2_H +#tranche-end + +#include "test2.h" + +#tranche test2.h +int f(int x); +#tranche-end + +int f(int x){ + return x; +} + +#tranche test2.h +#endif +#tranche-end + +#tranche-end diff --git a/tranche/test/tranche b/tranche/test/tranche new file mode 120000 index 0000000..acf4a6f --- /dev/null +++ b/tranche/test/tranche @@ -0,0 +1 @@ +../1_execs/tranche \ No newline at end of file