4 This file is part of avahi.
6 avahi is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 avahi is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14 Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with avahi; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include <sys/socket.h>
28 #include <sys/types.h>
37 #include <avahi-core/log.h>
38 #include <libdaemon/dfork.h>
42 #include "setproctitle.h"
45 AVAHI_CHROOT_SUCCESS = 0,
47 AVAHI_CHROOT_GET_RESOLV_CONF,
49 AVAHI_CHROOT_GET_SERVER_INTROSPECT,
50 AVAHI_CHROOT_GET_ENTRY_GROUP_INTROSPECT,
51 AVAHI_CHROOT_GET_ADDRESS_RESOLVER_INTROSPECT,
52 AVAHI_CHROOT_GET_DOMAIN_BROWSER_INTROSPECT,
53 AVAHI_CHROOT_GET_HOST_NAME_RESOLVER_INTROSPECT,
54 AVAHI_CHROOT_GET_SERVICE_BROWSER_INTROSPECT,
55 AVAHI_CHROOT_GET_SERVICE_RESOLVER_INTROSPECT,
56 AVAHI_CHROOT_GET_SERVICE_TYPE_BROWSER_INTROSPECT,
57 AVAHI_CHROOT_GET_RECORD_BROWSER_INTROSPECT,
59 AVAHI_CHROOT_UNLINK_PID,
60 AVAHI_CHROOT_UNLINK_SOCKET,
64 static const char* const get_file_name_table[AVAHI_CHROOT_MAX] = {
69 AVAHI_DBUS_INTROSPECTION_DIR"/Server.introspect",
70 AVAHI_DBUS_INTROSPECTION_DIR"/EntryGroup.introspect",
71 AVAHI_DBUS_INTROSPECTION_DIR"/AddressResolver.introspect",
72 AVAHI_DBUS_INTROSPECTION_DIR"/DomainBrowser.introspect",
73 AVAHI_DBUS_INTROSPECTION_DIR"/HostNameResolver.introspect",
74 AVAHI_DBUS_INTROSPECTION_DIR"/ServiceBrowser.introspect",
75 AVAHI_DBUS_INTROSPECTION_DIR"/ServiceResolver.introspect",
76 AVAHI_DBUS_INTROSPECTION_DIR"/ServiceTypeBrowser.introspect",
77 AVAHI_DBUS_INTROSPECTION_DIR"/RecordBrowser.introspect",
83 static const char *const unlink_file_name_table[AVAHI_CHROOT_MAX] = {
98 AVAHI_DAEMON_RUNTIME_DIR"/pid",
102 static int helper_fd = -1;
104 static int send_fd(int fd, int payload_fd) {
105 uint8_t dummy = AVAHI_CHROOT_SUCCESS;
110 char buf[CMSG_SPACE(sizeof(int))];
113 /* Send a file descriptor over the socket */
115 memset(&iov, 0, sizeof(iov));
116 memset(&msg, 0, sizeof(msg));
117 memset(&cmsg, 0, sizeof(cmsg));
119 iov.iov_base = &dummy;
120 iov.iov_len = sizeof(dummy);
127 msg.msg_control = &cmsg;
128 msg.msg_controllen = sizeof(cmsg);
131 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
132 cmsg.hdr.cmsg_level = SOL_SOCKET;
133 cmsg.hdr.cmsg_type = SCM_RIGHTS;
134 *((int*) CMSG_DATA(&cmsg.hdr)) = payload_fd;
136 if (sendmsg(fd, &msg, 0) < 0) {
137 avahi_log_error("sendmsg() failed: %s", strerror(errno));
144 static int recv_fd(int fd) {
150 char buf[CMSG_SPACE(sizeof(int))];
153 /* Receive a file descriptor from a socket */
155 memset(&iov, 0, sizeof(iov));
156 memset(&msg, 0, sizeof(msg));
157 memset(&cmsg, 0, sizeof(cmsg));
159 iov.iov_base = &dummy;
160 iov.iov_len = sizeof(dummy);
167 msg.msg_control = cmsg.buf;
168 msg.msg_controllen = sizeof(cmsg);
171 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
172 cmsg.hdr.cmsg_level = SOL_SOCKET;
173 cmsg.hdr.cmsg_type = SCM_RIGHTS;
174 *((int*) CMSG_DATA(&cmsg.hdr)) = -1;
176 if (recvmsg(fd, &msg, 0) <= 0) {
177 avahi_log_error("recvmsg() failed: %s", strerror(errno));
182 if (dummy != AVAHI_CHROOT_SUCCESS) {
187 if (!(h = CMSG_FIRSTHDR(&msg))) {
188 avahi_log_error("recvmsg() sent no fd.");
193 assert(h->cmsg_len = CMSG_LEN(sizeof(int)));
194 assert(h->cmsg_level = SOL_SOCKET);
195 assert(h->cmsg_type == SCM_RIGHTS);
197 return *((int*)CMSG_DATA(h));
201 static int helper_main(int fd) {
205 /* This is the main function of our helper process which is forked
206 * off to access files outside the chroot environment. Keep in
207 * mind that this code is security sensitive! */
209 avahi_log_debug(__FILE__": chroot() helper started");
215 if ((r = read(fd, &command, sizeof(command))) <= 0) {
221 avahi_log_error(__FILE__": read() failed: %s", strerror(errno));
225 assert(r == sizeof(command));
227 avahi_log_debug(__FILE__": chroot() helper got command %02x", command);
231 case AVAHI_CHROOT_GET_SERVER_INTROSPECT:
232 case AVAHI_CHROOT_GET_ENTRY_GROUP_INTROSPECT:
233 case AVAHI_CHROOT_GET_ADDRESS_RESOLVER_INTROSPECT:
234 case AVAHI_CHROOT_GET_DOMAIN_BROWSER_INTROSPECT:
235 case AVAHI_CHROOT_GET_HOST_NAME_RESOLVER_INTROSPECT:
236 case AVAHI_CHROOT_GET_SERVICE_BROWSER_INTROSPECT:
237 case AVAHI_CHROOT_GET_SERVICE_RESOLVER_INTROSPECT:
238 case AVAHI_CHROOT_GET_SERVICE_TYPE_BROWSER_INTROSPECT:
239 case AVAHI_CHROOT_GET_RECORD_BROWSER_INTROSPECT:
241 case AVAHI_CHROOT_GET_RESOLV_CONF: {
244 if ((payload = open(get_file_name_table[(int) command], O_RDONLY)) < 0) {
245 uint8_t c = AVAHI_CHROOT_FAILURE;
247 avahi_log_error(__FILE__": open() failed: %s", strerror(errno));
249 if (write(fd, &c, sizeof(c)) != sizeof(c)) {
250 avahi_log_error(__FILE__": write() failed: %s\n", strerror(errno));
257 if (send_fd(fd, payload) < 0)
265 case AVAHI_CHROOT_UNLINK_SOCKET:
266 case AVAHI_CHROOT_UNLINK_PID: {
267 uint8_t c = AVAHI_CHROOT_SUCCESS;
269 unlink(unlink_file_name_table[(int) command]);
271 if (write(fd, &c, sizeof(c)) != sizeof(c)) {
272 avahi_log_error(__FILE__": write() failed: %s\n", strerror(errno));
280 avahi_log_error(__FILE__": Unknown command %02x.", command);
289 avahi_log_debug(__FILE__": chroot() helper exiting with return value %i", ret);
294 int avahi_chroot_helper_start(const char *argv0) {
298 assert(helper_fd < 0);
300 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) < 0) {
301 avahi_log_error("socketpair() failed: %s", strerror(errno));
305 if ((pid = fork()) < 0) {
308 avahi_log_error(__FILE__": fork() failed: %s", strerror(errno));
310 } else if (pid == 0) {
314 /* Drop all remaining capabilities */
315 avahi_caps_drop_all();
317 avahi_set_proc_title(argv0, "%s: chroot helper", argv0);
319 daemon_retval_done();
322 helper_main(sock[1]);
332 void avahi_chroot_helper_shutdown(void) {
341 int avahi_chroot_helper_get_fd(const char *fname) {
343 if (helper_fd >= 0) {
346 for (command = 2; command < AVAHI_CHROOT_MAX; command++)
347 if (get_file_name_table[(int) command] &&
348 strcmp(fname, get_file_name_table[(int) command]) == 0)
351 if (command >= AVAHI_CHROOT_MAX) {
352 avahi_log_error("chroot() helper accessed for invalid file name");
357 assert(get_file_name_table[(int) command]);
359 if (write(helper_fd, &command, sizeof(command)) < 0) {
360 avahi_log_error("write() failed: %s\n", strerror(errno));
364 return recv_fd(helper_fd);
367 return open(fname, O_RDONLY);
371 FILE *avahi_chroot_helper_get_file(const char *fname) {
375 if ((fd = avahi_chroot_helper_get_fd(fname)) < 0)
384 int avahi_chroot_helper_unlink(const char *fname) {
386 if (helper_fd >= 0) {
390 for (command = 2; command < AVAHI_CHROOT_MAX; command++)
391 if (unlink_file_name_table[(int) command] &&
392 strcmp(fname, unlink_file_name_table[(int) command]) == 0)
395 if (command >= AVAHI_CHROOT_MAX) {
396 avahi_log_error("chroot() helper accessed for invalid file name");
401 if (write(helper_fd, &command, sizeof(command)) < 0) {
402 avahi_log_error("write() failed: %s\n", strerror(errno));
406 if ((r = read(helper_fd, &c, sizeof(c))) < 0) {
407 avahi_log_error("read() failed: %s\n", r < 0 ? strerror(errno) : "EOF");
415 return unlink(fname);