summaryrefslogtreecommitdiff
path: root/srcx/util.c
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 /srcx/util.c
parentd86ba2f5a45fd70e6503ba516eea9386bc176e22 (diff)
Create /dev/null before opening kernel interfaces if it doesn't exist
Diffstat (limited to 'srcx/util.c')
-rw-r--r--srcx/util.c662
1 files changed, 358 insertions, 304 deletions
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);
}