Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: avahi-daemon/chroot.c
===================================================================
--- avahi-daemon/chroot.c	(nonexistent)
+++ avahi-daemon/chroot.c	(revision 331)
@@ -0,0 +1,415 @@
+/***
+  This file is part of avahi.
+
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <avahi-core/log.h>
+#include <libdaemon/dfork.h>
+
+#include "chroot.h"
+#include "caps.h"
+#include "setproctitle.h"
+
+enum {
+    AVAHI_CHROOT_SUCCESS = 0,
+    AVAHI_CHROOT_FAILURE,
+    AVAHI_CHROOT_GET_RESOLV_CONF,
+#ifdef HAVE_DBUS
+    AVAHI_CHROOT_GET_SERVER_INTROSPECT,
+    AVAHI_CHROOT_GET_ENTRY_GROUP_INTROSPECT,
+    AVAHI_CHROOT_GET_ADDRESS_RESOLVER_INTROSPECT,
+    AVAHI_CHROOT_GET_DOMAIN_BROWSER_INTROSPECT,
+    AVAHI_CHROOT_GET_HOST_NAME_RESOLVER_INTROSPECT,
+    AVAHI_CHROOT_GET_SERVICE_BROWSER_INTROSPECT,
+    AVAHI_CHROOT_GET_SERVICE_RESOLVER_INTROSPECT,
+    AVAHI_CHROOT_GET_SERVICE_TYPE_BROWSER_INTROSPECT,
+    AVAHI_CHROOT_GET_RECORD_BROWSER_INTROSPECT,
+#endif
+    AVAHI_CHROOT_UNLINK_PID,
+    AVAHI_CHROOT_UNLINK_SOCKET,
+    AVAHI_CHROOT_MAX
+};
+
+static const char* const get_file_name_table[AVAHI_CHROOT_MAX] = {
+    NULL,
+    NULL,
+    "/etc/resolv.conf",
+#ifdef HAVE_DBUS
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.Server.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.EntryGroup.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.AddressResolver.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.DomainBrowser.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.HostNameResolver.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.ServiceBrowser.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.ServiceResolver.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.ServiceTypeBrowser.xml",
+    AVAHI_DBUS_INTROSPECTION_DIR"/org.freedesktop.Avahi.RecordBrowser.xml",
+#endif
+    NULL,
+    NULL
+};
+
+static const char *const unlink_file_name_table[AVAHI_CHROOT_MAX] = {
+    NULL,
+    NULL,
+    NULL,
+#ifdef HAVE_DBUS
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+#endif
+    AVAHI_DAEMON_RUNTIME_DIR"/pid",
+    AVAHI_SOCKET
+};
+
+static int helper_fd = -1;
+
+static int send_fd(int fd, int payload_fd) {
+    uint8_t dummy = AVAHI_CHROOT_SUCCESS;
+    struct iovec iov;
+    struct msghdr msg;
+    union {
+        struct cmsghdr hdr;
+        char buf[CMSG_SPACE(sizeof(int))];
+    } cmsg;
+
+    /* Send a file descriptor over the socket */
+
+    memset(&iov, 0, sizeof(iov));
+    memset(&msg, 0, sizeof(msg));
+    memset(&cmsg, 0, sizeof(cmsg));
+
+    iov.iov_base = &dummy;
+    iov.iov_len = sizeof(dummy);
+
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+
+    msg.msg_control = &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
+    msg.msg_flags = 0;
+
+    cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
+    cmsg.hdr.cmsg_level = SOL_SOCKET;
+    cmsg.hdr.cmsg_type = SCM_RIGHTS;
+    *((int*) CMSG_DATA(&cmsg.hdr)) = payload_fd;
+
+    if (sendmsg(fd, &msg, 0) < 0) {
+        avahi_log_error("sendmsg() failed: %s", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int recv_fd(int fd) {
+    uint8_t dummy;
+    struct iovec iov;
+    struct msghdr msg;
+    union {
+        struct cmsghdr hdr;
+        char buf[CMSG_SPACE(sizeof(int))];
+    } cmsg;
+
+    /* Receive a file descriptor from a socket */
+
+    memset(&iov, 0, sizeof(iov));
+    memset(&msg, 0, sizeof(msg));
+    memset(&cmsg, 0, sizeof(cmsg));
+
+    iov.iov_base = &dummy;
+    iov.iov_len = sizeof(dummy);
+
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+
+    msg.msg_control = cmsg.buf;
+    msg.msg_controllen = sizeof(cmsg);
+    msg.msg_flags = 0;
+
+    cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
+    cmsg.hdr.cmsg_level = SOL_SOCKET;
+    cmsg.hdr.cmsg_type = SCM_RIGHTS;
+    *((int*) CMSG_DATA(&cmsg.hdr)) = -1;
+
+    if (recvmsg(fd, &msg, 0) <= 0) {
+        avahi_log_error("recvmsg() failed: %s", strerror(errno));
+        return -1;
+    } else {
+        struct cmsghdr* h;
+
+        if (dummy != AVAHI_CHROOT_SUCCESS) {
+            errno = EINVAL;
+            return -1;
+        }
+
+        if (!(h = CMSG_FIRSTHDR(&msg))) {
+            avahi_log_error("recvmsg() sent no fd.");
+            errno = EINVAL;
+            return -1;
+        }
+
+        assert(h->cmsg_len == CMSG_LEN(sizeof(int)));
+        assert(h->cmsg_level == SOL_SOCKET);
+        assert(h->cmsg_type == SCM_RIGHTS);
+
+        return *((int*)CMSG_DATA(h));
+    }
+}
+
+static int helper_main(int fd) {
+    int ret = 1;
+    assert(fd >= 0);
+
+    /* This is the main function of our helper process which is forked
+     * off to access files outside the chroot environment. Keep in
+     * mind that this code is security sensitive! */
+
+    avahi_log_debug(__FILE__": chroot() helper started");
+
+    for (;;) {
+        uint8_t command;
+        ssize_t r;
+
+        if ((r = read(fd, &command, sizeof(command))) <= 0) {
+
+            /* EOF? */
+            if (r == 0)
+                break;
+
+            avahi_log_error(__FILE__": read() failed: %s", strerror(errno));
+            goto fail;
+        }
+
+        assert(r == sizeof(command));
+
+        avahi_log_debug(__FILE__": chroot() helper got command %02x", command);
+
+        switch (command) {
+#ifdef HAVE_DBUS
+            case AVAHI_CHROOT_GET_SERVER_INTROSPECT:
+            case AVAHI_CHROOT_GET_ENTRY_GROUP_INTROSPECT:
+            case AVAHI_CHROOT_GET_ADDRESS_RESOLVER_INTROSPECT:
+            case AVAHI_CHROOT_GET_DOMAIN_BROWSER_INTROSPECT:
+            case AVAHI_CHROOT_GET_HOST_NAME_RESOLVER_INTROSPECT:
+            case AVAHI_CHROOT_GET_SERVICE_BROWSER_INTROSPECT:
+            case AVAHI_CHROOT_GET_SERVICE_RESOLVER_INTROSPECT:
+            case AVAHI_CHROOT_GET_SERVICE_TYPE_BROWSER_INTROSPECT:
+            case AVAHI_CHROOT_GET_RECORD_BROWSER_INTROSPECT:
+#endif
+            case AVAHI_CHROOT_GET_RESOLV_CONF: {
+                int payload;
+
+                if ((payload = open(get_file_name_table[(int) command], O_RDONLY)) < 0) {
+                    uint8_t c = AVAHI_CHROOT_FAILURE;
+
+                    avahi_log_error(__FILE__": open() failed: %s", strerror(errno));
+
+                    if (write(fd, &c, sizeof(c)) != sizeof(c)) {
+                        avahi_log_error(__FILE__": write() failed: %s\n", strerror(errno));
+                        goto fail;
+                    }
+
+                    break;
+                }
+
+                if (send_fd(fd, payload) < 0)
+                    goto fail;
+
+                close(payload);
+
+                break;
+            }
+
+            case AVAHI_CHROOT_UNLINK_SOCKET:
+            case AVAHI_CHROOT_UNLINK_PID: {
+                uint8_t c = AVAHI_CHROOT_SUCCESS;
+
+                unlink(unlink_file_name_table[(int) command]);
+
+                if (write(fd, &c, sizeof(c)) != sizeof(c)) {
+                    avahi_log_error(__FILE__": write() failed: %s\n", strerror(errno));
+                    goto fail;
+                }
+
+                break;
+            }
+
+            default:
+                avahi_log_error(__FILE__": Unknown command %02x.", command);
+                break;
+        }
+    }
+
+    ret = 0;
+
+fail:
+
+    avahi_log_debug(__FILE__": chroot() helper exiting with return value %i", ret);
+
+    return ret;
+}
+
+int avahi_chroot_helper_start(const char *argv0) {
+    int sock[2];
+    pid_t pid;
+
+    assert(helper_fd < 0);
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
+        avahi_log_error("socketpair() failed: %s", strerror(errno));
+        return -1;
+    }
+
+    if ((pid = fork()) < 0) {
+        close(sock[0]);
+        close(sock[1]);
+        avahi_log_error(__FILE__": fork() failed: %s", strerror(errno));
+        return -1;
+    } else if (pid == 0) {
+
+        /* Drop all remaining capabilities */
+        avahi_caps_drop_all();
+
+        avahi_set_proc_title(argv0, "%s: chroot helper", argv0);
+
+        daemon_retval_done();
+
+        close(sock[0]);
+        helper_main(sock[1]);
+        _exit(0);
+    }
+
+    close(sock[1]);
+    helper_fd = sock[0];
+
+    return 0;
+}
+
+void avahi_chroot_helper_shutdown(void) {
+
+    if (helper_fd <= 0)
+        return;
+
+    close(helper_fd);
+    helper_fd = -1;
+}
+
+int avahi_chroot_helper_get_fd(const char *fname) {
+
+    if (helper_fd >= 0) {
+        uint8_t command;
+
+        for (command = 2; command < AVAHI_CHROOT_MAX; command++)
+            if (get_file_name_table[(int) command] &&
+                strcmp(fname, get_file_name_table[(int) command]) == 0)
+                break;
+
+        if (command >= AVAHI_CHROOT_MAX) {
+            avahi_log_error("chroot() helper accessed for invalid file name");
+            errno = EACCES;
+            return -1;
+        }
+
+        assert(get_file_name_table[(int) command]);
+
+        if (write(helper_fd, &command, sizeof(command)) < 0) {
+            avahi_log_error("write() failed: %s\n", strerror(errno));
+            return -1;
+        }
+
+        return recv_fd(helper_fd);
+
+    } else
+        return open(fname, O_RDONLY);
+}
+
+
+FILE *avahi_chroot_helper_get_file(const char *fname) {
+    FILE *f;
+    int fd;
+
+    if ((fd = avahi_chroot_helper_get_fd(fname)) < 0)
+        return NULL;
+
+    f = fdopen(fd, "r");
+    assert(f);
+
+    return f;
+}
+
+int avahi_chroot_helper_unlink(const char *fname) {
+
+    if (helper_fd >= 0) {
+        uint8_t c, command;
+        ssize_t r;
+
+        for (command = 2; command < AVAHI_CHROOT_MAX; command++)
+            if (unlink_file_name_table[(int) command] &&
+                strcmp(fname, unlink_file_name_table[(int) command]) == 0)
+                break;
+
+        if (command >= AVAHI_CHROOT_MAX) {
+            avahi_log_error("chroot() helper accessed for invalid file name");
+            errno = EACCES;
+            return -1;
+        }
+
+        if (write(helper_fd, &command, sizeof(command)) < 0 &&
+            (errno != EPIPE && errno != ECONNRESET)) {
+            avahi_log_error("write() failed: %s\n", strerror(errno));
+            return -1;
+        }
+
+        if ((r = read(helper_fd, &c, sizeof(c))) < 0 &&
+            (errno != EPIPE && errno != ECONNRESET)) {
+            avahi_log_error("read() failed: %s\n", r < 0 ? strerror(errno) : "EOF");
+            return -1;
+        }
+
+        return 0;
+
+    } else
+
+        return unlink(fname);
+
+}