static void child(int sock) { nvlist_t *nvl; nvl = nvlist_create(0); nvlist_add_bool(nvl, "nvlist/bool/true", true); nvlist_add_bool(nvl, "nvlist/bool/false", false); nvlist_add_number(nvl, "nvlist/number/0", 0); nvlist_add_number(nvl, "nvlist/number/1", 1); nvlist_add_number(nvl, "nvlist/number/-1", -1); nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX); nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN); nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX); nvlist_add_string(nvl, "nvlist/string/", ""); nvlist_add_string(nvl, "nvlist/string/x", "x"); nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"); nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO); nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1); nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")); nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl); nvlist_send(sock, nvl); nvlist_destroy(nvl); }
nvlist_t * nvlist_xfer(int sock, nvlist_t *nvl, int flags) { if (nvlist_send(sock, nvl) < 0) { nvlist_destroy(nvl); return (NULL); } nvlist_destroy(nvl); return (nvlist_recv(sock, flags)); }
static int u_sysctl_do_sysctl(struct nvlist *nvl, int ns, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) { nvlist_t *nvl_resp = NULL; int retval = 0; int r_errno; const char *rbuf; size_t r_len; /* XXX Eventually this should be in a sysctl transaction struct */ int shm_fd = -1; char *shm_mem = NULL; size_t shm_len = 0; char shm_path[128]; /* Setup request and response buffer information */ /* * If the requested size is provided and it's greater than the * maximum size allowed, we'll flip to using shm */ if (oldlenp != NULL && *oldlenp >= U_SYSCTL_MAX_REQ_BUF_LEN) { /* Construct a shm path */ /* XXX should make this less guessable */ snprintf(shm_path, 128, "/sysctl.%ld", (long) arc4random()); /* Open it */ shm_fd = shm_open(shm_path, O_CREAT | O_RDWR, 0640); if (shm_fd < 0) { warn("shm_open (%s)", shm_path); retval = -1; goto done; } /* * Calculate a mmap size that's a multiple of * the system page length. */ shm_len = round_page(*oldlenp); /* make it that big! */ if (ftruncate(shm_fd, shm_len) < 0) { warn("ftruncate"); goto done; } /* mmap it */ shm_mem = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, 0, shm_fd, 0); if (shm_mem == NULL) { warn("mmap"); goto done; } /* add the shm path to the outbound request */ nvlist_add_string(nvl, "sysctl_respbuf_shm_path", shm_path); nvlist_add_number(nvl, "sysctl_respbuf_shm_len", shm_len); } /* * Writing a value may pass in a NULL oldlenp, so only conditionally * send it. */ if (oldlenp != NULL) nvlist_add_number(nvl, "sysctl_respbuf_len", *oldlenp); if (newlen > 0) { nvlist_add_binary(nvl, "sysctl_reqbuf", newp, newlen); } /* Send command */ if (nvlist_send(ns, nvl) < 0) { warn("nvlist_send"); retval = -1; goto done; } /* Read response */ nvl_resp = nvlist_recv(ns); if (nvl_resp == NULL) { warn("nvlist_recv"); retval = -1; goto done; } if (! nvlist_exists_number(nvl_resp, "sysctl_errno")) { fprintf(stderr, "response: no errno?\n"); goto done; } r_errno = (int) nvlist_get_number(nvl_resp, "sysctl_errno"); /* XXX validate r_len versus oldlenp */ if (nvlist_exists_binary(nvl_resp, "sysctl_respbuf")) { rbuf = nvlist_get_binary(nvl_resp, "sysctl_respbuf", &r_len); memcpy(oldp, rbuf, r_len); } else if (shm_mem != NULL) { memcpy(oldp, shm_mem, r_len); r_len = nvlist_get_number(nvl_resp, "sysctl_respbuf_shm_len"); } else if (nvlist_exists_number(nvl_resp, "sysctl_respbuf_len")) { r_len = nvlist_get_number(nvl_resp, "sysctl_respbuf_len"); } else { r_len = 0; } if (oldlenp != NULL) *oldlenp = r_len; if (r_errno == 0) { retval = 0; } else { retval = -1; errno = r_errno; } done: if (shm_mem != NULL) munmap(shm_mem, shm_len); if (shm_fd != -1) { close(shm_fd); shm_unlink(shm_path); } if (nvl_resp) nvlist_destroy(nvl_resp); return (retval); }
int main(int argc, char *argv[]) { int fd[2]; socketpair(PF_UNIX, SOCK_STREAM, 0, fd); int kq = kqueue(); struct kevent ke; memset(&ke, 0, sizeof(ke)); EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &ke, 1, NULL, 0, NULL); memset(&ke, 0, sizeof(ke)); EV_SET(&ke, fd[1], EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &ke, 1, NULL, 0, NULL); signal(SIGWINCH, resize); nvlist_t *nvl = NULL; for (;;) { if (res) { struct winsize size; ioctl(1, TIOCGWINSZ, &size); nvl = nvlist_create(0); nvlist_add_string(nvl, "type", "resize"); nvlist_add_number(nvl, "rows", size.ws_row); nvlist_add_number(nvl, "cols", size.ws_col); if (nvlist_send(fd[0], nvl) < 0) err(1, "nvlist_send()"); nvlist_destroy(nvl); res = 0; } memset(&ke, 0, sizeof(ke)); int i = kevent(kq, NULL, 0, &ke, 1, NULL); if (i == -1) { if (errno == EINTR) continue; err(1, "kevent()"); } else if (i == 0) continue; if (ke.ident == fd[0]) { nvl = nvlist_recv(fd[0]); if (nvl == NULL) err(1, "nvlist_recv()"); const char *type = nvlist_get_string(nvl, "type"); if (strcmp(type, "ack") == 0) { int ok = nvlist_get_bool(nvl, "ok"); printf("received ack, ok?: %s\n", ok ? "true" : "false"); } nvlist_destroy(nvl); } else if (ke.ident == fd[1]) { nvl = nvlist_recv(fd[1]); if (nvl == NULL) err(1, "nvlist_recv()"); const char *type = nvlist_get_string(nvl, "type"); if (strcmp(type, "resize") == 0) { int rows = nvlist_get_number(nvl, "rows"); int cows = nvlist_get_number(nvl, "cols"); printf("got resize signal. new size: %d %d\n", rows, cows); } nvlist_destroy(nvl); nvl = nvlist_create(0); nvlist_add_string(nvl, "type", "ack"); nvlist_add_bool(nvl, "ok", 1); if (nvlist_send(fd[1], nvl) < 0) err(1, "nvlist_send()"); nvlist_destroy(nvl); } } }
/* * This function creates sandboxes on-demand whoever has access to it via * 'sock' socket. Function sends two descriptors to the caller: process * descriptor of the sandbox and socket pair descriptor for communication * between sandbox and its owner. */ static void zygote_main(int sock) { int error, fd, flags, procfd; int chanfd[2]; nvlist_t *nvlin, *nvlout; zygote_func_t *func; pid_t pid; assert(sock > STDERR_FILENO); setproctitle("zygote"); if (pjdlog_mode_get() != PJDLOG_MODE_STD) stdnull(); for (fd = STDERR_FILENO + 1; fd < sock; fd++) close(fd); closefrom(sock + 1); for (;;) { nvlin = nvlist_recv(sock); if (nvlin == NULL) { if (errno == ENOTCONN) { /* Casperd exited. */ exit(0); } continue; } func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin, "func"); flags = (int)nvlist_get_number(nvlin, "flags"); nvlist_destroy(nvlin); /* * Someone is requesting a new process, create one. */ procfd = -1; chanfd[0] = -1; chanfd[1] = -1; error = 0; if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, chanfd) == -1) { error = errno; goto send; } pid = pdfork(&procfd, 0); switch (pid) { case -1: /* Failure. */ error = errno; break; case 0: /* Child. */ close(sock); close(chanfd[0]); func(chanfd[1]); /* NOTREACHED */ exit(1); default: /* Parent. */ close(chanfd[1]); break; } send: nvlout = nvlist_create(0); if (error != 0) { nvlist_add_number(nvlout, "error", (uint64_t)error); if (chanfd[0] >= 0) close(chanfd[0]); if (procfd >= 0) close(procfd); } else { nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]); nvlist_move_descriptor(nvlout, "procfd", procfd); } (void)nvlist_send(sock, nvlout); nvlist_destroy(nvlout); } /* NOTREACHED */ }