From: Thomas Walker Lynch Date: Mon, 11 Feb 2019 00:30:50 +0000 (+0100) Subject: checkpoint subu-mk-0 X-Git-Url: https://git.reasoningtechnology.com/style/static/git-favicon.png?a=commitdiff_plain;h=37ed4eeb9162ac491c55b1337ebda60bea4c3bfc;p=subu checkpoint subu-mk-0 --- diff --git a/src/.deps/subu-mk-0.Tpo b/src/.deps/subu-mk-0.Tpo new file mode 100644 index 0000000..cb4e27f --- /dev/null +++ b/src/.deps/subu-mk-0.Tpo @@ -0,0 +1,125 @@ +subu-mk-0.o: subu-mk-0.c /usr/include/stdc-predef.h /usr/include/stdio.h \ + /usr/include/bits/libc-header-start.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \ + /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \ + /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \ + /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \ + /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h subu-mk-0.fi.h useradd.fi.h \ + /usr/include/unistd.h /usr/include/bits/posix_opt.h \ + /usr/include/bits/environments.h /usr/include/bits/confname.h \ + /usr/include/bits/getopt_posix.h /usr/include/bits/getopt_core.h \ + /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \ + /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \ + /usr/include/bits/types/timer_t.h /usr/include/bits/stdint-intn.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \ + /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \ + /usr/include/bits/types/struct_timeval.h \ + /usr/include/bits/types/struct_timespec.h \ + /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \ + /usr/include/bits/pthreadtypes-arch.h + +/usr/include/stdc-predef.h: + +/usr/include/stdio.h: + +/usr/include/bits/libc-header-start.h: + +/usr/include/features.h: + +/usr/include/sys/cdefs.h: + +/usr/include/bits/wordsize.h: + +/usr/include/bits/long-double.h: + +/usr/include/gnu/stubs.h: + +/usr/include/gnu/stubs-64.h: + +/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h: + +/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h: + +/usr/include/bits/types.h: + +/usr/include/bits/typesizes.h: + +/usr/include/bits/types/__fpos_t.h: + +/usr/include/bits/types/__mbstate_t.h: + +/usr/include/bits/types/__fpos64_t.h: + +/usr/include/bits/types/__FILE.h: + +/usr/include/bits/types/FILE.h: + +/usr/include/bits/types/struct_FILE.h: + +/usr/include/bits/stdio_lim.h: + +/usr/include/bits/sys_errlist.h: + +/usr/include/bits/stdio.h: + +subu-mk-0.fi.h: + +useradd.fi.h: + +/usr/include/unistd.h: + +/usr/include/bits/posix_opt.h: + +/usr/include/bits/environments.h: + +/usr/include/bits/confname.h: + +/usr/include/bits/getopt_posix.h: + +/usr/include/bits/getopt_core.h: + +/usr/include/sys/types.h: + +/usr/include/bits/types/clock_t.h: + +/usr/include/bits/types/clockid_t.h: + +/usr/include/bits/types/time_t.h: + +/usr/include/bits/types/timer_t.h: + +/usr/include/bits/stdint-intn.h: + +/usr/include/endian.h: + +/usr/include/bits/endian.h: + +/usr/include/bits/byteswap.h: + +/usr/include/bits/uintn-identity.h: + +/usr/include/sys/select.h: + +/usr/include/bits/select.h: + +/usr/include/bits/types/sigset_t.h: + +/usr/include/bits/types/__sigset_t.h: + +/usr/include/bits/types/struct_timeval.h: + +/usr/include/bits/types/struct_timespec.h: + +/usr/include/bits/pthreadtypes.h: + +/usr/include/bits/thread-shared-types.h: + +/usr/include/bits/pthreadtypes-arch.h: diff --git a/src/local_common.h b/src/local_common.h index 5c17b7b..50ac521 100644 --- a/src/local_common.h +++ b/src/local_common.h @@ -1,6 +1,14 @@ #ifndef LOCAL_COMMON_H #define LOCAL_COMMON_H +#include + +#define DEBUG + +// wstatus is the exec'ed program return code, which we only allow 16 bits +// so as to also have exec routine error codes +#define WSTATUS_MASK ((1 << 16) - 1) + typedef unsigned int uint; diff --git a/src/run.c b/src/run.c new file mode 100644 index 0000000..6823a06 --- /dev/null +++ b/src/run.c @@ -0,0 +1,46 @@ +/* +fork/exec/wait a command + +if the error values returned by the exec'd program +are less than 1 << 16, then + +*/ + +#include +#include +#include +#include +#include +#include "local_common.h" + +struct run_err_struct run_err; + +int run(char **argv, char **envp){ + run_err_init(run_err); + if( !argv || !argv[0] ){ + fprintf(stderr, "argv[0] null on call to run().\n"); + run_err.admin = ADMIN_ERR_NO_COMMAND; + return; + } + pid_t pid = fork(void); + if( pid == -1 ){ + fprintf(stderr, "fork() failed in run().\n"); + run_err.admin = ADMIN_ERR_FORK; + return; + } + if( pid == 0 ){ // we are the child + int run_err = execvpe(argv[0], argv, envp); + // exec will only return if it has an error .. + perror(command); + run_err.exec = errno; + return errno; + }else{ // we are the parent + int wstatus; + wait(1, &wstatus, 0); + if(wstatus != 0) run_err.process = wstatus; + if( run_err_has(run_err) ) + return -1; + else + return 0; + } +} diff --git a/src/run.h b/src/run.h new file mode 100644 index 0000000..8dbff3c --- /dev/null +++ b/src/run.h @@ -0,0 +1,29 @@ +#ifndef RUN_FI_H +#define RUN_FI_H + +#include "local_common.h" + +#define ADMIN_ERR_NO_COMMAND 1 +#define ADMIN_ERR_FORK 2 +#define ADMIN_ERR_ARGC 3 + +struct run_err_struct{ + int admin; // admin error + int exec; // errno from failed exec call + int process; // err code returned from process as reported by wait() +}; +inline run_err_init(struct run_err_struct re){ + re.admin = 0; + re.exec = 0; + re.process = 0; +} +inline run_err_has(struct run_err_struct re){ + return re.admin || re.exec || re.process +} + +extern struct run_err_struct run_err; +uint run(char **argv, char **envp); + +#endif + + diff --git a/src/subu-mk-0.c b/src/subu-mk-0.c index 8649d10..7764191 100644 --- a/src/subu-mk-0.c +++ b/src/subu-mk-0.c @@ -3,7 +3,8 @@ */ -#include "subu-mk-0_fun.h" +#include +#include "subu-mk-0.fi.h" int main(int argc, char **argv, char **env){ char *command = argv[0]; diff --git a/src/subu-mk-0.def.c b/src/subu-mk-0.def.c deleted file mode 100644 index 0adc76f..0000000 --- a/src/subu-mk-0.def.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - Makes a new subu user. - - According to the man page, we are not alloed to free the buffers made by getpwid(). - - 1. We have to make the subu first so that we will have subu_uid and subu_gid - to work with. - - 2. Then we add user access via setfacl to masteru's home directory and to - subu_land, so that we have permissions to make the home directory. - - 3. Then as subu we create the home directory. .. I wonder where the system - gets the umask for this? Perhaps we should create the dir, and then change - the ownership instead? - - 4. Still as subu, we add facls to our directory to give masteru access. - - ... then finished, good part is that we never need to move back to root. - -setfacl -m u:subu:x masteru -setfacl -m u:subu:x masteru/subu_land -setfacl -m d:u:masteru:rwX,u:masteru:rwX subu - -*/ -// without #define get warning: implicit declaration of function ‘seteuid’/‘setegid’ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "subu_mk_0_fun.h" - -#define DEBUG -typedef unsigned int uint; - -#define ERR_ARG_CNT 1 -#define ERR_SETUID_ROOT 2 -#define ERR_BAD_MASTERU_HOME 3 -#define ERR_NOT_EXIST_MASTERU_HOME 4 -#define ERR_FAILED_MKDIR_SUBU 5 -#define ERR_FAILED_RESTORATION 6 - -uid_gid subu_mk_0(char *subu_name){ - - //-------------------------------------------------------------------------------- - // help message - char *command = argv[0]; - if( argc != 2 ){ - fprintf(stderr, "usage: %s subu", command); - return ERR_ARG_CNT; - } - - //-------------------------------------------------------------------------------- - // we must be invoked from a user account and be running as root - uint uid = getuid(); - uint euid = geteuid(); - uint gid = getgid(); - uint egid = getegid(); - #ifdef DEBUG - printf("uid %u, gid %u, euid %u\n", uid, gid, euid); - #endif - if( uid == 0 || euid != 0 ){ - fprintf(stderr, "this program must be run setuid root from a user account\n"); - return ERR_SETUID_ROOT; - } - - //-------------------------------------------------------------------------------- - // who are these people anyway? - char *subu_name = argv[1]; - struct passwd *passwd_record_pt = getpwuid(uid); - char *masteru_name = passwd_record_pt->pw_name; - // verify that subu_name is legal! --> code goes here ... - - //-------------------------------------------------------------------------------- - // build the subu_land path - char *masteru_home_dir = passwd_record_pt->pw_dir; - size_t masteru_home_dir_len = strlen(masteru_home_dir); - if( masteru_home_dir_len == 0 || masteru_home_dir[0] == '(' ){ - fprintf(stderr,"strange, %s has no home directory\n", masteru_name); - return ERR_BAD_MASTERU_HOME; - } - char *subu_land_extension = "/subu_land/"; - size_t subu_land_extension_len = strlen(subu_land_extension); - size_t subu_name_len = strlen(subu_name); // we leave room in the buffer to latter add the subu_name - char *subu_land = (char *)malloc( masteru_home_dir_len + subu_land_extension_len + subu_name_len + 1 ); - strcpy(subu_land, masteru_home_dir); - strcpy(subu_land + masteru_home_dir_len, subu_land_extension); - #ifdef DEBUG - printf("The path to subu_land: %s\n", subu_land); - #endif - - //-------------------------------------------------------------------------------- - // Just because masteru_home_dir is referenced in /etc/passwd does not mean it exists. - // If it does, and the subu_land doesn't, then we make subu_land. - struct stat st; - if( stat(masteru_home_dir, &st) == -1) { - fprintf(stderr, "Strange, masteru home does not exist, %s.", masteru_home_dir); - return ERR_NOT_EXIST_MASTERU_HOME; - } - - //-------------------------------------------------------------------------------- - // the name for the subu home directory, which is subu_land/subu_name - size_t subu_land_len = masteru_home_dir_len + subu_land_extension_len + subu_name_len; - strcpy (subu_land + subu_land_len, subu_name); // we had left room in the subu_land buffer for subu_name - char *subu_home_path = subu_land; // the buffer now holds the subu_home_path, so we call it as such - #ifdef DEBUG - printf("subu home: %s\n", subu_home_path); - #endif - - //-------------------------------------------------------------------------------- - // we now make the subu - char *useradd_argv[4]; - useradd_argv[0] = command; - useradd_argv[1] = "-d"; - useradd_argv[2] = subu_home_path; - useradd_argv[3] = (char *) NULL; - char *useradd_envp[1]; - useradd_envp[0] (char *) NULL; - useradd_0(subu_name, useradd_argv, envp); - - // change to subu space - if( seteuid(uid) == -1 || setegid(gid) == -1 ){ // we are root so this should never happen - fprintf(stderr,"Strangely, root could not seteuid/setegid to %s\n", masteru_name); - return ERR_FAILED_MKDIR_SUBU; - } - if( stat(subu_land, &st) == -1) { // then make the directory - if( mkdir(subu_land, 0700) == -1 || stat(subu_land, &st) == -1 ){ - fprintf(stderr,"Failed to make subu directory %s\n", subu_land); - return ERR_FAILED_MKDIR_SUBU; - } - } - //change back to set the acls - if( seteuid(euid) == -1 || setegid(egid) == -1 ){ - fprintf(stderr,"Could not restore privledges, having to bail.\n"); - return ERR_FAILED_RESTORATION; - } - return 0; -} diff --git a/src/subu-mk-0.fi.c b/src/subu-mk-0.fi.c new file mode 100644 index 0000000..af64072 --- /dev/null +++ b/src/subu-mk-0.fi.c @@ -0,0 +1,156 @@ +/* + Makes a new subu user. + + According to the man page, we are not alloed to free the buffers made by getpwid(). + + 1. We have to make the subu first so that we will have subu_uid and subu_gid + to work with. + + 2. Then we add user access via setfacl to masteru's home directory and to + subu_land, so that we have permissions to make the home directory. + + 3. Then we create the subu home directory. .. I wonder where the system + gets the umask for this? Perhaps we should create the dir, and then change + the ownership instead? + + 4. Still as subu, we add facls to our directory to give masteru access. + + ... then finished, good part is that we never need to move back to root. + +setfacl -m u:subu:x masteru +setfacl -m u:subu:x masteru/subu_land +setfacl -m d:u:masteru:rwX,u:masteru:rwX subu + +*/ +// without #define get warning: implicit declaration of function ‘seteuid’/‘setegid’ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "subu_mk_0.fi.h" + +typedef unsigned int uint; + +uid_gid subu_mk_0(char *subu_name){ + + //-------------------------------------------------------------------------------- + // we must be invoked from a user account and be running as root + uid_t uid = getuid(); + uid_t euid = geteuid(); + gid_t gid = getgid(); + gid_t egid = getegid(); + #ifdef DEBUG + printf("uid %u, gid %u, euid %u\n", uid, gid, euid); + #endif + if( uid == 0 || euid != 0 ){ + fprintf(stderr, "this program must be run setuid root from a user account\n"); + return ERR_SETUID_ROOT; + } + + //-------------------------------------------------------------------------------- + // who are these people anyway? + size_t subu_name_len; + char *masteru_name; + { + // subu_name is the first argument passed in + // verify that subu_name is legal! --> code goes here ... + subu_name_len = strlen(subu_name); + struct passwd *masteru_pw_record_pt = getpwuid(uid); + masteru_name = materu_pw_record_pt->pw_name; + } + #ifdef DEBUG + printf("masteru_name: %s\n", masteru_name); + #endif + + //-------------------------------------------------------------------------------- + // build the subu_land path + char *subu_land; + size_t subu_land_len; + { + char *masteru_home_dir = passwd_record_pt->pw_dir; + size_t masteru_home_dir_len = strlen(masteru_home_dir); + if( masteru_home_dir_len == 0 || masteru_home_dir[0] == '(' ){ + fprintf(stderr,"strange, %s has no home directory\n", masteru_name); + return ERR_BAD_MASTERU_HOME; + } + char *subu_land_extension = "/subu_land/"; + size_t subu_land_extension_len = strlen(subu_land_extension); + // add space in the subu_land buffer to append the subu_name later + subu_land = (char *)malloc( masteru_home_dir_len + subu_land_extension_len + subu_name_len + 1 ); + strcpy(subu_land, masteru_home_dir); + strcpy(subu_land + masteru_home_dir_len, subu_land_extension); + subu_land_len = masteru_home_dir_len + subu_land_extension_len + subu_name_len; + } + #ifdef DEBUG + printf("The path to subu_land: \"%s\"\n", subu_land); + #endif + + //-------------------------------------------------------------------------------- + // Just because masteru_home_dir is referenced in /etc/passwd does not mean it exists. + // We also require that the subu_land sub directory exists. + { + struct stat st; + if( stat(masteru_home_dir, &st) == -1) { + fprintf(stderr, "Strange, masteru home does not exist, \"%s\".", masteru_home_dir); + return ERR_NOT_EXIST_MASTERU_HOME; + } + if( stat(subu_land, &st) == -1) { + fprintf(stderr, "$masteru_home/subu_land not exist"); + return ERR_NOT_EXIST_SUBU_LAND; + } + } + + //-------------------------------------------------------------------------------- + // the name for the subu home directory, which is subu_land/subu_name + strcpy (subu_land + subu_land_len, subu_name); // we had left room in the subu_land buffer for subu_name + char *subu_home_path = subu_land; // the buffer now holds the subu_home_path, so we call it as such + #ifdef DEBUG + printf("subu home: %s\n", subu_home_path); + #endif + + //-------------------------------------------------------------------------------- + // make the subservient user account + uid_t subu_uid; + tid_t subu_gid; + { + char *argv[5]; + argv[0] = command; + argv[1] = subu_name; + argv[2] = "-d"; + argv[3] = subu_home_path; + argv[4] = (char *) NULL; + char *envp[1]; + envp[0] (char *) NULL; + struct ret u_ret = useradd(argv, envp); + if(ret.error){ + fprintf(stderr, "%u useradd failed\n", ret.error) + return ERR_FAILED_USERADD; + } + subu_uid = user_ret.pw_record->pw_uid; + subu_gid = user_ret.pw_record->pw_gid; + } + + //-------------------------------------------------------------------------------- + // Set acls on the subu home directory + + + // subu sets acls to allow masteru access + + return 0; +} + +/* + // change to subu space + if( seteuid(subu_uid) == -1 || setegid(subu_gid) == -1 ){ // we are root so this should never happen + fprintf(stderr,"Strangely, root could not seteuid/setegid to %s\n", subu_name); + return ERR_FAILED_MKDIR_SUBU; + } + +*/ diff --git a/src/subu-mk-0.fi.h b/src/subu-mk-0.fi.h new file mode 100644 index 0000000..cf2828d --- /dev/null +++ b/src/subu-mk-0.fi.h @@ -0,0 +1,18 @@ +#ifndef SUBU_MK_0_H +#define SUBU_MK_0_H + +#include "useradd.fi.h" + +#define ERR_ARG_CNT 1 +#define ERR_SETUID_ROOT 2 +#define ERR_BAD_MASTERU_HOME 3 +#define ERR_NOT_EXIST_MASTERU_HOME 4 +#define ERR_NOT_EXIST_SUBU_LAND 5 +#define ERR_FAILED_MKDIR_SUBU 6 +#define ERR_FAILED_RESTORATION 7 +#define ERR_FAILED_USERADD 8 + + +struct uid_gid subu_mk_0(char *subu_name); + +#endif diff --git a/src/subu_mk_0_def.h b/src/subu_mk_0_def.h deleted file mode 100644 index 1749c43..0000000 --- a/src/subu_mk_0_def.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef SUBU_MK_0_H -#define SUBU_MK_0_H - -#include "useradd-fun.h" -uid_gid subu_mk_0(char *subu_name); - -#endif diff --git a/src/useradd.fi.c b/src/useradd.fi.c new file mode 100644 index 0000000..ff91646 --- /dev/null +++ b/src/useradd.fi.c @@ -0,0 +1,42 @@ +/* +There is no C library interface to useradd(8), but if there were, these functions +would be found there instead. + +*/ + +#include +#include +#include +#include +#include +#include "local_common.h" +#include "run.h" + +// we have a contract with the caller that argv[1] is always the subuname +useradd_ret useradd(char **argv, char **envp){ + run_err_init(run_err); + if( !argv || !argv[0] || !argv[1]){ + fprintf(stderr,"useradd() needs a first argument as the name of the user to be made"); + return useradd_ret(USERADD_ERR_ARGC, NULL); + } + char *subu_name = argv[1]; + if( run(argv, envp) == -1 ){ + fprintf(stderr,"%s failed\n", argv[0]); + return useradd_ret(USER_ERR_RUN); + } + struct password *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 ){ + return struct useradd_ret(USERADD_ERR_PWREC, NULL); + } + return struct useradd_ret(0, pw_record); +} + diff --git a/src/useradd.fi.h b/src/useradd.fi.h new file mode 100644 index 0000000..0042f1d --- /dev/null +++ b/src/useradd.fi.h @@ -0,0 +1,23 @@ +#ifndef USERADD_FI_H +#define USERADD_FI_H + +#include +#include +#include + +// some value larger than any wstatus value +#define USERADD_ERR_UNDEFINED (1 << 16); +#define USERADD_ERR_ARGCNT (2 << 16); +#define USERADD_ERR_PWREC (3 << 16); + +// only use pw_record if error is zero +struct useradd_ret{ + useradd_ret(error=USERADD_ERR_UNDEFINED,pwd=NULL):error(error),pwd(pwd){} + int error; + struct password *pw_record;// as per getpwnam man page do not free() this. +}; +struct useradd_ret useradd(char **argv, char **envp); + +#endif + + diff --git a/src/useradd_fun.c b/src/useradd_fun.c deleted file mode 100644 index 8fe6d13..0000000 --- a/src/useradd_fun.c +++ /dev/null @@ -1,40 +0,0 @@ -/* -There is no C library interface to useradd(8), but if there were, these functions -would be found there instead. I'm also wondering about the wisdom of using -useradd(8) from shadow. Wondering if the locks are in place for multiple users hitting it -simultaneously via different methods, and if it handles signals cleanly. - -We pass argv[1:..] and envp through to useradd. We return the uid of the newly -created user, or the negative value of the return code from useradd(8) - -*/ - -#include -#include -#include -#include -#include - -// better to change this to vargs for the option list -// this currently works because I know there is only one option -int useradd_0(char *user, char **argv, char **envp){ - char *subu_name; - if( argv && argv[0] && argv[1] ){ - - } - pid_t pid = fork(void); - if( pid == -1 ) return 1; - if( pid == 0 ){ // we are the child - char *command = "/usr/bin/useradd"; - argv[0] = command; // we can do this because we made the argv in the caller - int err = execvpe( command, argv, envp); - fprintf(stderr, "subu execvpe call to /usr/bin/useradd issued error %d, but it is too difficult to tell the parent process about this.", errno); - } else { - int wstatus; - wait(1, &wstatus, 0); - if(wstatus != 0) return -abs(wstatus); - // useradd did not tell us the uid of the newly created user, so now we have go get it. - struct passwd *getpwname( - } - -} diff --git a/src/useradd_fun.h b/src/useradd_fun.h deleted file mode 100644 index a2d6e2f..0000000 --- a/src/useradd_fun.h +++ /dev/null @@ -1,14 +0,0 @@ - -#ifndef USERADD_H -#define USERADD_H -#include local_common.h - -struct uid_gid{ - uint error; - pid_t uid; - pid_t gid; -}; - -uit_gid useradd_0(char *user, char **argv, char **envp); - -#endif