diff options
| author | Stef Walter <stef@memberwebs.com> | 2004-05-19 16:35:30 +0000 | 
|---|---|---|
| committer | Stef Walter <stef@memberwebs.com> | 2004-05-19 16:35:30 +0000 | 
| commit | 298e1a85181102bde3aed73f73a34fe81f7de66a (patch) | |
| tree | cbdb94d3c824a34f299afc8ccfbe8f89f89cb07f /srcx | |
| parent | d86ba2f5a45fd70e6503ba516eea9386bc176e22 (diff) | |
Create /dev/null before opening kernel interfaces if it doesn't exist
Diffstat (limited to 'srcx')
| -rw-r--r-- | srcx/jkill.c | 477 | ||||
| -rw-r--r-- | srcx/jps.c | 198 | ||||
| -rw-r--r-- | srcx/jstart.c | 150 | ||||
| -rw-r--r-- | srcx/util.c | 662 | ||||
| -rw-r--r-- | srcx/util.h | 4 | 
5 files changed, 778 insertions, 713 deletions
| diff --git a/srcx/jkill.c b/srcx/jkill.c index 7125350..4311ed8 100644 --- a/srcx/jkill.c +++ b/srcx/jkill.c @@ -63,7 +63,7 @@  #endif  /* The timeout to wait between kills */ -#define		DEFAULT_TIMEOUT		3 +#define        DEFAULT_TIMEOUT        3  int g_timeout = DEFAULT_TIMEOUT;  int g_quiet = 0;        /* Supress warnings */ @@ -84,15 +84,15 @@ static void usage_jail(const char* name);  int main(int argc, char* argv[])  { -	int r, jid; -	int ret = 0; -	pid_t child; +    int r, jid; +    int ret = 0; +    pid_t child;      /*       * When running in a jail we do things slightly       * differently, and accept different args       */ -	if(running_in_jail()) +    if(running_in_jail())      {          parse_jail_opts(argc, argv); @@ -103,8 +103,8 @@ int main(int argc, char* argv[])          if(daemon(0, 1) == -1)              err(1, "couldn't disconnect from console"); -   	  	r = kill_jail(argv[0]); -   	  	exit(r); +        r = kill_jail(argv[0]); +        exit(r);      }      else @@ -114,54 +114,54 @@ int main(int argc, char* argv[])          argc -= optind;          argv += optind; -    	/* For each jail */ -    	for(; argc > 0; argc--, argv++) -    	{ -    		jid = translate_jail_name(argv[0]); -    		if(jid == -1) -    		{ -    			warnx("unknown jail host name: %s", argv[0]); -    			ret = 1; -    			continue; -    		} - -    		/* -    		 * We fork and the child goes into the jail and -    		 * does the dirty work. Unless in debug mode where +        /* For each jail */ +        for(; argc > 0; argc--, argv++) +        { +            jid = translate_jail_name(argv[0]); +            if(jid == -1) +            { +                warnx("unknown jail host name: %s", argv[0]); +                ret = 1; +                continue; +            } + +            /* +             * We fork and the child goes into the jail and +             * does the dirty work. Unless in debug mode where               * we just do one jail. -         	 */ +              */  #ifdef _DEBUG -        	switch((child = fork())) -    	    { -    	    /* Error condition */ -    	    case -1: -    	    	err(1, "couldn't fork child process"); -    	    	break; - -    	    /* The child */ -    	    case 0: +            switch((child = fork())) +            { +            /* Error condition */ +            case -1: +                err(1, "couldn't fork child process"); +                break; + +            /* The child */ +            case 0:  #endif                  if(jail_attach(jid) == -1)                      err(1, "couldn't attach to jail"); -    	     	r = kill_jail(argv[0]); -    	     	exit(r); +                 r = kill_jail(argv[0]); +                 exit(r);  #ifdef _DEBUG -    	     	break; +                 break; -    	    /* The parent */ -    	    default: -    	    	if(waitpid(child, &r, 0) == -1) -    	     		err(1, "error waiting for child process"); +            /* The parent */ +            default: +                if(waitpid(child, &r, 0) == -1) +                     err(1, "error waiting for child process"); -    	    	if(WEXITSTATUS(r) != 0) -    	    		ret = WEXITSTATUS(r); -    	    	break; -    	    }; +                if(WEXITSTATUS(r) != 0) +                    ret = WEXITSTATUS(r); +                break; +            };  #endif -    		argc--; -    		argv++; +            argc--; +            argv++;          }          return ret; @@ -181,7 +181,7 @@ static void parse_jail_opts(int argc, char* argv[])          g_verbose = 1;          g_force = 1;          g_usescripts = 1; -	g_restart = 0; +        g_restart = 0;      }      else if(strcmp(argv[0], "reboot")) @@ -202,25 +202,25 @@ static void parse_jail_opts(int argc, char* argv[])          return;      } -	while((ch = getopt(argc, argv, "dk:lnqp")) != -1) -	{ -		switch(ch) -		{ -		case 'd': +    while((ch = getopt(argc, argv, "dk:lnqp")) != -1) +    { +        switch(ch) +        { +        case 'd':          case 'k':          case 'l':          case 'n':          case 'q':          case 'p':              warnx("the '-%c' option is not supported from inside a jail", (char)ch); -			break; +            break; -		case '?': -		default: -			usage_jail(t); +        case '?': +        default: +            usage_jail(t);              break; -		} -	} +        } +    }      argc -= optind;      argv += optind; @@ -233,224 +233,223 @@ static void parse_host_opts(int argc, char* argv[])  {      int ch; -	while((ch = getopt(argc, argv, "fhkqrt:v")) != -1) -	{ -		switch(ch) -		{ -		case 'f': -			g_force = 1; -			break; - -		case 'h': -			/* dummy for compatibility with killjail */ -			warnx("the '-h' option has been depreciated"); -			break; - -		case 'k': -			g_usescripts = 0; -			break; - -		case 'q': -			g_quiet = 1; -			g_verbose = 0; -			break; - -		case 'r': -			g_restart = 1; -			break; - -		/* Timeout to use between kills */ -		case 't': -			g_timeout = atoi(optarg); -			if(g_timeout <= 0) -				errx(2, "invalid timeout argument: %s", optarg); -			break; - -		case 'v': -			g_verbose = 1; -			g_quiet = 0; -			break; - -		case '?': -		default: -			usage(); +    while((ch = getopt(argc, argv, "fhkqrt:v")) != -1) +    { +        switch(ch) +        { +        case 'f': +            g_force = 1;              break; -		} -	} -	if(!g_usescripts && g_restart) -		usage(); +        case 'h': +            /* dummy for compatibility with killjail */ +            warnx("the '-h' option has been depreciated"); +            break; + +        case 'k': +            g_usescripts = 0; +            break; -	argc -= optind; -	argv += optind; +        case 'q': +            g_quiet = 1; +            g_verbose = 0; +            break; + +        case 'r': +            g_restart = 1; +            break; + +        /* Timeout to use between kills */ +        case 't': +            g_timeout = atoi(optarg); +            if(g_timeout <= 0) +                errx(2, "invalid timeout argument: %s", optarg); +            break; + +        case 'v': +            g_verbose = 1; +            g_quiet = 0; +            break; + +        case '?': +        default: +            usage(); +            break; +        } +    } + +    if(!g_usescripts && g_restart) +        usage(); + +    argc -= optind; +    argv += optind;      if(argc <= 0)          usage();  }  #define SHUTDOWN_SCRIPT "/etc/rc.shutdown" -static char* SHUTDOWN_ARGS[] = {	_PATH_BSHELL, SHUTDOWN_SCRIPT }; +static char* SHUTDOWN_ARGS[] = {    _PATH_BSHELL, SHUTDOWN_SCRIPT };  #define START_SCRIPT "/etc/rc" -static char* START_ARGS[] = {	_PATH_BSHELL, START_SCRIPT }; +static char* START_ARGS[] = {    _PATH_BSHELL, START_SCRIPT };  static int kill_jail(const char* jail)  { -	kvm_t* kd = NULL; -	char errbuf[_POSIX2_LINE_MAX]; -	int pass = 0; -	int timeout = 0; -	int ret = 0; -	int cmdargs = JAIL_RUN_CONSOLE; - -	/* Open the kernel interface */ -	kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, -			   O_RDONLY, errbuf); -	if(kd == NULL) -		errx(1, "couldn't connect to kernel: %s", errbuf); - -	if(g_verbose) -		cmdargs |= JAIL_RUN_STDERR; - -	/* -	 * Multiple passes are used to do different things. -	 * Each time the jails processes are listed. -	 */ -	while(1) -	{ -		while(timeout > 0) -		{ -			sleep(1); -			timeout--; - -			if(!check_running_processes(kd)) -				goto done; -		} - -		switch(pass) -		{ -		/* First pass is an orderly shutdown */ -		case 0: - -			/* Check if we have an executable shutdown script */ -			if(g_usescripts && check_jail_command(jail, SHUTDOWN_SCRIPT)) -				run_jail_command(jail, SHUTDOWN_ARGS[0], SHUTDOWN_ARGS, cmdargs); - -			break; - -		/* Okay now quit all processes in jail */ -		case 1: -			kill_jail_processes(kd, SIGTERM); -			timeout = g_timeout; -			break; - -		/* ... and again ... */ -		case 2: -			kill_jail_processes(kd, SIGTERM); -			timeout = g_timeout; -			break; - -		/* Okay now we force kill the processes if necessary */ -		case 3: - -			if(g_force) -			{ -				/* If we get here, jailer looks like it's really irresponsive */ -				if(!g_quiet) -					warnx("%s: jail won't stop. forcing jail termination...", jail); - -				kill_jail_processes(kd, SIGKILL); -				timeout = g_timeout; -			} - -			break; - -		case 4: - -			/* And if that didn't do it, well then give up */ -			if(!g_quiet) -				warnx("%s: couldn't stop jail, processes wouldn't die", jail); - -			ret = 1; -			goto done; -		} - -		pass++; - -		if(!check_running_processes(kd)) -			goto done; -	} +    kvm_t* kd = NULL; +    char errbuf[_POSIX2_LINE_MAX]; +    int pass = 0; +    int timeout = 0; +    int ret = 0; +    int cmdargs = JAIL_RUN_CONSOLE; + +    /* Open the kernel interface */ +    kd = open_kvm_handle(jail, errbuf); +    if(kd == NULL) +        errx(1, "couldn't connect to kernel: %s", errbuf); + +    if(g_verbose) +        cmdargs |= JAIL_RUN_STDERR; + +    /* +     * Multiple passes are used to do different things. +     * Each time the jails processes are listed. +     */ +    while(1) +    { +        while(timeout > 0) +        { +            sleep(1); +            timeout--; + +            if(!check_running_processes(kd)) +                goto done; +        } + +        switch(pass) +        { +        /* First pass is an orderly shutdown */ +        case 0: + +            /* Check if we have an executable shutdown script */ +            if(g_usescripts && check_jail_command(jail, SHUTDOWN_SCRIPT)) +                run_jail_command(jail, SHUTDOWN_ARGS[0], SHUTDOWN_ARGS, cmdargs); + +            break; + +        /* Okay now quit all processes in jail */ +        case 1: +            kill_jail_processes(kd, SIGTERM); +            timeout = g_timeout; +            break; + +        /* ... and again ... */ +        case 2: +            kill_jail_processes(kd, SIGTERM); +            timeout = g_timeout; +            break; + +        /* Okay now we force kill the processes if necessary */ +        case 3: + +            if(g_force) +            { +                /* If we get here, jailer looks like it's really irresponsive */ +                if(!g_quiet) +                    warnx("%s: jail won't stop. forcing jail termination...", jail); + +                kill_jail_processes(kd, SIGKILL); +                timeout = g_timeout; +            } + +            break; + +        case 4: + +            /* And if that didn't do it, well then give up */ +            if(!g_quiet) +                warnx("%s: couldn't stop jail, processes wouldn't die", jail); + +            ret = 1; +            goto done; +        } + +        pass++; + +        if(!check_running_processes(kd)) +            goto done; +    }  done: -	if(g_restart) -	{ -		/* Check if we have an executable shutdown script */ -		if(check_jail_command(jail, START_SCRIPT)) -			run_jail_command(jail, START_ARGS[0], START_ARGS, cmdargs); -	} +    if(g_restart) +    { +        /* Check if we have an executable shutdown script */ +        if(check_jail_command(jail, START_SCRIPT)) +            run_jail_command(jail, START_ARGS[0], START_ARGS, cmdargs); +    } -	if(kd != NULL) -		kvm_close(kd); +    if(kd != NULL) +        kvm_close(kd); -	return ret; +    return ret;  }  static void kill_jail_processes(kvm_t* kd, int sig)  { -	struct kinfo_proc* kp; -	int nentries, i; -	pid_t cur; - -	cur = getpid(); - -	/* Get a process listing */ -	if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) -		errx(1, "couldn't list processes: %s", kvm_geterr(kd)); - -	/* Okay now loop and look at each process' jail */ -	for(i = 0; i < nentries; i++) -	{ -		if(kp[i].ki_pid == cur) -			continue; - -		if(kill(kp[i].ki_pid, sig) == -1) -		{ -			if(errno != ESRCH) -				errx(1, "couldn't signal process: %d", (int)kp[i].ki_pid); -		} -	} +    struct kinfo_proc* kp; +    int nentries, i; +    pid_t cur; + +    cur = getpid(); + +    /* Get a process listing */ +    if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) +        errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + +    /* Okay now loop and look at each process' jail */ +    for(i = 0; i < nentries; i++) +    { +        if(kp[i].ki_pid == cur) +            continue; + +        if(kill(kp[i].ki_pid, sig) == -1) +        { +            if(errno != ESRCH) +                errx(1, "couldn't signal process: %d", (int)kp[i].ki_pid); +        } +    }  }  static int check_running_processes(kvm_t* kd)  { -	struct kinfo_proc* kp; -	int nentries, i; -	pid_t cur; +    struct kinfo_proc* kp; +    int nentries, i; +    pid_t cur; -	cur = getpid(); +    cur = getpid(); -	/* Get a process listing */ -	if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) -		errx(1, "couldn't list processes: %s", kvm_geterr(kd)); +    /* Get a process listing */ +    if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) +        errx(1, "couldn't list processes: %s", kvm_geterr(kd)); -	if(nentries != 1) -		return 1; +    if(nentries != 1) +        return 1; -	/* Okay now loop and look at each process' jail */ -	for(i = 0; i < nentries; i++) -	{ -		if(kp[i].ki_pid != cur) -			return 1; -	} +    /* Okay now loop and look at each process' jail */ +    for(i = 0; i < nentries; i++) +    { +        if(kp[i].ki_pid != cur) +            return 1; +    } -	return 0; +    return 0;  }  static void usage()  { -	fprintf(stderr, "usage: jkill [-fkqv] [-t timeout] jail ...\n"); -	fprintf(stderr, "       jkill -r [-fqv] [-t timeout] jail ...\n"); -	exit(2); +    fprintf(stderr, "usage: jkill [-fkqv] [-t timeout] jail ...\n"); +    fprintf(stderr, "       jkill -r [-fqv] [-t timeout] jail ...\n"); +    exit(2);  }  static void usage_jail(const char* name) @@ -61,117 +61,125 @@ static void run_jail_ps(int argc, char* argv[]);  int main(int argc, char* argv[])  { -	int ch = 0; -	int simple = 0; -	int jid = 0; - -	while((ch = getopt(argc, argv, "i")) != -1) -	{ -		switch(ch) -		{ -		case 'i': -			simple = 1; -			break; - -		case '?': -		default: -			usage(); -		} -	} - -	argc -= optind; -	argv += optind; - -	/* Make sure we have a jail name or id */ -	if(argc == 0) -		usage(); - -	if(running_in_jail()) -		errx(1, "can't run from inside jail"); - -	/* Translate the jail name into an id if neccessary */ -	jid = translate_jail_name(argv[0]); -	if(jid == -1) -		errx(1, "unknown jail host name: %s", argv[0]); - -	argc--; -	argv++; - -	/* Go into the jail */ -	if(jail_attach(jid) == -1) -		err(1, "couldn't attach to jail"); - -	if(simple) -	{ -		if(argc > 0) -			usage(); - -		print_jail_ids(); -	} - -	else -	{ -		/* This function never returns */ -		run_jail_ps(argc, argv); -	} - -	return 0; +    int ch = 0; +    int simple = 0; +    int jid = 0; + +    while((ch = getopt(argc, argv, "i")) != -1) +    { +        switch(ch) +        { +        case 'i': +            simple = 1; +            break; + +        case '?': +        default: +            usage(); +        } +    } + +    argc -= optind; +    argv += optind; + +    /* Make sure we have a jail name or id */ +    if(argc == 0) +        usage(); + +    if(running_in_jail()) +        errx(1, "can't run from inside jail"); + +    /* Translate the jail name into an id if neccessary */ +    jid = translate_jail_name(argv[0]); +    if(jid == -1) +        errx(1, "unknown jail host name: %s", argv[0]); + +    argc--; +    argv++; + +    /* Go into the jail */ +    if(jail_attach(jid) == -1) +        err(1, "couldn't attach to jail"); + +    if(simple) +    { +        if(argc > 0) +            usage(); + +        print_jail_ids(); +    } + +    else +    { +        /* This function never returns */ +        run_jail_ps(argc, argv); +    } + +    return 0;  }  static void usage()  { -	fprintf(stderr, "usage: jps [-i] jail [ ps_options ... ]\n"); -	exit(2); +    fprintf(stderr, "usage: jps [-i] jail [ ps_options ... ]\n"); +    exit(2);  }  static void run_jail_ps(int argc, char* argv[])  { -	char** args; -	int i; +    char errbuf[_POSIX2_LINE_MAX]; +    char** args; +    kvm_t kd; +    int i; -	if(!check_jail_command(NULL, "/bin/ps")) -		exit(1); +    if(!check_jail_command(NULL, "/bin/ps")) +        exit(1); -	/* -	 * TODO: We need to purge down the environment here. -	 * If the jail is in any way malicious or compromised -	 * then it could have replaced /bin/ps which we run... -	 */ +    /* Make sure we can use kvm functionality here */ +    kd = open_kvm_handle(NULL, errbuf); +    if(kd == NULL) +        errx(1, "couldn't connect to kernel: %s", errbuf); -	args = (char**)alloca(sizeof(char*) * (argc + 2)); -	args[0] = "ps"; +    kvm_close(kd); -	for(i = 0; i < argc; i++) -		args[i + 1] = argv[i]; +    /* +     * TODO: We need to purge down the environment here. +     * If the jail is in any way malicious or compromised +     * then it could have replaced /bin/ps which we run... +     */ -  args[i + 1] = NULL; +    args = (char**)alloca(sizeof(char*) * (argc + 2)); +    args[0] = "ps"; -  run_jail_command(NULL, "/bin/ps", args, JAIL_RUN_NOFORK); +    for(i = 0; i < argc; i++) +        args[i + 1] = argv[i]; + +    args[i + 1] = NULL; + +    run_jail_command(NULL, "/bin/ps", args, JAIL_RUN_NOFORK);  }  static void print_jail_ids()  { -	kvm_t* kd; -	int nentries, i; -	struct kinfo_proc* kp; -	char errbuf[_POSIX2_LINE_MAX]; - -	/* Open kernel interface */ -	kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf); -	if(kd == NULL) -		errx(1, "couldn't connect to kernel: %s", errbuf); - -	/* Get all processes and print the pids */ -	if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) -		errx(1, "couldn't list processes: %s", kvm_geterr(kd)); - -	for(i = 0; i < nentries; i++) -	{ -		if(kp[i].ki_pid != getpid()) -			printf("%d ", (int)(kp[i].ki_pid)); -	} - -	fputc('\n', stdout); -	kvm_close(kd); +    kvm_t* kd; +    int nentries, i; +    struct kinfo_proc* kp; +    char errbuf[_POSIX2_LINE_MAX]; + +    /* Open kernel interface */ +    kd = open_kvm_handle(NULL, errbuf); +    if(kd == NULL) +        errx(1, "couldn't connect to kernel: %s", errbuf); + +    /* Get all processes and print the pids */ +    if((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == 0) +        errx(1, "couldn't list processes: %s", kvm_geterr(kd)); + +    for(i = 0; i < nentries; i++) +    { +        if(kp[i].ki_pid != getpid()) +            printf("%d ", (int)(kp[i].ki_pid)); +    } + +    fputc('\n', stdout); +    kvm_close(kd);  } - diff --git a/srcx/jstart.c b/srcx/jstart.c index 288b444..770d41f 100644 --- a/srcx/jstart.c +++ b/srcx/jstart.c @@ -61,89 +61,91 @@  #endif  #define START_SCRIPT "/etc/rc" -static char* START_ARGS[] = {	_PATH_BSHELL, START_SCRIPT }; +static char* START_ARGS[] = {    _PATH_BSHELL, START_SCRIPT };  static void usage();  int main(int argc, char* argv[])  { -	int ch, jid; -	struct jail j; -	int printjid = 0; -  struct in_addr in; - -	while((ch = getopt(argc, argv, "i")) != -1) -	{ -		switch(ch) -		{ -		case 'i': -			printjid = 1; -			break; - -		case '?': -		default: -			usage(); -		} -	} - -	argc -= optind; -	argv += optind; - -	if(argc < 3) -		usage(); - -	if(getuid() != 0) -		errx(1, "must be run as root"); - -	if(chdir(argv[0]) != 0) -		err(1, "couldn't change to jail directory: %s", argv[0]); - -	if(inet_aton(argv[2], &in) != 1) -		errx(1, "invalid ip address: %s", argv[2]); - -	memset(&j, 0, sizeof(j)); -	j.version = 0; -	j.path = argv[0]; -	j.hostname = argv[1]; -	j.ip_number = ntohl(in.s_addr); - -	/* Here's where we actually go into the jail */ -	jid = jail(&j); -	if(jid == -1) -		err(1, "couldn't create jail"); - -	if(printjid) -	{ -		printf("%d\n", jid); -		fflush(stdout); -	} - -	argc -= 3; -	argv += 3; - -	if(argc == 0) -	{ -		if(!check_jail_command(NULL, START_SCRIPT)) -			exit(1); - -		run_jail_command(NULL, START_ARGS[0], START_ARGS, JAIL_RUN_CONSOLE | 	JAIL_RUN_STDOUT); -	} - -	else -	{ -		if(!check_jail_command(NULL, argv[0])) -			exit(1); - -		run_jail_command(NULL, argv[0], argv, JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); -	} - -	return 0; +    int ch, jid; +    struct jail j; +    int printjid = 0; +    struct in_addr in; + +    while((ch = getopt(argc, argv, "i")) != -1) +    { +        switch(ch) +        { +        case 'i': +            printjid = 1; +            break; + +        case '?': +        default: +            usage(); +        } +    } + +    argc -= optind; +    argv += optind; + +    if(argc < 3) +        usage(); + +    if(getuid() != 0) +        errx(1, "must be run as root"); + +    if(chdir(argv[0]) != 0) +        err(1, "couldn't change to jail directory: %s", argv[0]); + +    if(inet_aton(argv[2], &in) != 1) +        errx(1, "invalid ip address: %s", argv[2]); + +    memset(&j, 0, sizeof(j)); +    j.version = 0; +    j.path = argv[0]; +    j.hostname = argv[1]; +    j.ip_number = ntohl(in.s_addr); + +    /* Here's where we actually go into the jail */ +    jid = jail(&j); +    if(jid == -1) +        err(1, "couldn't create jail"); + +    if(printjid) +    { +        printf("%d\n", jid); +        fflush(stdout); +    } + +    argc -= 3; +    argv += 3; + +    if(argc == 0) +    { +        if(!check_jail_command(NULL, START_SCRIPT)) +            exit(1); + +        run_jail_command(NULL, START_ARGS[0], START_ARGS, +                         JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); +    } + +    else +    { +        if(!check_jail_command(NULL, argv[0])) +            exit(1); + +        run_jail_command(NULL, argv[0], argv, +                         JAIL_RUN_CONSOLE | JAIL_RUN_STDOUT); +    } + +    return 0;  }  static void usage()  { -	fprintf(stderr, "usage: jstart [-i] path hostname ip-number [command ...]\n"); -	exit(2); +    fprintf(stderr, "usage: jstart [-i] path hostname ip-number [command ...]\n"); +    exit(2);  } diff --git a/srcx/util.c b/srcx/util.c index 1911d2f..8d5e145 100644 --- a/srcx/util.c +++ b/srcx/util.c @@ -61,95 +61,149 @@ extern char** environ;  size_t get_jail_sysctl(struct xprison** ret)  { -	struct xprison* xp; -	size_t len; -	*ret = NULL; +  struct xprison* xp; +  size_t len; +  *ret = NULL;    if(sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) -  	err(1, "couldn't list jails"); +    err(1, "couldn't list jails");  retry: -	if(len <= 0) -		return 0; +  if(len <= 0) +    return 0; -	xp = calloc(len, 1); -	if(xp == NULL) -		err(1, "out of memory"); +  xp = calloc(len, 1); +  if(xp == NULL) +    err(1, "out of memory"); -	if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) -	{ -		if(errno == ENOMEM) -		{ -			free(xp); -			goto retry; -		} +  if(sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) +  { +    if(errno == ENOMEM) +    { +      free(xp); +      goto retry; +    } -		err(1, "couldn't list jails"); -	} +    err(1, "couldn't list jails"); +  } -	if(len < sizeof(*xp) || len % sizeof(*xp) || xp->pr_version != XPRISON_VERSION) -		errx(1, "kernel and userland out of sync"); +  if(len < sizeof(*xp) || len % sizeof(*xp) || xp->pr_version != XPRISON_VERSION) +    errx(1, "kernel and userland out of sync"); -	*ret = xp; -	return len / sizeof(*xp); +  *ret = xp; +  return len / sizeof(*xp);  }  int translate_jail_name(const char* str)  { -	struct xprison* xp = NULL; -	size_t len, i; -	char* e; -	int jid = -1; - -	len = get_jail_sysctl(&xp); -	if(len == 0) -		goto done; - -	jid = strtol(str, &e, 10); - -	/* If it was all a number ... */ -	if(!*e) -	{ -		if(jid <= 0) -			errx(1, "invalid jail id: %s", str); - -		/* Validate the number */ -		for(i = 0; i < len; i++) -		{ -			if(jid == xp[i].pr_id) -				goto done; -		} - -		jid = -1; -	} - -	jid = -1; - -	for(i = 0; i < len; i++) -	{ -		if(strcmp(xp[i].pr_host, str) == 0) -		{ -			jid = xp[i].pr_id; -			break; -		} -	} +  struct xprison* xp = NULL; +  size_t len, i; +  char* e; +  int jid = -1; + +  len = get_jail_sysctl(&xp); +  if(len == 0) +    goto done; + +  jid = strtol(str, &e, 10); + +  /* If it was all a number ... */ +  if(!*e) +  { +    if(jid <= 0) +      errx(1, "invalid jail id: %s", str); + +    /* Validate the number */ +    for(i = 0; i < len; i++) +    { +      if(jid == xp[i].pr_id) +        goto done; +    } + +    jid = -1; +  } + +  jid = -1; + +  for(i = 0; i < len; i++) +  { +    if(strcmp(xp[i].pr_host, str) == 0) +    { +      jid = xp[i].pr_id; +      break; +    } +  }  done: -	if(xp) -		free(xp); +  if(xp) +    free(xp); -	return jid; +  return jid;  } -kvm_t open_kvm_handle(char* errbuf) +kvm_t open_kvm_handle(char* jail, char* errbuf)  { -	/* -	 * Basically the kvm routines won't work in -	 * a jail unless there's a /dev/null device - 	 * for us to use as the file name. If it's -         * missing we have to create it -	 */ +  /* +   * Basically the kvm routines won't work in a jail unless there's +   * a /dev/null device for us to use as the file names. If it's +   * missing we have to create it. +   */ + +  struct stat sb; +  int nodir = 0; +  int nonull = 0; + +  if(stat(_PATH_DEVNULL, &sb) == -1) +  { +    if(errno == ENOTDIR) +    { +      nodir = 1; +      nonull = 1; +    } + +    else if(errno == ENOENT) +    { +      nonull = 1; +    } + +    else +    { +      err(1, "%s%scouldn't stat file: %s", jail ? jail : "", +                  jail ? ": " : "", _PATH_DEVNULL); +    } +  } + +  if(nodir) +  { +    warnx("%s%sthe %s directory doesn't exist in jail. creating...", +         jail ? jail : "", jail ? ": " : "", _PATH_DEV); + +    if(mkdir(_PATH_DEV, 0) == -1 || +       chmod(_PATH_DEV, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) +    { +      warn("%s%scouldn't create %s directory", +           jail ? jail : "", jail ? ": " : "", _PATH_DEV); +      nofile = 0; +    } +  } + +  if(nofile) +  { +    mode_t mode = 0666 | S_IFCHR; +    dev_t dev = makedev(2, 2); + +    warnx("%s%sthe %s device doesn't exist in jail. creating...", +         jail ? jail : "", jail ? ": " : "", _PATH_DEVNULL); + +    if(mknod(_PATH_DEVNULL, mode, dev) == -1) +    { +      warn("%s%scouldn't create %s device", +           jail ? jail : "", jail ? ": " : "", _PATH_DEVNULL); +    } +  } + +  return kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf);  }  /* @@ -161,119 +215,119 @@ kvm_t open_kvm_handle(char* errbuf)  int running_in_jail()  { -	int count; -	kvm_t* kd = 0; -	struct kinfo_proc* kp; -	char errbuf[_POSIX2_LINE_MAX]; -	int	result = -1; +  int count; +  kvm_t* kd = 0; +  struct kinfo_proc* kp; +  char errbuf[_POSIX2_LINE_MAX]; +  int  result = -1; -	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); -	if(kd == NULL) -		errx(1, "couldn't connect to kernel: %s", errbuf); +  kd = open_kvm_handle(NULL, errbuf); +  if(kd == NULL) +    errx(1, "couldn't connect to kernel: %s", errbuf); -	kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &count); -	if(kp == NULL) -		errx(1, "couldn't list processes: %s", kvm_geterr(kd)); +  kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &count); +  if(kp == NULL) +    errx(1, "couldn't list processes: %s", kvm_geterr(kd)); -	result = (kp->ki_flag & P_JAILED) ? 1 : 0; -	kvm_close(kd); +  result = (kp->ki_flag & P_JAILED) ? 1 : 0; +  kvm_close(kd); -	return result; +  return result;  }  int check_jail_command(const char* jail, const char* cmd)  { -	struct stat sb; - -	if(stat(cmd, &sb) == -1) -	{ -		if(errno == EACCES || errno == ELOOP || errno == ENAMETOOLONG || -			 errno == ENOENT || errno == ENOTDIR) -		{ -			warn("%s%scan't execute in jail: %s", jail ? jail : "", -								jail ? ": " : "", cmd); -			return 0; -		} - -		err(1, "%s%scouldn't stat file: %s", jail ? jail : "", -								jail ? ": " : "", cmd); -	} - -	if(!(sb.st_mode & S_IFREG)) -	{ -		warnx("%s%snot a regular file: %s", jail ? jail : "", -								jail ? ": " : "", cmd); -		return 0; -	} - -	if(sb.st_uid != 0) -	{ -		warnx("%s%snot owned by root: %s", jail ? jail : "", -								jail ? ": " : "", cmd); -		return 0; -	} - -	return 1; +  struct stat sb; + +  if(stat(cmd, &sb) == -1) +  { +    if(errno == EACCES || errno == ELOOP || errno == ENAMETOOLONG || +       errno == ENOENT || errno == ENOTDIR) +    { +      warn("%s%scan't execute in jail: %s", jail ? jail : "", +                jail ? ": " : "", cmd); +      return 0; +    } + +    err(1, "%s%scouldn't stat file: %s", jail ? jail : "", +                jail ? ": " : "", cmd); +  } + +  if(!(sb.st_mode & S_IFREG)) +  { +    warnx("%s%snot a regular file: %s", jail ? jail : "", +                jail ? ": " : "", cmd); +    return 0; +  } + +  if(sb.st_uid != 0) +  { +    warnx("%s%snot owned by root: %s", jail ? jail : "", +                jail ? ": " : "", cmd); +    return 0; +  } + +  return 1;  }  int run_overlay_command(const char* jail, const char* cmd, char* env[], -												char* args[]) +                        char* args[])  { -	if(args) -		execve(cmd, args, env); -	else -		execle(cmd, cmd, NULL, env); - -	warn("%s%serror executing: %s: %s", jail ? jail : "", -					jail ? ": " : "", cmd); -	return 0; +  if(args) +    execve(cmd, args, env); +  else +    execle(cmd, cmd, NULL, env); + +  warn("%s%serror executing: %s: %s", jail ? jail : "", +          jail ? ": " : "", cmd); +  return 0;  }  int run_simple_command(const char* jail, const char* cmd, char* env[], -											 char* args[], int opts) +                       char* args[], int opts)  { -	pid_t pid; -	int status = 0; - -	if(opts & JAIL_RUN_NOFORK) -		return run_overlay_command(jail, cmd, env, args); - -	switch((pid = fork())) -	{ -	case -1: -		err(1, "couldn't fork child process"); -		break; - -	/* This is the child here */ -	case 0: -		if(args) -			execve(cmd, args, env); -		else -			execle(cmd, cmd, NULL, env); - -		exit(errno); -		break; - -	/* This is the parent process */ -	default: - -		/* If the processes exited then break out */ -		if(waitpid(pid, &status, 0) == -1) -			err(1, "couldn't wait on child process"); - -		/* Return any status codes */ -		if(WEXITSTATUS(status) != 0) -		{ -			warnx("%s%serror executing: %s: %s", jail ? jail : "", -								jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); -			return 0; -		} - -		break; -	} - -	return 1; +  pid_t pid; +  int status = 0; + +  if(opts & JAIL_RUN_NOFORK) +    return run_overlay_command(jail, cmd, env, args); + +  switch((pid = fork())) +  { +  case -1: +    err(1, "couldn't fork child process"); +    break; + +  /* This is the child here */ +  case 0: +    if(args) +      execve(cmd, args, env); +    else +      execle(cmd, cmd, NULL, env); + +    exit(errno); +    break; + +  /* This is the parent process */ +  default: + +    /* If the processes exited then break out */ +    if(waitpid(pid, &status, 0) == -1) +      err(1, "couldn't wait on child process"); + +    /* Return any status codes */ +    if(WEXITSTATUS(status) != 0) +    { +      warnx("%s%serror executing: %s: %s", jail ? jail : "", +                jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); +      return 0; +    } + +    break; +  } + +  return 1;  }  /* read & write ends of a pipe */ @@ -286,157 +340,157 @@ int run_simple_command(const char* jail, const char* cmd, char* env[],  #define  STDERR  2  int run_dup_command(const char* jail, const char* cmd, char* env[], -										char* args[], int opts) +                    char* args[], int opts)  { -	int outpipe[2]; -	pid_t pid; +  int outpipe[2]; +  pid_t pid; -	/* -	 * Special function to duplicate output of a command to two +  /* +   * Special function to duplicate output of a command to two     * files.     *     * NOTE: Yes, I know this may seem like overkill, but system,     * popen and all those guys would hang with certain rc scripts.     * Those which opened a daemon in the background ('&') but still     * kept their output going to the same stdin/stdout handles. -	 */ - -	/* Create a pipe for the child process */ -	if(pipe(outpipe) < 0) -		return -1; - -	switch(pid = fork()) -	{ -	case -1: -  	err(1, "couldn't fork child process"); -  	break; - -	/* This is the child here */ -	case 0: -		{ -			/* Fix up our end of the pipe */ -			if(dup2(outpipe[WRITE_END], STDOUT) < 0 || -			   dup2(outpipe[WRITE_END], STDERR) < 0) -				exit(errno); - -			/* Okay, now run whatever command it was */ -			if(args) -				execve(cmd, args, env); -			else -				execle(cmd, cmd, NULL, env); - -			/* In case it returns then have to do this to get -			   children to disconnect from stdout */ -			fflush(stdout); -			fclose(stdout); -			close(outpipe[WRITE_END]); - -			exit(errno); -		} -		break; - - -	/* And this is the parent */ -	default: -		{ -			int console = -1; -			int ret; -			int status = 0; -			fd_set readmask; -			char buff[256]; -			struct timeval timeout = { 0, 10000 }; - -			FD_ZERO(&readmask); - -			/* Open the console file and write the header */ -			if(opts & JAIL_RUN_CONSOLE) -				console = open(_PATH_CONSOLE, O_WRONLY | O_APPEND); - -			/* No blocking on the child processes pipe */ -			fcntl(outpipe[READ_END], F_SETFL, fcntl(outpipe[READ_END], F_GETFL, 0) | O_NONBLOCK); - -			/* Loop until the process dies or no more output */ -			while(1) -			{ -				FD_SET(outpipe[READ_END], &readmask); - -				if(select(FD_SETSIZE, &readmask, NULL, NULL, &timeout) == -1) -					err(1, "couldn't select"); - -				if(FD_ISSET(outpipe[READ_END], &readmask)) -				{ -					/* Read text */ -					while((ret = read(outpipe[READ_END], buff, 256)) > 0) -					{ -						if(opts & JAIL_RUN_STDOUT) -							write(STDOUT, buff, ret); - -						if(opts & JAIL_RUN_STDERR) -							write(STDERR, buff, ret); - -						if(console != -1) -							write(console, buff, ret); -					} -				} - -				/* If the processes exited then break out */ -				if(waitpid(pid, &status, WNOHANG) == pid) -					break; - -				/* Or if there's an error or end of file */ -				if(ret == -1 && errno != EAGAIN || ret == 0) -					break; -			} - -			/* Return any status codes */ -			if(WEXITSTATUS(status) != 0) -			{ -				warnx("%s%serror executing: %s: %s", jail ? jail : "", -								jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); -				return 0; -			} - -			/* Clean up */ -			close(outpipe[READ_END]); - -			if(console != -1) -				close(console); -		} -		break; -	} - -	return 1; +   */ + +  /* Create a pipe for the child process */ +  if(pipe(outpipe) < 0) +    return -1; + +  switch(pid = fork()) +  { +  case -1: +    err(1, "couldn't fork child process"); +    break; + +  /* This is the child here */ +  case 0: +    { +      /* Fix up our end of the pipe */ +      if(dup2(outpipe[WRITE_END], STDOUT) < 0 || +         dup2(outpipe[WRITE_END], STDERR) < 0) +        exit(errno); + +      /* Okay, now run whatever command it was */ +      if(args) +        execve(cmd, args, env); +      else +        execle(cmd, cmd, NULL, env); + +      /* In case it returns then have to do this to get +         children to disconnect from stdout */ +      fflush(stdout); +      fclose(stdout); +      close(outpipe[WRITE_END]); + +      exit(errno); +    } +    break; + + +  /* And this is the parent */ +  default: +    { +      int console = -1; +      int ret; +      int status = 0; +      fd_set readmask; +      char buff[256]; +      struct timeval timeout = { 0, 10000 }; + +      FD_ZERO(&readmask); + +      /* Open the console file and write the header */ +      if(opts & JAIL_RUN_CONSOLE) +        console = open(_PATH_CONSOLE, O_WRONLY | O_APPEND); + +      /* No blocking on the child processes pipe */ +      fcntl(outpipe[READ_END], F_SETFL, fcntl(outpipe[READ_END], F_GETFL, 0) | O_NONBLOCK); + +      /* Loop until the process dies or no more output */ +      while(1) +      { +        FD_SET(outpipe[READ_END], &readmask); + +        if(select(FD_SETSIZE, &readmask, NULL, NULL, &timeout) == -1) +          err(1, "couldn't select"); + +        if(FD_ISSET(outpipe[READ_END], &readmask)) +        { +          /* Read text */ +          while((ret = read(outpipe[READ_END], buff, 256)) > 0) +          { +            if(opts & JAIL_RUN_STDOUT) +              write(STDOUT, buff, ret); + +            if(opts & JAIL_RUN_STDERR) +              write(STDERR, buff, ret); + +            if(console != -1) +              write(console, buff, ret); +          } +        } + +        /* If the processes exited then break out */ +        if(waitpid(pid, &status, WNOHANG) == pid) +          break; + +        /* Or if there's an error or end of file */ +        if(ret == -1 && errno != EAGAIN || ret == 0) +          break; +      } + +      /* Return any status codes */ +      if(WEXITSTATUS(status) != 0) +      { +        warnx("%s%serror executing: %s: %s", jail ? jail : "", +                jail ? ": " : "", cmd, strerror(WEXITSTATUS(status))); +        return 0; +      } + +      /* Clean up */ +      close(outpipe[READ_END]); + +      if(console != -1) +        close(console); +    } +    break; +  } + +  return 1;  }  int run_jail_command(const char* jail, const char* cmd, char* args[], int opts)  { -	char* env[5]; -	char* t; -	int j; - -	memset(env, 0, sizeof(env)); - -#define MAKE_ENV_VAR(n)		 											\ -	t = getenv(n);																\ -	if(t != NULL)																	\ -	{																							\ -		env[j] = alloca(strlen(n) + 2 + strlen(t));	\ -		sprintf(env[j], "%s=%s", (char*)(n), t);		\ -		j++;																				\ -	} - -	/* Prepare an environment for the cmd */ -	env[0] = "PATH=" _PATH_STDPATH; -	j = 1; - -	MAKE_ENV_VAR("TERM"); -	MAKE_ENV_VAR("COLUMNS"); -	MAKE_ENV_VAR("LINES"); - -	if(opts & JAIL_RUN_OUTPUT) -		return run_dup_command(jail, cmd, env, args, opts); -	else -		return run_simple_command(jail, cmd, env, args, opts); +  char* env[5]; +  char* t; +  int j; + +  memset(env, 0, sizeof(env)); + +#define MAKE_ENV_VAR(n)                           \ +  t = getenv(n);                                \ +  if(t != NULL)                                  \ +  {                                              \ +    env[j] = alloca(strlen(n) + 2 + strlen(t));  \ +    sprintf(env[j], "%s=%s", (char*)(n), t);    \ +    j++;                                        \ +  } + +  /* Prepare an environment for the cmd */ +  env[0] = "PATH=" _PATH_STDPATH; +  j = 1; + +  MAKE_ENV_VAR("TERM"); +  MAKE_ENV_VAR("COLUMNS"); +  MAKE_ENV_VAR("LINES"); + +  if(opts & JAIL_RUN_OUTPUT) +    return run_dup_command(jail, cmd, env, args, opts); +  else +    return run_simple_command(jail, cmd, env, args, opts);  } diff --git a/srcx/util.h b/srcx/util.h index af07e97..d39c1de 100644 --- a/srcx/util.h +++ b/srcx/util.h @@ -42,9 +42,11 @@  struct xprison;  int translate_jail_name(const char* str); -size_t get_jail_sysctl(struct xprison** ret);  int running_in_jail(); +kvm_t open_kvm_handle(char* jail, char* errbuf); +size_t get_jail_sysctl(struct xprison** ret); +  #define JAIL_RUN_CONSOLE	0x00000001	/* Output stuff to the jail console if available */  #define JAIL_RUN_STDOUT		0x00000002	/* Output to stdout */  #define JAIL_RUN_STDERR		0x00000004	/* Output to stderr */ | 
