diff options
Diffstat (limited to 'sbin/casperd')
-rw-r--r-- | sbin/casperd/Makefile | 17 | ||||
-rw-r--r-- | sbin/casperd/casperd.8 | 132 | ||||
-rw-r--r-- | sbin/casperd/casperd.c | 721 | ||||
-rw-r--r-- | sbin/casperd/zygote.c | 227 | ||||
-rw-r--r-- | sbin/casperd/zygote.h | 40 |
5 files changed, 0 insertions, 1137 deletions
diff --git a/sbin/casperd/Makefile b/sbin/casperd/Makefile deleted file mode 100644 index 93f145c..0000000 --- a/sbin/casperd/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# $FreeBSD$ - -PROG= casperd - -SRCS= casperd.c zygote.c - -LIBADD= casper nv pjdlog util - -MAN= casperd.8 - -CFLAGS+=-I${.CURDIR} -CFLAGS+=-I${.CURDIR}/../../lib/libcapsicum -CFLAGS+=-I${.CURDIR}/../../lib/libcasper -CFLAGS+=-I${.CURDIR}/../../lib/libnv -CFLAGS+=-I${.CURDIR}/../../lib/libpjdlog - -.include <bsd.prog.mk> diff --git a/sbin/casperd/casperd.8 b/sbin/casperd/casperd.8 deleted file mode 100644 index 945b517..0000000 --- a/sbin/casperd/casperd.8 +++ /dev/null @@ -1,132 +0,0 @@ -.\" Copyright (c) 2013 The FreeBSD Foundation -.\" All rights reserved. -.\" -.\" This documentation was written by Pawel Jakub Dawidek under sponsorship -.\" from the FreeBSD Foundation. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd October 26, 2013 -.Dt CASPERD 8 -.Os -.Sh NAME -.Nm casperd -.Nd "Capability Services friendly daemon" -.Sh SYNOPSIS -.Nm -.Op Fl Fhv -.Op Fl l Ar listenqueue -.Op Fl D Ar servconfdir -.Op Fl P Ar pidfile -.Op Fl S Ar sockpath -.Sh DESCRIPTION -The -.Nm -daemon hosts various services that can be accessed through -libcapsicum's capabilities by programs running in sandboxes. -For example it is prohibited to send UDP packets to arbitrary destinations -when operating in capability mode, which makes DNS resolution impossible. -To make it possible the -.Nm -daemon provides the -.Nm system.dns -service that proxies DNS resolution requests through a dedicated, -non-sandboxed process provided by -.Nm . -.Pp -The -.Nm -daemon can be started with the following command line arguments: -.Bl -tag -width ".Fl D Ar servconfdir" -.It Fl D Ar servconfdir -Specify alternative location of the service configuration directory. -The default location is -.Pa /etc/casper/ . -.It Fl F -Start the -.Nm -daemon in the foreground. -By default -.Nm -starts in the background. -.It Fl h -Print the -.Nm -usage message. -.It Fl l Ar listenqueue -Specify depth of socket listen queue for the -.Nm -daemon. -The default queue length is -.Pa SOMAXCONN . -.It Fl P Ar pidfile -Specify alternative location of a file where main process PID will be -stored. -The default location is -.Pa /var/run/casperd.pid . -.It Fl S Ar sockpath -Specify alternative location of the -.Xr unix 4 -domain socket used to connect to the -.Nm -daemon. -The default location is -.Pa /var/run/casper . -.It Fl v -Print or log verbose/debugging information. -This option can be specified multiple times to raise the verbosity -level. -.El -.Sh FILES -.Bl -tag -width ".Pa /var/run/casperd.pid" -compact -.It Pa /etc/casper/ -The configuration directory for -.Nm -services. -.It Pa /var/run/casper -.Xr unix 4 -domain socket used to connect to the -.Nm -daemon. -.It Pa /var/run/casperd.pid -The default location of the -.Nm -PID file. -.El -.Sh EXIT STATUS -The -.Nm -daemon exits 0 on success, and >0 if an error occurs. -.Sh SEE ALSO -.Xr cap_enter 2 , -.Xr libcapsicum 3 , -.Xr pidfile 3 , -.Xr capsicum 4 , -.Xr unix 4 -.Sh AUTHORS -The -.Nm -was implemented by -.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net -under sponsorship from the FreeBSD Foundation. diff --git a/sbin/casperd/casperd.c b/sbin/casperd/casperd.c deleted file mode 100644 index 65da58a..0000000 --- a/sbin/casperd/casperd.c +++ /dev/null @@ -1,721 +0,0 @@ -/*- - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Pawel Jakub Dawidek under sponsorship from - * the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/capsicum.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <sys/nv.h> - -#include <assert.h> -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <libutil.h> -#include <paths.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> - -#include <libcapsicum.h> -#include <libcapsicum_impl.h> -#include <libcasper.h> -#include <libcasper_impl.h> -#include <msgio.h> -#include <pjdlog.h> - -#include "msgio.h" - -#include "zygote.h" - -#define CASPERD_PIDFILE "/var/run/casperd.pid" -#define CASPERD_SERVCONFDIR "/etc/casper" -#define CASPERD_SOCKPATH "/var/run/casper" - -typedef void service_function_t(struct service_connection *, const nvlist_t *, - nvlist_t *); - -struct casper_service { - const char *cs_name; - const char *cs_execpath; - struct service *cs_service; - nvlist_t *cs_attrs; - TAILQ_ENTRY(casper_service) cs_next; -}; - -static TAILQ_HEAD(, casper_service) casper_services = - TAILQ_HEAD_INITIALIZER(casper_services); - -#define SERVICE_IS_CORE(service) ((service)->cs_execpath == NULL) - -static void service_external_execute(int chanfd); - -#define KEEP_ERRNO(work) do { \ - int _serrno; \ - \ - _serrno = errno; \ - work; \ - errno = _serrno; \ -} while (0) - -static struct casper_service * -service_find(const char *name) -{ - struct casper_service *casserv; - - TAILQ_FOREACH(casserv, &casper_services, cs_next) { - if (strcmp(casserv->cs_name, name) == 0) - break; - } - return (casserv); -} - -/* - * Function always consumes the given attrs. - */ -static void -service_register(nvlist_t *attrs) -{ - struct casper_service *casserv; - const char *name; - - PJDLOG_ASSERT(nvlist_exists_string(attrs, "name")); - PJDLOG_ASSERT(nvlist_exists_string(attrs, "execpath") || - (nvlist_exists_number(attrs, "commandfunc") && - nvlist_exists_number(attrs, "limitfunc"))); - - name = nvlist_get_string(attrs, "name"); - PJDLOG_ASSERT(name != NULL); - if (name[0] == '\0') { - pjdlog_error("Unable to register service with an empty name."); - nvlist_destroy(attrs); - return; - } - if (service_find(name) != NULL) { - pjdlog_error("Service \"%s\" is already registered.", name); - nvlist_destroy(attrs); - return; - } - - casserv = malloc(sizeof(*casserv)); - if (casserv == NULL) { - pjdlog_errno(LOG_ERR, "Unable to register service \"%s\"", - name); - nvlist_destroy(attrs); - return; - } - casserv->cs_name = name; - if (nvlist_exists_string(attrs, "execpath")) { - struct stat sb; - - PJDLOG_ASSERT(!nvlist_exists_number(attrs, "commandfunc")); - PJDLOG_ASSERT(!nvlist_exists_number(attrs, "limitfunc")); - - casserv->cs_service = NULL; - - casserv->cs_execpath = nvlist_get_string(attrs, "execpath"); - if (casserv->cs_execpath == NULL || - casserv->cs_execpath[0] == '\0') { - pjdlog_error("Unable to register service with an empty execpath."); - free(casserv); - nvlist_destroy(attrs); - return; - } - if (stat(casserv->cs_execpath, &sb) == -1) { - pjdlog_errno(LOG_ERR, - "Unable to register service \"%s\", problem with executable \"%s\"", - name, casserv->cs_execpath); - free(casserv); - nvlist_destroy(attrs); - return; - } - } else /* if (nvlist_exists_number(attrs, "commandfunc")) */ { - PJDLOG_ASSERT(!nvlist_exists_string(attrs, "execpath")); - - casserv->cs_execpath = NULL; - - casserv->cs_service = service_alloc(name, - (void *)(uintptr_t)nvlist_get_number(attrs, "limitfunc"), - (void *)(uintptr_t)nvlist_get_number(attrs, "commandfunc")); - if (casserv->cs_service == NULL) { - pjdlog_errno(LOG_ERR, - "Unable to register service \"%s\"", name); - free(casserv); - nvlist_destroy(attrs); - return; - } - } - casserv->cs_attrs = attrs; - TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next); - pjdlog_debug(1, "Service %s successfully registered.", - casserv->cs_name); -} - -static bool -casper_allowed_service(const nvlist_t *limits, const char *service) -{ - - if (limits == NULL) - return (true); - - if (nvlist_exists_null(limits, service)) - return (true); - - return (false); -} - -static int -casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits) -{ - const char *name; - int type; - void *cookie; - - cookie = NULL; - while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) { - if (type != NV_TYPE_NULL) - return (EINVAL); - if (!casper_allowed_service(oldlimits, name)) - return (ENOTCAPABLE); - } - - return (0); -} - -static int -casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin, - nvlist_t *nvlout) -{ - struct casper_service *casserv; - const char *servname; - nvlist_t *nvl; - int chanfd, execfd, procfd, error; - - if (strcmp(cmd, "open") != 0) - return (EINVAL); - if (!nvlist_exists_string(nvlin, "service")) - return (EINVAL); - - servname = nvlist_get_string(nvlin, "service"); - - casserv = service_find(servname); - if (casserv == NULL) - return (ENOENT); - - if (!casper_allowed_service(limits, servname)) - return (ENOTCAPABLE); - -#ifdef O_EXEC_WORKING - execfd = open(casserv->cs_execpath, O_EXEC); -#else - execfd = open(casserv->cs_execpath, O_RDONLY); -#endif - if (execfd < -1) { - error = errno; - pjdlog_errno(LOG_ERR, - "Unable to open executable '%s' of service '%s'", - casserv->cs_execpath, casserv->cs_name); - return (error); - } - - if (zygote_clone(service_external_execute, &chanfd, &procfd) == -1) { - error = errno; - close(execfd); - return (error); - } - - nvl = nvlist_create(0); - nvlist_add_string(nvl, "service", casserv->cs_name); - if (nvlist_exists_descriptor(nvlin, "stderrfd")) { - nvlist_move_descriptor(nvl, "stderrfd", - nvlist_take_descriptor(nvlin, "stderrfd")); - } - nvlist_move_descriptor(nvl, "execfd", execfd); - nvlist_move_descriptor(nvl, "procfd", procfd); - if (nvlist_send(chanfd, nvl) == -1) { - error = errno; - pjdlog_errno(LOG_ERR, "Unable to send nvlist"); - nvlist_destroy(nvl); - close(chanfd); - return (error); - } - nvlist_destroy(nvl); - - nvlist_move_descriptor(nvlout, "chanfd", chanfd); - - return (0); -} - -static void -fdswap(int *fd0, int *fd1) -{ - int tmpfd; - - PJDLOG_VERIFY((tmpfd = dup(*fd0)) != -1); - PJDLOG_VERIFY(dup2(*fd1, *fd0) != -1); - PJDLOG_VERIFY(dup2(tmpfd, *fd1) != -1); - close(tmpfd); - tmpfd = *fd0; - *fd0 = *fd1; - *fd1 = tmpfd; -} - -static void -fdmove(int *oldfdp, int newfd) -{ - - if (*oldfdp != newfd) { - PJDLOG_VERIFY(dup2(*oldfdp, newfd) != -1); - close(*oldfdp); - *oldfdp = newfd; - } -} - -static void -fdcloexec(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFD); - PJDLOG_ASSERT(flags != -1); - if ((flags & FD_CLOEXEC) != 0) - PJDLOG_VERIFY(fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) != -1); -} - -static void -service_register_core(void) -{ - nvlist_t *nvl; - - nvl = nvlist_create(0); - nvlist_add_string(nvl, "name", "core.casper"); - nvlist_add_number(nvl, "limitfunc", (uint64_t)(uintptr_t)casper_limit); - nvlist_add_number(nvl, "commandfunc", - (uint64_t)(uintptr_t)casper_command); - service_register(nvl); -} - -static int -setup_creds(int sock) -{ - struct cmsgcred cred; - - if (cred_recv(sock, &cred) == -1) - return (-1); - - if (setgroups((int)cred.cmcred_ngroups, cred.cmcred_groups) == -1) - return (-1); - - if (setgid(cred.cmcred_groups[0]) == -1) - return (-1); - - if (setuid(cred.cmcred_euid) == -1) - return (-1); - - return (0); -} - -static void -service_external_execute(int chanfd) -{ - char *service, *argv[3]; - int stderrfd, execfd, procfd; - nvlist_t *nvl; - - nvl = nvlist_recv(chanfd, 0); - if (nvl == NULL) - pjdlog_exit(1, "Unable to receive nvlist"); - service = nvlist_take_string(nvl, "service"); - PJDLOG_ASSERT(service != NULL); - if (nvlist_exists_descriptor(nvl, "stderrfd")) { - stderrfd = nvlist_take_descriptor(nvl, "stderrfd"); - } else { - stderrfd = open(_PATH_DEVNULL, O_RDWR); - if (stderrfd < 0) - pjdlog_exit(1, "Unable to open %s", _PATH_DEVNULL); - } - execfd = nvlist_take_descriptor(nvl, "execfd"); - procfd = nvlist_take_descriptor(nvl, "procfd"); - nvlist_destroy(nvl); - - /* - * Move all descriptors into right slots. - */ - - if (stderrfd != STDERR_FILENO) { - if (chanfd == STDERR_FILENO) - fdswap(&stderrfd, &chanfd); - else if (execfd == STDERR_FILENO) - fdswap(&stderrfd, &execfd); - else if (procfd == STDERR_FILENO) - fdswap(&stderrfd, &procfd); - fdmove(&stderrfd, STDERR_FILENO); - } - fdcloexec(stderrfd); - - if (chanfd != PARENT_FILENO) { - if (execfd == PARENT_FILENO) - fdswap(&chanfd, &execfd); - else if (procfd == PARENT_FILENO) - fdswap(&chanfd, &procfd); - fdmove(&chanfd, PARENT_FILENO); - } - fdcloexec(chanfd); - - if (execfd != EXECUTABLE_FILENO) { - if (procfd == EXECUTABLE_FILENO) - fdswap(&execfd, &procfd); - fdmove(&execfd, EXECUTABLE_FILENO); - } - fdcloexec(execfd); - - if (procfd != PROC_FILENO) - fdmove(&procfd, PROC_FILENO); - fdcloexec(procfd); - - /* - * Use credentials of the caller process. - */ - setup_creds(chanfd); - - argv[0] = service; - asprintf(&argv[1], "%d", pjdlog_debug_get()); - argv[2] = NULL; - - fexecve(execfd, argv, NULL); - pjdlog_exit(1, "Unable to execute service %s", service); -} - -static void -service_register_external_one(const char *dirpath, int dfd, - const char *filename) -{ - char execpath[FILENAME_MAX]; - nvlist_t *nvl; - ssize_t done; - int fd; - - fd = openat(dfd, filename, O_RDONLY); - if (fd == -1) { - pjdlog_errno(LOG_ERR, "Unable to open \"%s/%s\"", dirpath, - filename); - return; - } - - done = read(fd, execpath, sizeof(execpath)); - if (done == -1) { - pjdlog_errno(LOG_ERR, "Unable to read content of \"%s/%s\"", - dirpath, filename); - close(fd); - return; - } - close(fd); - if (done == sizeof(execpath)) { - pjdlog_error("Executable path too long in \"%s/%s\".", dirpath, - filename); - return; - } - execpath[done] = '\0'; - while (done > 0) { - if (execpath[--done] == '\n') - execpath[done] = '\0'; - } - - nvl = nvlist_create(0); - nvlist_add_string(nvl, "name", filename); - nvlist_add_string(nvl, "execpath", execpath); - if (nvlist_error(nvl) != 0) { - pjdlog_common(LOG_ERR, 0, nvlist_error(nvl), - "Unable to allocate attributes for service \"%s/%s\"", - dirpath, filename); - nvlist_destroy(nvl); - return; - } - - service_register(nvl); - /* service_register() consumed nvl. */ -} - -static uint8_t -file_type(int dfd, const char *filename) -{ - struct stat sb; - - if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) { - pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename); - return (DT_UNKNOWN); - } - return (IFTODT(sb.st_mode)); -} - -static void -service_register_external(const char *dirpath) -{ - DIR *dirp; - struct dirent *dp; - int dfd; - - dirp = opendir(dirpath); - if (dirp == NULL) { - pjdlog_errno(LOG_WARNING, "Unable to open \"%s\"", dirpath); - return; - } - dfd = dirfd(dirp); - PJDLOG_ASSERT(dfd >= 0); - while ((dp = readdir(dirp)) != NULL) { - dp->d_type = file_type(dfd, dp->d_name); - /* We are only interested in regular files, skip the rest. */ - if (dp->d_type != DT_REG) { - pjdlog_debug(1, - "File \"%s/%s\" is not a regular file, skipping.", - dirpath, dp->d_name); - continue; - } - service_register_external_one(dirpath, dfd, dp->d_name); - } - closedir(dirp); -} - -static void -casper_accept(int lsock) -{ - struct casper_service *casserv; - struct service_connection *sconn; - int sock; - - sock = accept(lsock, NULL, NULL); - if (sock == -1) { - pjdlog_errno(LOG_ERR, "Unable to accept casper connection"); - return; - } - casserv = service_find("core.casper"); - PJDLOG_ASSERT(casserv != NULL); - - sconn = service_connection_add(casserv->cs_service, sock, NULL); - if (sconn == NULL) { - close(sock); - return; - } -} - -static void -main_loop(int lqlen, const char *sockpath, struct pidfh *pfh) -{ - fd_set fds; - struct sockaddr_un sun; - struct casper_service *casserv; - struct service_connection *sconn, *sconntmp; - int lsock, sock, maxfd, ret; - mode_t oldumask; - - lsock = socket(AF_UNIX, SOCK_STREAM, 0); - if (lsock == -1) - pjdlog_exit(1, "Unable to create socket"); - - (void)unlink(sockpath); - - bzero(&sun, sizeof(sun)); - sun.sun_family = AF_UNIX; - PJDLOG_VERIFY(strlcpy(sun.sun_path, sockpath, sizeof(sun.sun_path)) < - sizeof(sun.sun_path)); - sun.sun_len = SUN_LEN(&sun); - - oldumask = umask(S_IXUSR | S_IXGRP | S_IXOTH); - if (bind(lsock, (struct sockaddr *)&sun, sizeof(sun)) == -1) - pjdlog_exit(1, "Unable to bind to %s", sockpath); - (void)umask(oldumask); - if (listen(lsock, lqlen) == -1) - pjdlog_exit(1, "Unable to listen on %s", sockpath); - - for (;;) { - FD_ZERO(&fds); - FD_SET(lsock, &fds); - maxfd = lsock; - TAILQ_FOREACH(casserv, &casper_services, cs_next) { - /* We handle only core services. */ - if (!SERVICE_IS_CORE(casserv)) - continue; - for (sconn = service_connection_first(casserv->cs_service); - sconn != NULL; - sconn = service_connection_next(sconn)) { - sock = service_connection_get_sock(sconn); - FD_SET(sock, &fds); - maxfd = sock > maxfd ? sock : maxfd; - } - } - maxfd++; - - PJDLOG_ASSERT(maxfd <= (int)FD_SETSIZE); - ret = select(maxfd, &fds, NULL, NULL, NULL); - PJDLOG_ASSERT(ret == -1 || ret > 0); /* select() cannot timeout */ - if (ret == -1) { - if (errno == EINTR) - continue; - KEEP_ERRNO((void)pidfile_remove(pfh)); - pjdlog_exit(1, "select() failed"); - } - - if (FD_ISSET(lsock, &fds)) - casper_accept(lsock); - TAILQ_FOREACH(casserv, &casper_services, cs_next) { - /* We handle only core services. */ - if (!SERVICE_IS_CORE(casserv)) - continue; - for (sconn = service_connection_first(casserv->cs_service); - sconn != NULL; sconn = sconntmp) { - /* - * Prepare for connection to be removed from - * the list on failure. - */ - sconntmp = service_connection_next(sconn); - sock = service_connection_get_sock(sconn); - if (FD_ISSET(sock, &fds)) { - service_message(casserv->cs_service, - sconn); - } - } - } - } -} - -static void -usage(void) -{ - - pjdlog_exitx(1, - "usage: casperd [-Fhv] [-D servconfdir] [-P pidfile] [-S sockpath]"); -} - -int -main(int argc, char *argv[]) -{ - struct pidfh *pfh; - const char *pidfile, *servconfdir, *sockpath; - pid_t otherpid; - int ch, debug, lqlen; - bool foreground; - - pjdlog_init(PJDLOG_MODE_STD); - - debug = 0; - foreground = false; - lqlen = SOMAXCONN; - pidfile = CASPERD_PIDFILE; - servconfdir = CASPERD_SERVCONFDIR; - sockpath = CASPERD_SOCKPATH; - - while ((ch = getopt(argc, argv, "D:Fhl:P:S:v")) != -1) { - switch (ch) { - case 'D': - servconfdir = optarg; - break; - case 'F': - foreground = true; - break; - case 'l': - lqlen = strtol(optarg, NULL, 0); - if (lqlen < 1) - lqlen = SOMAXCONN; - break; - case 'P': - pidfile = optarg; - break; - case 'S': - sockpath = optarg; - break; - case 'v': - debug++; - break; - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - - if (argc != 0) - usage(); - - if (!foreground) - pjdlog_mode_set(PJDLOG_MODE_SYSLOG); - pjdlog_prefix_set("(casperd) "); - pjdlog_debug_set(debug); - - if (zygote_init() < 0) - pjdlog_exit(1, "Unable to create zygote process"); - - pfh = pidfile_open(pidfile, 0600, &otherpid); - if (pfh == NULL) { - if (errno == EEXIST) { - pjdlog_exitx(1, "casperd already running, pid: %jd.", - (intmax_t)otherpid); - } - pjdlog_errno(LOG_WARNING, "Cannot open or create pidfile %s", - pidfile); - } - - if (!foreground) { - if (daemon(0, 0) == -1) { - KEEP_ERRNO((void)pidfile_remove(pfh)); - pjdlog_exit(1, "Unable to go into background"); - } - } - - /* Write PID to a file. */ - if (pidfile_write(pfh) == -1) { - pjdlog_errno(LOG_WARNING, "Unable to write to pidfile %s", - pidfile); - } else { - pjdlog_debug(1, "PID stored in %s.", pidfile); - } - - /* - * Register core services. - */ - service_register_core(); - /* - * Register external services. - */ - service_register_external(servconfdir); - - /* - * Wait for connections. - */ - main_loop(lqlen, sockpath, pfh); -} diff --git a/sbin/casperd/zygote.c b/sbin/casperd/zygote.c deleted file mode 100644 index 5bc9396..0000000 --- a/sbin/casperd/zygote.c +++ /dev/null @@ -1,227 +0,0 @@ -/*- - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Pawel Jakub Dawidek under sponsorship from - * the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/capsicum.h> -#include <sys/procdesc.h> -#include <sys/socket.h> -#include <sys/nv.h> - -#include <assert.h> -#include <err.h> -#include <errno.h> -#include <paths.h> -#include <stdbool.h> -#include <stdlib.h> -#include <strings.h> -#include <unistd.h> - -#include <libcapsicum.h> -#include <libcapsicum_impl.h> -#include <pjdlog.h> - -#include "zygote.h" - -/* Zygote info. */ -static int zygote_sock = -1; - -static void -stdnull(void) -{ - int fd; - - fd = open(_PATH_DEVNULL, O_RDWR); - if (fd == -1) - errx(1, "Unable to open %s", _PATH_DEVNULL); - - if (setsid() == -1) - errx(1, "Unable to detach from session"); - - if (dup2(fd, STDIN_FILENO) == -1) - errx(1, "Unable to cover stdin"); - if (dup2(fd, STDOUT_FILENO) == -1) - errx(1, "Unable to cover stdout"); - if (dup2(fd, STDERR_FILENO) == -1) - errx(1, "Unable to cover stderr"); - - close(fd); -} - -int -zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp) -{ - nvlist_t *nvl; - int error; - - if (zygote_sock == -1) { - /* Zygote didn't start. */ - errno = ENXIO; - return (-1); - } - - nvl = nvlist_create(0); - nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func); - nvl = nvlist_xfer(zygote_sock, nvl, 0); - if (nvl == NULL) - return (-1); - if (nvlist_exists_number(nvl, "error")) { - error = (int)nvlist_get_number(nvl, "error"); - nvlist_destroy(nvl); - errno = error; - return (-1); - } - - *chanfdp = nvlist_take_descriptor(nvl, "chanfd"); - *procfdp = nvlist_take_descriptor(nvl, "procfd"); - - nvlist_destroy(nvl); - return (0); -} - -/* - * 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, 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, 0); - if (nvlin == NULL) { - if (errno == ENOTCONN) { - /* Casperd exited. */ - exit(0); - } - continue; - } - func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin, - "func"); - 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 */ -} - -int -zygote_init(void) -{ - int serrno, sp[2]; - pid_t pid; - - if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp) == -1) - return (-1); - - pid = fork(); - switch (pid) { - case -1: - /* Failure. */ - serrno = errno; - close(sp[0]); - close(sp[1]); - errno = serrno; - return (-1); - case 0: - /* Child. */ - close(sp[0]); - zygote_main(sp[1]); - /* NOTREACHED */ - abort(); - default: - /* Parent. */ - zygote_sock = sp[0]; - close(sp[1]); - return (0); - } - /* NOTREACHED */ -} diff --git a/sbin/casperd/zygote.h b/sbin/casperd/zygote.h deleted file mode 100644 index 4c9c771..0000000 --- a/sbin/casperd/zygote.h +++ /dev/null @@ -1,40 +0,0 @@ -/*- - * Copyright (c) 2012 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Pawel Jakub Dawidek under sponsorship from - * the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _ZYGOTE_H_ -#define _ZYGOTE_H_ - -typedef void zygote_func_t(int); - -int zygote_init(void); -int zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp); - -#endif /* !_ZYGOTE_H_ */ |