- /* Open the Unix socket. The vmchannel implementation that got
- * merged with qemu sucks in a number of ways. Both ends do
- * connect(2), which means that no one knows what, if anything, is
- * connected to the other end, or if it becomes disconnected. Even
- * worse, we have to wait some indeterminate time for qemu to create
- * the socket and connect to it (which happens very early in qemu's
- * start-up), so any code that uses vmchannel is inherently racy.
- * Hence this silly loop.
- */
- g->sock = socket (AF_UNIX, SOCK_STREAM, 0);
- if (g->sock == -1) {
- perrorf (g, "socket");
+ /* Null vmchannel implementation: We listen on g->sock for a
+ * connection. The connection could come from any local process
+ * so we must check it comes from the appliance (or at least
+ * from our UID) for security reasons.
+ */
+ while (sock == -1) {
+ sock = accept_from_daemon (g);
+ if (sock == -1)
+ goto cleanup1;
+
+ if (check_peer_euid (g, sock, &uid) == -1)
+ goto cleanup1;
+ if (uid != geteuid ()) {
+ fprintf (stderr,
+ "libguestfs: warning: unexpected connection from UID %d to port %d\n",
+ uid, null_vmchannel_sock);
+ close (sock);
+ continue;
+ }
+ }
+
+ if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) {
+ perrorf (g, "fcntl");
+ goto cleanup1;
+ }
+
+ close (g->sock);
+ g->sock = sock;
+ } else {
+ /* Other vmchannel. Open the Unix socket.
+ *
+ * The vmchannel implementation that got merged with qemu sucks in
+ * a number of ways. Both ends do connect(2), which means that no
+ * one knows what, if anything, is connected to the other end, or
+ * if it becomes disconnected. Even worse, we have to wait some
+ * indeterminate time for qemu to create the socket and connect to
+ * it (which happens very early in qemu's start-up), so any code
+ * that uses vmchannel is inherently racy. Hence this silly loop.
+ */
+ g->sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (g->sock == -1) {
+ perrorf (g, "socket");
+ goto cleanup1;
+ }
+
+ if (fcntl (g->sock, F_SETFL, O_NONBLOCK) == -1) {
+ perrorf (g, "fcntl");
+ goto cleanup1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, unixsock, UNIX_PATH_MAX);
+ addr.sun_path[UNIX_PATH_MAX-1] = '\0';
+
+ tries = 100;
+ /* Always sleep at least once to give qemu a small chance to start up. */
+ usleep (10000);
+ while (tries > 0) {
+ r = connect (g->sock, (struct sockaddr *) &addr, sizeof addr);
+ if ((r == -1 && errno == EINPROGRESS) || r == 0)
+ goto connected;
+
+ if (errno != ENOENT)
+ perrorf (g, "connect");
+ tries--;
+ usleep (100000);
+ }
+
+ error (g, _("failed to connect to vmchannel socket"));