static int virFDStreamOpenInternal(virStreamPtr st, int fd, virCommandPtr cmd, int errfd, unsigned long long length) { struct virFDStreamData *fdst; VIR_DEBUG("st=%p fd=%d cmd=%p errfd=%d length=%llu", st, fd, cmd, errfd, length); if ((st->flags & VIR_STREAM_NONBLOCK) && virSetNonBlock(fd) < 0) return -1; if (VIR_ALLOC(fdst) < 0) return -1; fdst->fd = fd; fdst->cmd = cmd; fdst->errfd = errfd; fdst->length = length; if (virMutexInit(&fdst->lock) < 0) { VIR_FREE(fdst); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to initialize mutex")); return -1; } st->driver = &virFDStreamDrv; st->privateData = fdst; return 0; }
static int qemuAgentOpenUnix(const char *monitor, pid_t cpid, bool *inProgress) { struct sockaddr_un addr; int monfd; int timeout = 3; /* In seconds */ int ret, i = 0; *inProgress = false; if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { virReportSystemError(errno, "%s", _("failed to create socket")); return -1; } if (virSetNonBlock(monfd) < 0) { virReportSystemError(errno, "%s", _("Unable to put monitor " "into non-blocking mode")); goto error; } if (virSetCloseExec(monfd) < 0) { virReportSystemError(errno, "%s", _("Unable to set monitor " "close-on-exec flag")); goto error; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; if (virStrcpyStatic(addr.sun_path, monitor) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Agent path %s too big for destination"), monitor); goto error; } do { ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr)); if (ret == 0) break; if ((errno == ENOENT || errno == ECONNREFUSED) && virProcessKill(cpid, 0) == 0) { /* ENOENT : Socket may not have shown up yet * ECONNREFUSED : Leftover socket hasn't been removed yet */ continue; } if ((errno == EINPROGRESS) || (errno == EAGAIN)) { VIR_DEBUG("Connection attempt continuing in background"); *inProgress = true; ret = 0; break; } virReportSystemError(errno, "%s", _("failed to connect to monitor socket")); goto error; } while ((++i <= timeout*5) && (usleep(.2 * 1000000) <= 0)); if (ret != 0) { virReportSystemError(errno, "%s", _("monitor socket did not show up.")); goto error; } return monfd; error: VIR_FORCE_CLOSE(monfd); return -1; }
static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, virSocketAddrPtr remoteAddr, bool isClient, int fd, int errfd, pid_t pid) { virNetSocketPtr sock; int no_slow_start = 1; VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d", localAddr, remoteAddr, fd, errfd, pid); if (virSetCloseExec(fd) < 0) { virReportSystemError(errno, "%s", _("Unable to set close-on-exec flag")); return NULL; } if (virSetNonBlock(fd) < 0) { virReportSystemError(errno, "%s", _("Unable to enable non-blocking flag")); return NULL; } if (VIR_ALLOC(sock) < 0) { virReportOOMError(); return NULL; } if (virMutexInit(&sock->lock) < 0) { virReportSystemError(errno, "%s", _("Unable to initialize mutex")); VIR_FREE(sock); return NULL; } sock->refs = 1; if (localAddr) sock->localAddr = *localAddr; if (remoteAddr) sock->remoteAddr = *remoteAddr; sock->fd = fd; sock->errfd = errfd; sock->pid = pid; /* Disable nagle for TCP sockets */ if (sock->localAddr.data.sa.sa_family == AF_INET || sock->localAddr.data.sa.sa_family == AF_INET6) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &no_slow_start, sizeof(no_slow_start)) < 0) { virReportSystemError(errno, "%s", _("Unable to disable nagle algorithm")); goto error; } } if (localAddr && !(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) goto error; if (remoteAddr && !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) goto error; sock->client = isClient; PROBE(RPC_SOCKET_NEW, "sock=%p refs=%d fd=%d errfd=%d pid=%d localAddr=%s, remoteAddr=%s", sock, sock->refs, fd, errfd, pid, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); return sock; error: sock->fd = sock->errfd = -1; /* Caller owns fd/errfd on failure */ virNetSocketFree(sock); return NULL; }
/* * This tests validation checking of peer certificates * * This is replicating the checks that are done for an * active TLS session after handshake completes. To * simulate that we create our TLS contexts, skipping * sanity checks. When then get a socketpair, and * initiate a TLS session across them. Finally do * do actual cert validation tests */ static int testTLSSessionInit(const void *opaque) { struct testTLSSessionData *data = (struct testTLSSessionData *)opaque; virNetTLSContextPtr clientCtxt = NULL; virNetTLSContextPtr serverCtxt = NULL; virNetTLSSessionPtr clientSess = NULL; virNetTLSSessionPtr serverSess = NULL; int ret = -1; int channel[2]; bool clientShake = false; bool serverShake = false; /* We'll use this for our fake client-server connection */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) < 0) abort(); /* * We have an evil loop to do the handshake in a single * thread, so we need these non-blocking to avoid deadlock * of ourselves */ ignore_value(virSetNonBlock(channel[0])); ignore_value(virSetNonBlock(channel[1])); /* We skip initial sanity checks here because we * want to make sure that problems are being * detected at the TLS session validation stage */ serverCtxt = virNetTLSContextNewServer(data->servercacrt, NULL, data->servercrt, KEYFILE, data->wildcards, NULL, false, true); clientCtxt = virNetTLSContextNewClient(data->clientcacrt, NULL, data->clientcrt, KEYFILE, NULL, false, true); if (!serverCtxt) { VIR_WARN("Unexpected failure loading %s against %s", data->servercacrt, data->servercrt); goto cleanup; } if (!clientCtxt) { VIR_WARN("Unexpected failure loading %s against %s", data->clientcacrt, data->clientcrt); goto cleanup; } /* Now the real part of the test, setup the sessions */ serverSess = virNetTLSSessionNew(serverCtxt, NULL); clientSess = virNetTLSSessionNew(clientCtxt, data->hostname); if (!serverSess) { VIR_WARN("Unexpected failure using %s against %s", data->servercacrt, data->servercrt); goto cleanup; } if (!clientSess) { VIR_WARN("Unexpected failure using %s against %s", data->clientcacrt, data->clientcrt); goto cleanup; } /* For handshake to work, we need to set the I/O callbacks * to read/write over the socketpair */ virNetTLSSessionSetIOCallbacks(serverSess, testWrite, testRead, &channel[0]); virNetTLSSessionSetIOCallbacks(clientSess, testWrite, testRead, &channel[1]); /* * Finally we loop around & around doing handshake on each * session until we get an error, or the handshake completes. * This relies on the socketpair being nonblocking to avoid * deadlocking ourselves upon handshake */ do { int rv; if (!serverShake) { rv = virNetTLSSessionHandshake(serverSess); if (rv < 0) goto cleanup; if (rv == VIR_NET_TLS_HANDSHAKE_COMPLETE) serverShake = true; } if (!clientShake) { rv = virNetTLSSessionHandshake(clientSess); if (rv < 0) goto cleanup; if (rv == VIR_NET_TLS_HANDSHAKE_COMPLETE) clientShake = true; } } while (!clientShake && !serverShake); /* Finally make sure the server validation does what * we were expecting */ if (virNetTLSContextCheckCertificate(serverCtxt, serverSess) < 0) { if (!data->expectServerFail) { VIR_WARN("Unexpected server cert check fail"); goto cleanup; } else { VIR_DEBUG("Got expected server cert fail"); } } else { if (data->expectServerFail) { VIR_WARN("Expected server cert check fail"); goto cleanup; } else { VIR_DEBUG("No unexpected server cert fail"); } } /* * And the same for the client validation check */ if (virNetTLSContextCheckCertificate(clientCtxt, clientSess) < 0) { if (!data->expectClientFail) { VIR_WARN("Unexpected client cert check fail"); goto cleanup; } else { VIR_DEBUG("Got expected client cert fail"); } } else { if (data->expectClientFail) { VIR_WARN("Expected client cert check fail"); goto cleanup; } else { VIR_DEBUG("No unexpected client cert fail"); } } ret = 0; cleanup: virObjectUnref(serverCtxt); virObjectUnref(clientCtxt); virObjectUnref(serverSess); virObjectUnref(clientSess); VIR_FORCE_CLOSE(channel[0]); VIR_FORCE_CLOSE(channel[1]); return ret; }