int virNetServerClientInit(virNetServerClientPtr client) { virObjectLock(client); #if WITH_GNUTLS if (!client->tlsCtxt) { #endif /* Plain socket, so prepare to read first message */ if (virNetServerClientRegisterEvent(client) < 0) goto error; #if WITH_GNUTLS } else { int ret; if (!(client->tls = virNetTLSSessionNew(client->tlsCtxt, NULL))) goto error; virNetSocketSetTLSSession(client->sock, client->tls); /* Begin the TLS handshake. */ ret = virNetTLSSessionHandshake(client->tls); if (ret == 0) { /* Unlikely, but ... Next step is to check the certificate. */ if (virNetServerClientCheckAccess(client) < 0) goto error; /* Handshake & cert check OK, so prepare to read first message */ if (virNetServerClientRegisterEvent(client) < 0) goto error; } else if (ret > 0) { /* Most likely, need to do more handshake data */ if (virNetServerClientRegisterEvent(client) < 0) goto error; } else { goto error; } } #endif virObjectUnlock(client); return 0; error: client->wantClose = true; virObjectUnlock(client); return -1; }
int virNetClientSetTLSSession(virNetClientPtr client, virNetTLSContextPtr tls) { int ret; char buf[1]; int len; struct pollfd fds[1]; sigset_t oldmask, blockedsigs; sigemptyset (&blockedsigs); #ifdef SIGWINCH sigaddset (&blockedsigs, SIGWINCH); #endif #ifdef SIGCHLD sigaddset (&blockedsigs, SIGCHLD); #endif sigaddset (&blockedsigs, SIGPIPE); virNetClientLock(client); if (!(client->tls = virNetTLSSessionNew(tls, client->hostname))) goto error; virNetSocketSetTLSSession(client->sock, client->tls); for (;;) { ret = virNetTLSSessionHandshake(client->tls); if (ret < 0) goto error; if (ret == 0) break; fds[0].fd = virNetSocketGetFD(client->sock); fds[0].revents = 0; if (virNetTLSSessionGetHandshakeStatus(client->tls) == VIR_NET_TLS_HANDSHAKE_RECVING) fds[0].events = POLLIN; else fds[0].events = POLLOUT; /* Block SIGWINCH from interrupting poll in curses programs, * then restore the original signal mask again immediately * after the call (RHBZ#567931). Same for SIGCHLD and SIGPIPE * at the suggestion of Paolo Bonzini and Daniel Berrange. */ ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); repoll: ret = poll(fds, ARRAY_CARDINALITY(fds), -1); if (ret < 0 && errno == EAGAIN) goto repoll; ignore_value(pthread_sigmask(SIG_BLOCK, &oldmask, NULL)); } ret = virNetTLSContextCheckCertificate(tls, client->tls); if (ret < 0) goto error; /* At this point, the server is verifying _our_ certificate, IP address, * etc. If we make the grade, it will send us a '\1' byte. */ fds[0].fd = virNetSocketGetFD(client->sock); fds[0].revents = 0; fds[0].events = POLLIN; /* Block SIGWINCH from interrupting poll in curses programs */ ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); repoll2: ret = poll(fds, ARRAY_CARDINALITY(fds), -1); if (ret < 0 && errno == EAGAIN) goto repoll2; ignore_value(pthread_sigmask(SIG_BLOCK, &oldmask, NULL)); len = virNetTLSSessionRead(client->tls, buf, 1); if (len < 0 && errno != ENOMSG) { virReportSystemError(errno, "%s", _("Unable to read TLS confirmation")); goto error; } if (len != 1 || buf[0] != '\1') { virNetError(VIR_ERR_RPC, "%s", _("server verification (of our certificate or IP " "address) failed")); goto error; } virNetClientUnlock(client); return 0; error: virNetTLSSessionFree(client->tls); client->tls = NULL; virNetClientUnlock(client); return -1; }