--- /dev/null
+subu-mk-0.o: subu-mk-0.c /usr/include/stdc-predef.h /usr/include/stdio.h \
+ /usr/include/bits/libc-header-start.h /usr/include/features.h \
+ /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
+ /usr/include/bits/long-double.h /usr/include/gnu/stubs.h \
+ /usr/include/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h subu-mk-0.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:
#ifndef LOCAL_COMMON_H
#define LOCAL_COMMON_H
+#include <stdbool.h>
+
+#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;
--- /dev/null
+/*
+fork/exec/wait a command
+
+if the error values returned by the exec'd program
+are less than 1 << 16, then
+
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#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;
+ }
+}
--- /dev/null
+#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
+
+
*/
-#include "subu-mk-0_fun.h"
+#include <stdio.h>
+#include "subu-mk-0.fi.h"
int main(int argc, char **argv, char **env){
char *command = argv[0];
+++ /dev/null
-/*
- 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 <unistd.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <string.h>
-#include <sys/stat.h>
-#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;
-}
--- /dev/null
+/*
+ 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 <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/stat.h>
+#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;
+ }
+
+*/
--- /dev/null
+#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
+++ /dev/null
-#ifndef SUBU_MK_0_H
-#define SUBU_MK_0_H
-
-#include "useradd-fun.h"
-uid_gid subu_mk_0(char *subu_name);
-
-#endif
--- /dev/null
+/*
+There is no C library interface to useradd(8), but if there were, these functions
+would be found there instead.
+
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#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);
+}
+
--- /dev/null
+#ifndef USERADD_FI_H
+#define USERADD_FI_H
+
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+
+// 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
+
+
+++ /dev/null
-/*
-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 <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-// 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(
- }
-
-}
+++ /dev/null
-
-#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