summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2004-05-19 16:35:30 +0000
committerStef Walter <stef@memberwebs.com>2004-05-19 16:35:30 +0000
commit298e1a85181102bde3aed73f73a34fe81f7de66a (patch)
treecbdb94d3c824a34f299afc8ccfbe8f89f89cb07f
parentd86ba2f5a45fd70e6503ba516eea9386bc176e22 (diff)
Create /dev/null before opening kernel interfaces if it doesn't exist
-rw-r--r--srcx/jkill.c477
-rw-r--r--srcx/jps.c198
-rw-r--r--srcx/jstart.c150
-rw-r--r--srcx/util.c662
-rw-r--r--srcx/util.h4
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)
diff --git a/srcx/jps.c b/srcx/jps.c
index c34aa41..6f8e4db 100644
--- a/srcx/jps.c
+++ b/srcx/jps.c
@@ -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 */