Beispiel #1
0
static PyObject* is_socket_unix(PyObject *self, PyObject *args) {
        int r;
        int fd, type = 0, listening = -1;
        char* path = NULL;
        Py_ssize_t length = 0;

#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1
        _cleanup_Py_DECREF_ PyObject *_path = NULL;
        if (!PyArg_ParseTuple(args, "i|iiO&:_is_socket_unix",
                              &fd, &type, &listening, Unicode_FSConverter, &_path))
                return NULL;
        if (_path) {
                assert(PyBytes_Check(_path));
                if (PyBytes_AsStringAndSize(_path, &path, &length))
                        return NULL;
        }
#else
        if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix",
                              &fd, &type, &listening, &path, &length))
                return NULL;
#endif

        r = sd_is_socket_unix(fd, type, listening, path, length);
        if (set_error(r, path, NULL) < 0)
                return NULL;

        return PyBool_FromLong(r);
}
Beispiel #2
0
int SocketManager::GetSocketFromSystemD(
    const GenericSocketService::ServiceDescription &desc)
{
    int fd;

    // TODO optimalization - do it once in object constructor
    //                       and remember all information path->sockfd
    int n = sd_listen_fds(0);

    LogInfo("sd_listen_fds returns: " << n);

    if (n < 0) {
        LogError("Error in sd_listend_fds");
        ThrowMsg(Exception::InitFailed, "Error in sd_listend_fds");
    }

    for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd) {
        if (0 < sd_is_socket_unix(fd, SOCK_STREAM, 1,
                                  desc.serviceHandlerPath.c_str(), 0)) {
            LogInfo("Useable socket " << desc.serviceHandlerPath <<
                " was passed by SystemD under descriptor " << fd);
            return fd;
        }
    }
    LogError("No useable sockets were passed by systemd.");
    return -1;
}
static gboolean
systemd_syslog_sd_acquire_socket(AFSocketSourceDriver *s,
                          gint *acquired_fd)
{
  gint fd, number_of_fds;

  *acquired_fd = -1;
  fd = -1;

  number_of_fds = sd_listen_fds(0);

  if (number_of_fds > 1)
    {
      msg_error("Systemd socket activation failed: got more than one fd",
                evt_tag_int("number", number_of_fds),
                NULL);

      return TRUE;
    }
  else if (number_of_fds < 1)
    {
      msg_error("Failed to acquire /run/systemd/journal/syslog socket, disabling systemd-syslog source",
                NULL);
      return TRUE;
    }
  else
    {
      fd = SD_LISTEN_FDS_START;
      msg_debug("Systemd socket activation",
                evt_tag_int("file-descriptor", fd),
                NULL);

      if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, NULL, 0))
        {
          *acquired_fd = fd;
        }
      else
        {
          msg_error("The systemd supplied UNIX domain socket is of a"
                    " different type, check the configured driver and"
                    " the matching systemd unit file",
                    evt_tag_int("systemd-sock-fd", fd),
                    evt_tag_str("expecting", "unix-dgram()"),
                    NULL);
          *acquired_fd = -1;
          return TRUE;
        }
    }

  if (*acquired_fd != -1)
    {
      g_fd_set_nonblock(*acquired_fd, TRUE);
      msg_verbose("Acquired systemd syslog socket",
                  evt_tag_int("systemd-syslog-sock-fd", *acquired_fd),
                  NULL);
      return TRUE;
    }

  return TRUE;
}
Beispiel #4
0
int get_socket()
{
  int fd, n;
  size_t name_length;
  socklen_t new_length;
  name_length = strlen(ABSTRACT_SOCKET_NAME) + 1;

  if (HAVE_LIBSYSTEMD == 1) {
    /* Check for file descriptors passed by the system manager */
    n = sd_listen_fds(0);
  } else {
    n = 0;
  }

  if (n < 0)  {
    /* Below 0 is an error code */
    fprintf(stderr, "sd_listen_fds(): %s\n", strerror(-n));
    exit(EXIT_FAILURE);
  } else if (n > 1) {
    /* Only need one socket */
    fprintf(stderr, "Too many file descriptors received.\n");
    exit(EXIT_FAILURE);
  } else if (n == 1) {
    /* Got one socket */
    fd = SD_LISTEN_FDS_START + 0;
    /* Check it is correct type */
    if (sd_is_socket_unix(fd, SOCK_STREAM, -1, "\0", name_length) <= 0) {
      fprintf(stderr, "Invalid socket passed.\n");
      exit(EXIT_FAILURE);
    }
  } else {
    /* No socket from system manager. Lets make our own then */

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(struct sockaddr_un));  /* Clear address structure */
    addr.sun_family = AF_UNIX;                     /* UNIX domain address */

    /* addr.sun_path[0] has already been set to 0 by memset() */

    strncpy(&addr.sun_path[1], ABSTRACT_SOCKET_NAME, strlen(ABSTRACT_SOCKET_NAME));

    fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
    if (fd == -1) {
      printf("socket error");
      exit(EXIT_FAILURE);
    }

    new_length = (socklen_t) sizeof(sa_family_t) + (socklen_t) name_length;
    if (bind(fd, (struct sockaddr *) &addr, new_length) == -1) {
      printf("socket binding error");
      exit(EXIT_FAILURE);
    }
  }
  return fd;
}
Beispiel #5
0
/* Will work regardless of the order systemd gives them to us */
static int oxen_get_sd_fd(const char *connect_to)
{
	int fd = SD_LISTEN_FDS_START;
	int r;

	while (fd <= SD_LISTEN_FDS_START + 1) {
		r = sd_is_socket_unix(fd, SOCK_STREAM, 1, connect_to, 0);
		if (r > 0)
			return fd;
		fd++;
	}

	return -EBADR;
}
static char *
system_linux_find_dev_log(void)
{
    int r, fd;

    r = sd_listen_fds(0);
    if (r == 0)
        return "/dev/log";
    if (r < 0)
    {
        msg_error ("system(): sd_listen_fds() failed",
                   evt_tag_int("errno", r),
                   NULL);
        return NULL;
    }

    /* We only support socket activation for /dev/log, meaning
     * one socket only. Bail out if we get more.
     */
    if (r != 1)
    {
        msg_error("system(): Too many sockets passed in for socket activation, syslog-ng only supports one.",
                  NULL);
        return NULL;
    }

    fd = SD_LISTEN_FDS_START;
    if (sd_is_socket_unix(fd, SOCK_DGRAM, -1,
                          "/run/systemd/journal/syslog", 0) != 1)
    {
        msg_error("system(): Socket activation is only supported on /run/systemd/journal/syslog",
                  NULL);
        return NULL;
    }

    return "/run/systemd/journal/syslog";
}
Beispiel #7
0
/*! starts listening on a UNIX domain server socket.
 *
 * \param path the path on the local file system, that this socket is to listen to.
 * \param flags some flags, such as O_CLOEXEC and O_NONBLOCK (the most prominent) to set on server socket and each created client socket
 *
 * \retval true successfully initialized
 * \retval false some failure occured during setting up the server socket.
 */
bool ServerSocket::open(const std::string& path, int flags)
{
#ifndef NDEBUG
	setLoggingPrefix("ServerSocket(%s)", path.c_str());
#endif
	TRACE("opening");

	int fd = -1;
	size_t addrlen;
	int sd_fd_count = sd_listen_fds(false);

	typeMask_ = 0;
	flags_ = flags;

	if (flags & O_CLOEXEC) {
		flags_ &= ~O_CLOEXEC;
		typeMask_ |= SOCK_CLOEXEC;
	}

	if (flags & O_NONBLOCK) {
		flags_ &= ~O_NONBLOCK;
		typeMask_ |= SOCK_NONBLOCK;
	}

	// check if passed by parent x0d first
	if ((fd = x0::getSocketUnix(path.c_str())) >= 0) {
		// socket found, but ensure our expected `flags` are set.
		if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) {
			goto syserr;
		} else {
			goto done;
		}
	}

	// check if systemd created the socket for us
	if (sd_fd_count > 0) {
		fd = SD_LISTEN_FDS_START;
		int last = fd + sd_fd_count;

		for (; fd < last; ++fd) {
			if (sd_is_socket_unix(fd, AF_UNIX, SOCK_STREAM, path.c_str(), path.size()) > 0) {
				// socket found, but ensure our expected `flags` are set.
				if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) {
					goto syserr;
				} else {
					goto done;
				}
			}
		}

		errorText_ = "Running under systemd socket unit, but we received no UNIX-socket for \"" + path + "\".";
		goto err;
	}

	// create socket manually
	fd = ::socket(PF_UNIX, SOCK_STREAM, 0);
	if (fd < 0)
		goto syserr;

	if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0)
		goto syserr;

	struct sockaddr_un addr;
	addr.sun_family = AF_UNIX;

	if (path.size() >= sizeof(addr.sun_path)) {
		errno = ENAMETOOLONG;
		goto syserr;
	}

	addrlen = sizeof(addr.sun_family)
		+ strlen(strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path)));

	if (::bind(fd, reinterpret_cast<struct sockaddr*>(&addr), addrlen) < 0)
		goto syserr;

	if (::listen(fd, backlog_))
		goto syserr;

	if (chmod(path.c_str(), 0666) < 0) {
		perror("chmod");
	}

done:
	fd_ = fd;
	addressFamily_ = AF_UNIX;
	address_ = path;
	port_ = 0;

	io_.set<ServerSocket, &ServerSocket::accept>(this);
	start();

	return true;

syserr:
	errorText_ = strerror(errno);

err:
	if (fd >= 0)
		::close(fd);

	return false;
}
Beispiel #8
0
/**
 * Entry point into bt-daemon
 * @param argc Number of arguments passed
 * @param argv An array of string arguments
 * @returns EXIT_SUCCESS if the operation succeeded, otherwise EXIT_FAILURE
 */
int main(int argc, char *argv[])
{
	int fd;
	int smackfd = -1;
	socklen_t addr_len;
	struct sockaddr_un remote;
	int descriptors;
	int ret;
	bool manual_start = false;
	struct sigaction sa;

	if (!buxton_cache_smack_rules())
		exit(EXIT_FAILURE);
	smackfd = buxton_watch_smack_rules();
	if (smackfd < 0 && errno)
		exit(EXIT_FAILURE);

	self.nfds_alloc = 0;
	self.accepting_alloc = 0;
	self.nfds = 0;
	self.buxton.client.direct = true;
	self.buxton.client.uid = geteuid();
	if (!buxton_direct_open(&self.buxton))
		exit(EXIT_FAILURE);

	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;
	sa.sa_handler = my_handler;
	ret = sigaction(SIGINT, &sa, NULL);
	if (ret == -1)
		exit(EXIT_FAILURE);
	ret = sigaction(SIGTERM, &sa, NULL);
	if (ret == -1)
		exit(EXIT_FAILURE);

	/* For client notifications */
	self.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
	/* Store a list of connected clients */
	LIST_HEAD_INIT(client_list_item, self.client_list);

	descriptors = sd_listen_fds(0);
	if (descriptors < 0) {
		buxton_log("sd_listen_fds: %m\n");
		exit(EXIT_FAILURE);
	} else if (descriptors == 0) {
		/* Manual invocation */
		manual_start = true;
		union {
			struct sockaddr sa;
			struct sockaddr_un un;
		} sa;

		fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if (fd < 0) {
			buxton_log("socket(): %m\n");
			exit(EXIT_FAILURE);
		}

		memset(&sa, 0, sizeof(sa));
		sa.un.sun_family = AF_UNIX;
		strncpy(sa.un.sun_path, BUXTON_SOCKET, sizeof(sa.un.sun_path) - 1);
		sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;

		ret = unlink(sa.un.sun_path);
		if (ret == -1 && errno != ENOENT) {
			exit(EXIT_FAILURE);
		}

		if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
			buxton_log("bind(): %m\n");
			exit(EXIT_FAILURE);
		}

		chmod(sa.un.sun_path, 0666);

		if (listen(fd, SOMAXCONN) < 0) {
			buxton_log("listen(): %m\n");
			exit(EXIT_FAILURE);
		}
		add_pollfd(&self, fd, POLLIN | POLLPRI, true);
	} else {
		/* systemd socket activation */
		for (fd = SD_LISTEN_FDS_START + 0; fd < SD_LISTEN_FDS_START + descriptors; fd++) {
			if (sd_is_fifo(fd, NULL)) {
				add_pollfd(&self, fd, POLLIN, false);
				buxton_debug("Added fd %d type FIFO\n", fd);
			} else if (sd_is_socket_unix(fd, SOCK_STREAM, -1, BUXTON_SOCKET, 0)) {
				add_pollfd(&self, fd, POLLIN | POLLPRI, true);
				buxton_debug("Added fd %d type UNIX\n", fd);
			} else if (sd_is_socket(fd, AF_UNSPEC, 0, -1)) {
				add_pollfd(&self, fd, POLLIN | POLLPRI, true);
				buxton_debug("Added fd %d type SOCKET\n", fd);
			}
		}
	}

	if (smackfd >= 0) {
		/* add Smack rule fd to pollfds */
		add_pollfd(&self, smackfd, POLLIN | POLLPRI, false);
	}

	buxton_log("%s: Started\n", argv[0]);

	/* Enter loop to accept clients */
	for (;;) {
		ret = poll(self.pollfds, self.nfds, -1);

		if (ret < 0) {
			buxton_log("poll(): %m\n");
			if (errno == EINTR) {
				if (do_shutdown)
					break;
				else
					continue;
			}
			break;
		}
		if (ret == 0)
			continue;

		for (nfds_t i=0; i<self.nfds; i++) {
			client_list_item *cl = NULL;
			char discard[256];

			if (self.pollfds[i].revents == 0)
				continue;

			if (self.pollfds[i].fd == -1) {
				/* TODO: Remove client from list  */
				buxton_debug("Removing / Closing client for fd %d\n", self.pollfds[i].fd);
				del_pollfd(&self, i);
				continue;
			}

			if (smackfd >= 0) {
				if (self.pollfds[i].fd == smackfd) {
					if (!buxton_cache_smack_rules())
						exit(EXIT_FAILURE);
					buxton_log("Reloaded Smack access rules\n");
					/* discard inotify data itself */
					while (read(smackfd, &discard, 256) == 256);
					continue;
				}
			}

			if (self.accepting[i] == true) {
				struct timeval tv;
				int fd;
				int on = 1;

				addr_len = sizeof(remote);

				if ((fd = accept(self.pollfds[i].fd,
				    (struct sockaddr *)&remote, &addr_len)) == -1) {
					buxton_log("accept(): %m\n");
					break;
				}

				buxton_debug("New client fd %d connected through fd %d\n", fd, self.pollfds[i].fd);

				cl = malloc0(sizeof(client_list_item));
				if (!cl)
					exit(EXIT_FAILURE);

				LIST_INIT(client_list_item, item, cl);

				cl->fd = fd;
				cl->cred = (struct ucred) {0, 0, 0};
				LIST_PREPEND(client_list_item, item, self.client_list, cl);

				/* poll for data on this new client as well */
				add_pollfd(&self, cl->fd, POLLIN | POLLPRI, false);

				/* Mark our packets as high prio */
				if (setsockopt(cl->fd, SOL_SOCKET, SO_PRIORITY, &on, sizeof(on)) == -1)
					buxton_log("setsockopt(SO_PRIORITY): %m\n");

				/* Set socket recv timeout */
				tv.tv_sec = SOCKET_TIMEOUT;
				tv.tv_usec = 0;
				if (setsockopt(cl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
					       sizeof(struct timeval)) == -1)
					buxton_log("setsockopt(SO_RCVTIMEO): %m\n");

				/* check if this is optimal or not */
				break;
			}

			assert(self.accepting[i] == 0);
			if (smackfd >= 0)
				assert(self.pollfds[i].fd != smackfd);

			/* handle data on any connection */
			/* TODO: Replace with hash table lookup */
			LIST_FOREACH(item, cl, self.client_list)
				if (self.pollfds[i].fd == cl->fd)
					break;

			assert(cl);
			handle_client(&self, cl, i);
		}
	}

	buxton_log("%s: Closing all connections\n", argv[0]);

	if (manual_start)
		unlink(BUXTON_SOCKET);
	for (int i = 0; i < self.nfds; i++) {
		close(self.pollfds[i].fd);
	}
	for (client_list_item *i = self.client_list; i;) {
		client_list_item *j = i->item_next;
		free(i);
		i = j;
	}
	hashmap_free(self.notify_mapping);
	buxton_direct_close(&self.buxton);
	return EXIT_SUCCESS;
}
Beispiel #9
0
static gboolean
afunix_sd_acquire_named_socket(AFSocketSourceDriver *s, gint *result_fd,
                               const gchar *filename)
{
  AFUnixSourceDriver *self = (AFUnixSourceDriver *) s;
  gint fd, fds;

  *result_fd = -1;
  fd = -1;
  fds = sd_listen_fds(0);

  if (fds == 0)
    return TRUE;

  msg_debug("Systemd socket activation",
	    evt_tag_int("systemd-sockets", fds),
	    evt_tag_str("systemd-listen-pid", getenv("LISTEN_PID")),
	    evt_tag_str("systemd-listen-fds", getenv("LISTEN_FDS")),
	    NULL);

  if (fds < 0)
    {
      msg_error("Failed to acquire systemd sockets, incorrectly set LISTEN_FDS environment variable?",
		NULL);
      return FALSE;
    }
  else if (fds > 0)
    {
      for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fds; fd++)
	{
	  /* check if any type is available */
	  if (sd_is_socket_unix(fd, 0, -1, filename, 0))
	    {
	      /* check if it matches our idea of the socket type */
	      if (sd_is_socket_unix(fd, self->super.transport_mapper->sock_type, -1, filename, 0))
                {
                  *result_fd = fd;
                  break;
                }
              else
                {
                  msg_error("The systemd supplied UNIX domain socket is of a different type, check the configured driver and the matching systemd unit file",
		            evt_tag_str("filename", filename),
		            evt_tag_int("systemd-sock-fd", fd),
			    evt_tag_str("expecting", self->super.transport_mapper->sock_type == SOCK_STREAM ? "unix-stream()" : "unix-dgram()"),
                            NULL);
                  return FALSE;
                }
            }
          else
            {

              /* systemd passed an fd we didn't really care about. This is
               * not an error, but might be worth mentioning it at the debug
               * level.
               */

              msg_debug("Ignoring systemd supplied fd as it is not a UNIX domain socket",
		        evt_tag_str("filename", filename),
		        evt_tag_int("systemd-sock-fd", fd),
		        NULL);
            }
	}
    }

  if (*result_fd != -1)
    {
      g_fd_set_nonblock(*result_fd, TRUE);
      g_fd_set_cloexec(*result_fd, TRUE);
      msg_verbose("Acquired systemd socket",
		  evt_tag_str("filename", filename),
		  evt_tag_int("systemd-sock-fd", *result_fd),
		  NULL);
      return TRUE;
    }
  return TRUE;
}