2010-12-06 17:03:35 +00:00
|
|
|
/*
|
|
|
|
* virnetsocket.c: generic network socket handling
|
|
|
|
*
|
2014-07-16 06:00:19 +00:00
|
|
|
* Copyright (C) 2006-2014 Red Hat, Inc.
|
2010-12-06 17:03:35 +00:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-12-06 17:03:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2011-06-30 15:06:48 +00:00
|
|
|
#include <signal.h>
|
2011-07-07 14:17:21 +00:00
|
|
|
#include <fcntl.h>
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifdef WITH_IFADDRS_H
|
2015-05-21 15:27:15 +00:00
|
|
|
# include <ifaddrs.h>
|
|
|
|
#endif
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifdef WITH_SYS_UCRED_H
|
2012-12-14 18:06:33 +00:00
|
|
|
# include <sys/ucred.h>
|
|
|
|
#endif
|
|
|
|
|
2013-03-20 13:06:04 +00:00
|
|
|
#ifdef WITH_SELINUX
|
2012-01-20 17:18:28 +00:00
|
|
|
# include <selinux/selinux.h>
|
|
|
|
#endif
|
|
|
|
|
2020-01-08 12:11:16 +00:00
|
|
|
#include "virsocket.h"
|
2010-12-06 17:03:35 +00:00
|
|
|
#include "virnetsocket.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2012-12-13 15:49:48 +00:00
|
|
|
#include "virthread.h"
|
2014-09-07 18:41:11 +00:00
|
|
|
#include "virpidfile.h"
|
2014-02-27 13:41:11 +00:00
|
|
|
#include "virprobe.h"
|
2012-09-24 17:10:37 +00:00
|
|
|
#include "virprocess.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2011-10-21 10:13:21 +00:00
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
# include "virnetsshsession.h"
|
|
|
|
#endif
|
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
# include "virnetlibsshsession.h"
|
|
|
|
#endif
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_RPC
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("rpc.netsocket");
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
struct _virNetSocket {
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLockable parent;
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
int fd;
|
|
|
|
int watch;
|
|
|
|
pid_t pid;
|
|
|
|
int errfd;
|
2019-06-25 19:17:27 +00:00
|
|
|
bool isClient;
|
2016-11-09 14:28:32 +00:00
|
|
|
bool ownsFd;
|
2017-03-17 15:01:45 +00:00
|
|
|
bool quietEOF;
|
2019-06-25 19:17:27 +00:00
|
|
|
bool unlinkUNIX;
|
2011-07-19 13:11:33 +00:00
|
|
|
|
|
|
|
/* Event callback fields */
|
2010-12-06 17:03:35 +00:00
|
|
|
virNetSocketIOFunc func;
|
|
|
|
void *opaque;
|
2011-07-19 13:11:33 +00:00
|
|
|
virFreeCallback ff;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
2016-06-20 13:55:55 +00:00
|
|
|
char *localAddrStrSASL;
|
|
|
|
char *remoteAddrStrSASL;
|
2016-06-20 13:48:47 +00:00
|
|
|
char *remoteAddrStrURI;
|
2010-12-10 12:22:03 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetTLSSession *tlsSession;
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSASLSession *saslSession;
|
2010-12-10 12:22:03 +00:00
|
|
|
|
|
|
|
const char *saslDecoded;
|
|
|
|
size_t saslDecodedLength;
|
|
|
|
size_t saslDecodedOffset;
|
|
|
|
|
|
|
|
const char *saslEncoded;
|
|
|
|
size_t saslEncodedLength;
|
2017-12-18 17:41:12 +00:00
|
|
|
size_t saslEncodedRawLength;
|
2010-12-10 12:22:03 +00:00
|
|
|
size_t saslEncodedOffset;
|
|
|
|
#endif
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSSHSession *sshSession;
|
2011-11-14 14:50:02 +00:00
|
|
|
#endif
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetLibsshSession *libsshSession;
|
2016-11-09 14:28:36 +00:00
|
|
|
#endif
|
2010-12-06 17:03:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virClass *virNetSocketClass;
|
2012-07-11 13:35:51 +00:00
|
|
|
static void virNetSocketDispose(void *obj);
|
|
|
|
|
|
|
|
static int virNetSocketOnceInit(void)
|
|
|
|
{
|
2018-04-17 15:42:33 +00:00
|
|
|
if (!VIR_CLASS_NEW(virNetSocket, virClassForObjectLockable()))
|
2012-07-11 13:35:51 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:23:29 +00:00
|
|
|
VIR_ONCE_GLOBAL_INIT(virNetSocket);
|
2012-07-11 13:35:51 +00:00
|
|
|
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
#ifndef WIN32
|
2015-04-02 12:41:17 +00:00
|
|
|
static int virNetSocketForkDaemon(const char *binary)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
int ret;
|
2021-03-11 07:16:13 +00:00
|
|
|
virCommand *cmd = virCommandNewArgList(binary,
|
2019-07-18 14:50:42 +00:00
|
|
|
"--timeout=120",
|
2010-12-06 17:03:35 +00:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
2019-08-01 12:52:00 +00:00
|
|
|
virCommandAddEnvPass(cmd, "XDG_CACHE_HOME");
|
|
|
|
virCommandAddEnvPass(cmd, "XDG_CONFIG_HOME");
|
|
|
|
virCommandAddEnvPass(cmd, "XDG_RUNTIME_DIR");
|
2010-12-06 17:03:35 +00:00
|
|
|
virCommandClearCaps(cmd);
|
|
|
|
virCommandDaemonize(cmd);
|
|
|
|
ret = virCommandRun(cmd, NULL);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-07-15 11:48:44 +00:00
|
|
|
|
|
|
|
static int G_GNUC_UNUSED
|
|
|
|
virNetSocketCheckProtocolByLookup(const char *address,
|
|
|
|
int family,
|
|
|
|
bool *hasFamily)
|
2015-05-21 15:27:15 +00:00
|
|
|
{
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
int gaierr;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
2020-07-15 11:48:44 +00:00
|
|
|
hints.ai_family = family;
|
|
|
|
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
|
|
if ((gaierr = getaddrinfo(address, NULL, &hints, &ai)) != 0) {
|
|
|
|
*hasFamily = false;
|
|
|
|
|
|
|
|
if (gaierr == EAI_FAMILY ||
|
|
|
|
#ifdef EAI_ADDRFAMILY
|
|
|
|
gaierr == EAI_ADDRFAMILY ||
|
|
|
|
#endif
|
|
|
|
gaierr == EAI_NONAME) {
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot resolve %s address: %s"),
|
|
|
|
address,
|
|
|
|
gai_strerror(gaierr));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*hasFamily = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virNetSocketCheckProtocols(bool *hasIPv4,
|
|
|
|
bool *hasIPv6)
|
|
|
|
{
|
2020-09-01 11:27:44 +00:00
|
|
|
#ifdef WITH_IFADDRS_H
|
2020-07-15 11:48:44 +00:00
|
|
|
struct ifaddrs *ifaddr = NULL, *ifa;
|
2015-05-21 15:27:15 +00:00
|
|
|
|
|
|
|
*hasIPv4 = *hasIPv6 = false;
|
|
|
|
|
|
|
|
if (getifaddrs(&ifaddr) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot get host interface addresses"));
|
2019-10-21 18:19:01 +00:00
|
|
|
return -1;
|
2015-05-21 15:27:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
|
|
|
if (!ifa->ifa_addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET)
|
|
|
|
*hasIPv4 = true;
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET6)
|
|
|
|
*hasIPv6 = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
freeifaddrs(ifaddr);
|
|
|
|
|
2020-07-17 14:14:23 +00:00
|
|
|
if (*hasIPv4 &&
|
2020-07-15 11:48:46 +00:00
|
|
|
virNetSocketCheckProtocolByLookup("127.0.0.1", AF_INET, hasIPv4) < 0)
|
|
|
|
return -1;
|
2015-05-21 15:27:15 +00:00
|
|
|
|
2020-07-17 14:14:23 +00:00
|
|
|
if (*hasIPv6 &&
|
2020-07-15 11:48:45 +00:00
|
|
|
virNetSocketCheckProtocolByLookup("::1", AF_INET6, hasIPv6) < 0)
|
2020-07-15 11:48:44 +00:00
|
|
|
return -1;
|
2015-05-21 15:27:15 +00:00
|
|
|
|
2015-10-27 18:14:01 +00:00
|
|
|
VIR_DEBUG("Protocols: v4 %d v6 %d", *hasIPv4, *hasIPv6);
|
2015-05-21 15:27:15 +00:00
|
|
|
|
2019-10-21 18:19:01 +00:00
|
|
|
return 0;
|
2015-05-21 15:27:15 +00:00
|
|
|
#else
|
|
|
|
*hasIPv4 = *hasIPv6 = false;
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("Cannot check address family on this platform"));
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virNetSocket *
|
|
|
|
virNetSocketNew(virSocketAddr *localAddr,
|
|
|
|
virSocketAddr *remoteAddr,
|
2019-06-25 19:17:27 +00:00
|
|
|
bool isClient,
|
|
|
|
int fd,
|
|
|
|
int errfd,
|
|
|
|
pid_t pid,
|
|
|
|
bool unlinkUNIX)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock;
|
2010-12-06 17:03:35 +00:00
|
|
|
int no_slow_start = 1;
|
|
|
|
|
2012-07-11 13:35:51 +00:00
|
|
|
if (virNetSocketInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2012-02-10 23:52:01 +00:00
|
|
|
VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%lld",
|
2010-12-06 17:03:35 +00:00
|
|
|
localAddr, remoteAddr,
|
2018-04-25 12:42:34 +00:00
|
|
|
fd, errfd, (long long)pid);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
if (!(sock = virObjectLockableNew(virNetSocketClass)))
|
2011-07-19 13:00:24 +00:00
|
|
|
return NULL;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
if (localAddr)
|
|
|
|
sock->localAddr = *localAddr;
|
|
|
|
if (remoteAddr)
|
|
|
|
sock->remoteAddr = *remoteAddr;
|
|
|
|
sock->fd = fd;
|
|
|
|
sock->errfd = errfd;
|
|
|
|
sock->pid = pid;
|
2015-06-18 12:22:10 +00:00
|
|
|
sock->watch = -1;
|
2016-11-09 14:28:32 +00:00
|
|
|
sock->ownsFd = true;
|
2019-06-25 19:17:27 +00:00
|
|
|
sock->isClient = isClient;
|
|
|
|
sock->unlinkUNIX = unlinkUNIX;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
/* 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 &&
|
2016-06-20 13:55:55 +00:00
|
|
|
!(sock->localAddrStrSASL = virSocketAddrFormatFull(localAddr, true, ";")))
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (remoteAddr &&
|
2016-06-20 13:55:55 +00:00
|
|
|
!(sock->remoteAddrStrSASL = virSocketAddrFormatFull(remoteAddr, true, ";")))
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
2016-06-20 13:48:47 +00:00
|
|
|
if (remoteAddr &&
|
|
|
|
!(sock->remoteAddrStrURI = virSocketAddrFormatFull(remoteAddr, true, NULL)))
|
|
|
|
goto error;
|
|
|
|
|
Rewrite all the DTrace/SystemTAP probing
The libvirtd daemon had a few crude system tap probes. Some of
these were broken during the RPC rewrite. The new modular RPC
code is structured in a way that allows much more effective
tracing. Instead of trying to hook up the original probes,
define a new set of probes for the RPC and event code.
The master probes file is now src/probes.d. This contains
probes for virNetServerClientPtr, virNetClientPtr, virSocketPtr
virNetTLSContextPtr and virNetTLSSessionPtr modules. Also add
probes for the poll event loop.
The src/dtrace2systemtap.pl script can convert the probes.d
file into a libvirt_probes.stp file to make use from systemtap
much simpler.
The src/rpc/gensystemtap.pl script can generate a set of
systemtap functions for translating RPC enum values into
printable strings. This works for all RPC header enums (program,
type, status, procedure) and also the authentication enum
The PROBE macro will automatically generate a VIR_DEBUG
statement, so any place with a PROBE can remove any existing
manual DEBUG statements.
* daemon/libvirtd.stp, daemon/probes.d: Remove obsolete probing
* daemon/libvirtd.h: Remove probe macros
* daemon/Makefile.am: Remove all probe buildings/install
* daemon/remote.c: Update authentication probes
* src/dtrace2systemtap.pl, src/rpc/gensystemtap.pl: Scripts
to generate STP files
* src/internal.h: Add probe macros
* src/probes.d: Master list of probes
* src/rpc/virnetclient.c, src/rpc/virnetserverclient.c,
src/rpc/virnetsocket.c, src/rpc/virnettlscontext.c,
src/util/event_poll.c: Insert probe points, removing any
DEBUG statements that duplicate the info
2011-09-30 13:40:23 +00:00
|
|
|
PROBE(RPC_SOCKET_NEW,
|
2012-07-11 13:35:51 +00:00
|
|
|
"sock=%p fd=%d errfd=%d pid=%lld localAddr=%s, remoteAddr=%s",
|
2018-04-25 12:42:34 +00:00
|
|
|
sock, fd, errfd, (long long)pid,
|
2016-06-20 13:55:55 +00:00
|
|
|
NULLSTR(sock->localAddrStrSASL), NULLSTR(sock->remoteAddrStrSASL));
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
return sock;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2010-12-06 17:03:35 +00:00
|
|
|
sock->fd = sock->errfd = -1; /* Caller owns fd/errfd on failure */
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virNetSocketNewListenTCP(const char *nodename,
|
|
|
|
const char *service,
|
2015-05-21 14:51:28 +00:00
|
|
|
int family,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket ***retsocks,
|
2010-12-06 17:03:35 +00:00
|
|
|
size_t *nretsocks)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **socks = NULL;
|
2010-12-06 17:03:35 +00:00
|
|
|
size_t nsocks = 0;
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
struct addrinfo hints;
|
|
|
|
int fd = -1;
|
Convert 'int i' to 'size_t i' in src/rpc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2018-07-24 14:12:15 +00:00
|
|
|
int socketErrno = 0;
|
|
|
|
int bindErrno = 0;
|
2014-05-29 09:21:25 +00:00
|
|
|
virSocketAddr tmp_addr;
|
2019-06-26 11:22:29 +00:00
|
|
|
int port = 0;
|
2020-07-28 17:50:28 +00:00
|
|
|
int e;
|
|
|
|
struct addrinfo *runp;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
*retsocks = NULL;
|
|
|
|
*nretsocks = 0;
|
|
|
|
|
2012-03-29 09:52:04 +00:00
|
|
|
memset(&hints, 0, sizeof(hints));
|
2015-05-21 14:51:28 +00:00
|
|
|
hints.ai_family = family;
|
2014-05-29 09:21:25 +00:00
|
|
|
hints.ai_flags = AI_PASSIVE;
|
2010-12-06 17:03:35 +00:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
2014-05-29 09:21:25 +00:00
|
|
|
/* Don't use ADDRCONFIG for binding to the wildcard address.
|
|
|
|
* Just catch the error returned by socket() if the system has
|
|
|
|
* no IPv6 support.
|
|
|
|
*
|
|
|
|
* This allows libvirtd to be started in parallel with the network
|
|
|
|
* startup in most cases.
|
|
|
|
*/
|
|
|
|
if (nodename &&
|
2018-03-26 18:53:05 +00:00
|
|
|
!(virSocketAddrParseAny(&tmp_addr, nodename, AF_UNSPEC, false) > 0 &&
|
2014-05-29 09:21:25 +00:00
|
|
|
virSocketAddrIsWildcard(&tmp_addr)))
|
|
|
|
hints.ai_flags |= AI_ADDRCONFIG;
|
|
|
|
|
2020-07-28 17:50:28 +00:00
|
|
|
e = getaddrinfo(nodename, service, &hints, &ai);
|
2010-12-06 17:03:35 +00:00
|
|
|
if (e != 0) {
|
2012-07-18 10:41:47 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("Unable to resolve address '%s' service '%s': %s"),
|
|
|
|
nodename, service, gai_strerror(e));
|
2010-12-06 17:03:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-28 17:50:28 +00:00
|
|
|
runp = ai;
|
2010-12-06 17:03:35 +00:00
|
|
|
while (runp) {
|
|
|
|
virSocketAddr addr;
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
|
|
|
if ((fd = socket(runp->ai_family, runp->ai_socktype,
|
|
|
|
runp->ai_protocol)) < 0) {
|
2014-05-29 09:21:25 +00:00
|
|
|
if (errno == EAFNOSUPPORT) {
|
2018-07-24 14:12:15 +00:00
|
|
|
socketErrno = errno;
|
2014-05-29 09:21:25 +00:00
|
|
|
runp = runp->ai_next;
|
|
|
|
continue;
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
virReportSystemError(errno, "%s", _("Unable to create socket"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-09-07 15:05:03 +00:00
|
|
|
if (virSetSockReuseAddr(fd, true) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
#ifdef IPV6_V6ONLY
|
|
|
|
if (runp->ai_family == PF_INET6) {
|
|
|
|
int on = 1;
|
|
|
|
/*
|
|
|
|
* Normally on Linux an INET6 socket will bind to the INET4
|
|
|
|
* address too. If getaddrinfo returns results with INET4
|
|
|
|
* first though, this will result in INET6 binding failing.
|
|
|
|
* We can trivially cope with multiple server sockets, so
|
|
|
|
* we force it to only listen on IPv6
|
|
|
|
*/
|
|
|
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
|
2012-03-29 09:52:04 +00:00
|
|
|
(void*)&on, sizeof(on)) < 0) {
|
2010-12-06 17:03:35 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to force bind to IPv6 only"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-06-26 11:22:29 +00:00
|
|
|
addr.len = runp->ai_addrlen;
|
|
|
|
memcpy(&addr.data.sa, runp->ai_addr, runp->ai_addrlen);
|
|
|
|
|
|
|
|
/* When service is NULL, we let the kernel auto-select the
|
|
|
|
* port. Once we've selected a port for one IP protocol
|
|
|
|
* though, we want to ensure we pick the same port for the
|
|
|
|
* other IP protocol
|
|
|
|
*/
|
|
|
|
if (port != 0 && service == NULL) {
|
|
|
|
if (addr.data.sa.sa_family == AF_INET) {
|
|
|
|
addr.data.inet4.sin_port = port;
|
|
|
|
} else if (addr.data.sa.sa_family == AF_INET6) {
|
|
|
|
addr.data.inet6.sin6_port = port;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Used saved port %d", port);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bind(fd, &addr.data.sa, addr.len) < 0) {
|
2018-07-24 14:15:14 +00:00
|
|
|
if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
|
2010-12-06 17:03:35 +00:00
|
|
|
virReportSystemError(errno, "%s", _("Unable to bind to port"));
|
|
|
|
goto error;
|
|
|
|
}
|
2018-07-24 14:12:15 +00:00
|
|
|
bindErrno = errno;
|
2020-01-08 12:11:16 +00:00
|
|
|
closesocket(fd);
|
|
|
|
fd = -1;
|
2011-07-26 00:14:02 +00:00
|
|
|
runp = runp->ai_next;
|
2010-12-06 17:03:35 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr.len = sizeof(addr.data);
|
|
|
|
if (getsockname(fd, &addr.data.sa, &addr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-06-26 11:22:29 +00:00
|
|
|
if (port == 0 && service == NULL) {
|
|
|
|
if (addr.data.sa.sa_family == AF_INET)
|
|
|
|
port = addr.data.inet4.sin_port;
|
|
|
|
else if (addr.data.sa.sa_family == AF_INET6)
|
|
|
|
port = addr.data.inet6.sin6_port;
|
|
|
|
VIR_DEBUG("Saved port %d", port);
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family);
|
|
|
|
|
2021-03-19 23:37:03 +00:00
|
|
|
VIR_EXPAND_N(socks, nsocks, 1);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, false, fd, -1, 0, false)))
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
runp = runp->ai_next;
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:12:15 +00:00
|
|
|
if (nsocks == 0) {
|
|
|
|
if (bindErrno)
|
|
|
|
virReportSystemError(bindErrno, "%s", _("Unable to bind to port"));
|
|
|
|
else if (socketErrno)
|
|
|
|
virReportSystemError(socketErrno, "%s", _("Unable to create socket"));
|
|
|
|
else
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("No addresses to bind to"));
|
2011-07-26 00:14:02 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
freeaddrinfo(ai);
|
|
|
|
|
|
|
|
*retsocks = socks;
|
|
|
|
*nretsocks = nsocks;
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2013-05-21 07:59:54 +00:00
|
|
|
for (i = 0; i < nsocks; i++)
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(socks[i]);
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FREE(socks);
|
|
|
|
freeaddrinfo(ai);
|
2020-01-08 12:11:16 +00:00
|
|
|
if (fd != -1)
|
|
|
|
closesocket(fd);
|
2010-12-06 17:03:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-14 17:38:59 +00:00
|
|
|
#ifndef WIN32
|
2010-12-06 17:03:35 +00:00
|
|
|
int virNetSocketNewListenUNIX(const char *path,
|
|
|
|
mode_t mask,
|
2011-08-12 09:10:19 +00:00
|
|
|
uid_t user,
|
2010-12-06 17:03:35 +00:00
|
|
|
gid_t grp,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
virSocketAddr addr;
|
|
|
|
mode_t oldmask;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
|
|
|
addr.len = sizeof(addr.data.un);
|
|
|
|
|
|
|
|
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Failed to create socket"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr.data.un.sun_family = AF_UNIX;
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(addr.data.un.sun_path, path) < 0) {
|
2011-11-02 20:39:31 +00:00
|
|
|
virReportSystemError(ENAMETOOLONG,
|
|
|
|
_("Path %s too long for unix socket"), path);
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (addr.data.un.sun_path[0] == '@')
|
|
|
|
addr.data.un.sun_path[0] = '\0';
|
|
|
|
else
|
|
|
|
unlink(addr.data.un.sun_path);
|
|
|
|
|
|
|
|
oldmask = umask(~mask);
|
|
|
|
|
|
|
|
if (bind(fd, &addr.data.sa, addr.len) < 0) {
|
|
|
|
umask(oldmask);
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to bind socket to '%s'"),
|
|
|
|
path);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
umask(oldmask);
|
|
|
|
|
|
|
|
/* chown() doesn't work for abstract sockets but we use them only
|
|
|
|
* if libvirtd runs unprivileged
|
|
|
|
*/
|
2011-08-12 09:10:19 +00:00
|
|
|
if (grp != 0 && chown(path, user, grp)) {
|
2010-12-06 17:03:35 +00:00
|
|
|
virReportSystemError(errno,
|
2011-08-12 09:10:19 +00:00
|
|
|
_("Failed to change ownership of '%s' to %d:%d"),
|
2018-04-25 12:42:34 +00:00
|
|
|
path, (int)user, (int)grp);
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0, true)))
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2010-12-06 17:03:35 +00:00
|
|
|
if (path[0] != '@')
|
|
|
|
unlink(path);
|
2020-01-08 12:11:16 +00:00
|
|
|
if (fd != -1)
|
|
|
|
closesocket(fd);
|
2010-12-06 17:03:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetSocketNewListenUNIX(const char *path G_GNUC_UNUSED,
|
|
|
|
mode_t mask G_GNUC_UNUSED,
|
|
|
|
uid_t user G_GNUC_UNUSED,
|
|
|
|
gid_t grp G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock G_GNUC_UNUSED)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("UNIX sockets are not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-08-09 14:09:19 +00:00
|
|
|
int virNetSocketNewListenFD(int fd,
|
2019-06-25 19:17:27 +00:00
|
|
|
bool unlinkUNIX,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2012-08-09 14:09:19 +00:00
|
|
|
{
|
|
|
|
virSocketAddr addr;
|
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
|
|
|
addr.len = sizeof(addr.data);
|
|
|
|
if (getsockname(fd, &addr.data.sa, &addr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0, unlinkUNIX)))
|
2012-08-09 14:09:19 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
int virNetSocketNewConnectTCP(const char *nodename,
|
|
|
|
const char *service,
|
2015-05-21 14:51:28 +00:00
|
|
|
int family,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
struct addrinfo hints;
|
|
|
|
int fd = -1;
|
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
|
|
|
struct addrinfo *runp;
|
|
|
|
int savedErrno = ENOENT;
|
2020-07-28 17:50:28 +00:00
|
|
|
int e;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
memset(&localAddr, 0, sizeof(localAddr));
|
|
|
|
memset(&remoteAddr, 0, sizeof(remoteAddr));
|
|
|
|
|
2012-03-29 09:52:04 +00:00
|
|
|
memset(&hints, 0, sizeof(hints));
|
2015-05-21 14:51:28 +00:00
|
|
|
hints.ai_family = family;
|
2020-03-02 08:26:51 +00:00
|
|
|
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_V4MAPPED;
|
2010-12-06 17:03:35 +00:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
2020-07-28 17:50:28 +00:00
|
|
|
e = getaddrinfo(nodename, service, &hints, &ai);
|
2010-12-06 17:03:35 +00:00
|
|
|
if (e != 0) {
|
2012-07-18 10:41:47 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("Unable to resolve address '%s' service '%s': %s"),
|
2012-10-17 09:23:12 +00:00
|
|
|
nodename, service, gai_strerror(e));
|
2010-12-06 17:03:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
runp = ai;
|
|
|
|
while (runp) {
|
|
|
|
if ((fd = socket(runp->ai_family, runp->ai_socktype,
|
|
|
|
runp->ai_protocol)) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to create socket"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-09-07 15:05:03 +00:00
|
|
|
if (virSetSockReuseAddr(fd, false) < 0)
|
2013-01-15 18:12:56 +00:00
|
|
|
VIR_WARN("Unable to enable port reuse");
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
if (connect(fd, runp->ai_addr, runp->ai_addrlen) >= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
savedErrno = errno;
|
2020-01-08 12:11:16 +00:00
|
|
|
closesocket(fd);
|
|
|
|
fd = -1;
|
2010-12-06 17:03:35 +00:00
|
|
|
runp = runp->ai_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd == -1) {
|
|
|
|
virReportSystemError(savedErrno,
|
|
|
|
_("unable to connect to server at '%s:%s'"),
|
|
|
|
nodename, service);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
localAddr.len = sizeof(localAddr.data);
|
|
|
|
if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
remoteAddr.len = sizeof(remoteAddr.data);
|
|
|
|
if (getpeername(fd, &remoteAddr.data.sa, &remoteAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get remote socket name"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0, false)))
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2010-12-06 17:03:35 +00:00
|
|
|
freeaddrinfo(ai);
|
2020-01-08 12:11:16 +00:00
|
|
|
if (fd != -1)
|
|
|
|
closesocket(fd);
|
2010-12-06 17:03:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-14 17:38:59 +00:00
|
|
|
#ifndef WIN32
|
2010-12-06 17:03:35 +00:00
|
|
|
int virNetSocketNewConnectUNIX(const char *path,
|
2021-05-24 14:07:19 +00:00
|
|
|
const char *spawnDaemonPath,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2015-04-02 12:41:17 +00:00
|
|
|
char *lockpath = NULL;
|
|
|
|
int lockfd = -1;
|
|
|
|
int fd = -1;
|
2016-03-15 21:04:32 +00:00
|
|
|
int retries = 500;
|
2010-12-06 17:03:35 +00:00
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
2015-04-02 12:41:17 +00:00
|
|
|
char *rundir = NULL;
|
2015-04-24 09:56:34 +00:00
|
|
|
int ret = -1;
|
2016-01-12 01:13:38 +00:00
|
|
|
bool daemonLaunched = false;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2021-05-24 14:07:19 +00:00
|
|
|
VIR_DEBUG("path=%s spawnDaemonPath=%s", path, NULLSTR(spawnDaemonPath));
|
2016-01-12 01:01:24 +00:00
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
memset(&localAddr, 0, sizeof(localAddr));
|
|
|
|
memset(&remoteAddr, 0, sizeof(remoteAddr));
|
|
|
|
|
|
|
|
remoteAddr.len = sizeof(remoteAddr.data.un);
|
|
|
|
|
2021-05-24 14:07:19 +00:00
|
|
|
if (spawnDaemonPath) {
|
|
|
|
g_autofree char *binname = g_path_get_basename(spawnDaemonPath);
|
2019-12-19 09:19:25 +00:00
|
|
|
rundir = virGetUserRuntimeDirectory();
|
2014-09-07 18:41:11 +00:00
|
|
|
|
2021-02-26 08:17:30 +00:00
|
|
|
if (g_mkdir_with_parents(rundir, 0700) < 0) {
|
2015-04-02 12:41:17 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot create user runtime directory '%s'"),
|
|
|
|
rundir);
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2014-09-07 15:08:57 +00:00
|
|
|
}
|
2014-07-16 06:00:19 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
lockpath = g_strdup_printf("%s/%s.lock", rundir, binname);
|
2014-07-16 06:00:19 +00:00
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if ((lockfd = open(lockpath, O_RDWR | O_CREAT, 0600)) < 0 ||
|
|
|
|
virSetCloseExec(lockfd) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to create lock '%s'"), lockpath);
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2014-09-07 15:08:57 +00:00
|
|
|
}
|
2014-07-16 06:00:19 +00:00
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if (virFileLock(lockfd, false, 0, 1, true) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to lock '%s'"), lockpath);
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2014-09-07 15:08:57 +00:00
|
|
|
}
|
2015-04-02 12:41:17 +00:00
|
|
|
}
|
2014-08-28 21:33:24 +00:00
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Failed to create socket"));
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2015-04-02 12:41:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
remoteAddr.data.un.sun_family = AF_UNIX;
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) < 0) {
|
2015-04-02 12:41:17 +00:00
|
|
|
virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path);
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2015-04-02 12:41:17 +00:00
|
|
|
}
|
|
|
|
if (remoteAddr.data.un.sun_path[0] == '@')
|
|
|
|
remoteAddr.data.un.sun_path[0] = '\0';
|
|
|
|
|
2016-01-12 01:01:24 +00:00
|
|
|
while (retries) {
|
|
|
|
if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) == 0) {
|
|
|
|
VIR_DEBUG("connect() succeeded");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("connect() failed: retries=%d errno=%d", retries, errno);
|
|
|
|
|
2016-01-12 01:08:45 +00:00
|
|
|
retries--;
|
2021-05-24 14:07:19 +00:00
|
|
|
if (!spawnDaemonPath ||
|
2016-01-12 01:08:45 +00:00
|
|
|
retries == 0 ||
|
2016-01-12 01:01:24 +00:00
|
|
|
(errno != ENOENT && errno != ECONNREFUSED)) {
|
2014-09-07 15:08:57 +00:00
|
|
|
virReportSystemError(errno, _("Failed to connect socket to '%s'"),
|
|
|
|
path);
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2014-08-28 21:33:24 +00:00
|
|
|
}
|
2014-09-07 15:08:57 +00:00
|
|
|
|
2016-01-12 01:13:38 +00:00
|
|
|
if (!daemonLaunched) {
|
2021-05-24 14:07:19 +00:00
|
|
|
if (virNetSocketForkDaemon(spawnDaemonPath) < 0)
|
2016-01-12 01:13:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
daemonLaunched = true;
|
|
|
|
}
|
2015-04-02 12:41:17 +00:00
|
|
|
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(10000);
|
2015-04-02 12:41:17 +00:00
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
localAddr.len = sizeof(localAddr.data);
|
|
|
|
if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0, false)))
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2015-04-24 09:56:34 +00:00
|
|
|
ret = 0;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2015-04-24 09:56:34 +00:00
|
|
|
cleanup:
|
2015-04-16 14:07:15 +00:00
|
|
|
if (lockfd != -1) {
|
2015-04-02 12:41:17 +00:00
|
|
|
unlink(lockpath);
|
2015-04-16 14:07:15 +00:00
|
|
|
VIR_FORCE_CLOSE(lockfd);
|
|
|
|
}
|
2015-04-02 12:41:17 +00:00
|
|
|
VIR_FREE(lockpath);
|
|
|
|
VIR_FREE(rundir);
|
2015-04-24 09:56:34 +00:00
|
|
|
|
2020-01-08 12:11:16 +00:00
|
|
|
if (ret < 0 && fd != -1)
|
|
|
|
closesocket(fd);
|
2015-04-24 09:56:34 +00:00
|
|
|
|
|
|
|
return ret;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
#else
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetSocketNewConnectUNIX(const char *path G_GNUC_UNUSED,
|
2021-06-05 04:38:32 +00:00
|
|
|
const char *spawnDaemonPath G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock G_GNUC_UNUSED)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("UNIX sockets are not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef WIN32
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketNewConnectCommand(virCommand *cmd,
|
|
|
|
virNetSocket **retsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
pid_t pid = 0;
|
2011-06-29 18:28:57 +00:00
|
|
|
int sv[2] = { -1, -1 };
|
|
|
|
int errfd[2] = { -1, -1 };
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
/* Fork off the external process. Use socketpair to create a private
|
|
|
|
* (unnamed) Unix domain socket to the child process so we don't have
|
|
|
|
* to faff around with two file descriptors (a la 'pipe(2)').
|
|
|
|
*/
|
|
|
|
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("unable to create socket pair"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-01-24 15:22:12 +00:00
|
|
|
if (virPipe(errfd) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandSetInputFD(cmd, sv[1]);
|
|
|
|
virCommandSetOutputFD(cmd, &sv[1]);
|
|
|
|
virCommandSetErrorFD(cmd, &errfd[1]);
|
|
|
|
|
|
|
|
if (virCommandRunAsync(cmd, &pid) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Parent continues here. */
|
|
|
|
VIR_FORCE_CLOSE(sv[1]);
|
|
|
|
VIR_FORCE_CLOSE(errfd[1]);
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(*retsock = virNetSocketNew(NULL, NULL, true, sv[0], errfd[0], pid, false)))
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FORCE_CLOSE(sv[0]);
|
|
|
|
VIR_FORCE_CLOSE(sv[1]);
|
|
|
|
VIR_FORCE_CLOSE(errfd[0]);
|
|
|
|
VIR_FORCE_CLOSE(errfd[1]);
|
|
|
|
|
|
|
|
virCommandAbort(cmd);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketNewConnectCommand(virCommand *cmd G_GNUC_UNUSED,
|
|
|
|
virNetSocket **retsock G_GNUC_UNUSED)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Tunnelling sockets not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int virNetSocketNewConnectSSH(const char *nodename,
|
|
|
|
const char *service,
|
|
|
|
const char *binary,
|
|
|
|
const char *username,
|
|
|
|
bool noTTY,
|
2011-07-11 19:50:31 +00:00
|
|
|
bool noVerify,
|
2011-07-19 17:52:21 +00:00
|
|
|
const char *keyfile,
|
2020-02-11 19:05:53 +00:00
|
|
|
const char *command,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virCommand *cmd;
|
2011-10-13 19:49:01 +00:00
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
cmd = virCommandNew(binary ? binary : "ssh");
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
2019-08-01 12:52:00 +00:00
|
|
|
virCommandAddEnvPass(cmd, "KRB5CCNAME");
|
|
|
|
virCommandAddEnvPass(cmd, "SSH_AUTH_SOCK");
|
|
|
|
virCommandAddEnvPass(cmd, "SSH_ASKPASS");
|
|
|
|
virCommandAddEnvPass(cmd, "DISPLAY");
|
|
|
|
virCommandAddEnvPass(cmd, "XAUTHORITY");
|
2010-12-06 17:03:35 +00:00
|
|
|
virCommandClearCaps(cmd);
|
|
|
|
|
|
|
|
if (service)
|
|
|
|
virCommandAddArgList(cmd, "-p", service, NULL);
|
|
|
|
if (username)
|
|
|
|
virCommandAddArgList(cmd, "-l", username, NULL);
|
2011-07-19 17:52:21 +00:00
|
|
|
if (keyfile)
|
|
|
|
virCommandAddArgList(cmd, "-i", keyfile, NULL);
|
2019-07-09 17:02:38 +00:00
|
|
|
virCommandAddArgList(cmd, "-T", "-e", "none", NULL);
|
2010-12-06 17:03:35 +00:00
|
|
|
if (noTTY)
|
2019-07-09 17:02:38 +00:00
|
|
|
virCommandAddArgList(cmd, "-o", "BatchMode=yes", NULL);
|
2011-07-11 19:50:31 +00:00
|
|
|
if (noVerify)
|
|
|
|
virCommandAddArgList(cmd, "-o", "StrictHostKeyChecking=no", NULL);
|
2011-07-08 19:07:29 +00:00
|
|
|
|
2020-02-11 19:05:53 +00:00
|
|
|
virCommandAddArgList(cmd, "--", nodename, command, NULL);
|
2011-07-08 19:07:29 +00:00
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
return virNetSocketNewConnectCommand(cmd, retsock);
|
|
|
|
}
|
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
int
|
|
|
|
virNetSocketNewConnectLibSSH2(const char *host,
|
|
|
|
const char *port,
|
2015-05-21 14:51:28 +00:00
|
|
|
int family,
|
2011-11-14 14:50:02 +00:00
|
|
|
const char *username,
|
|
|
|
const char *privkey,
|
|
|
|
const char *knownHosts,
|
|
|
|
const char *knownHostsVerify,
|
|
|
|
const char *authMethods,
|
|
|
|
const char *command,
|
|
|
|
virConnectAuthPtr auth,
|
2021-03-11 07:16:13 +00:00
|
|
|
virURI *uri,
|
|
|
|
virNetSocket **retsock)
|
2011-11-14 14:50:02 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = NULL;
|
|
|
|
virNetSSHSession *sess = NULL;
|
2011-11-14 14:50:02 +00:00
|
|
|
unsigned int verify;
|
|
|
|
int ret = -1;
|
|
|
|
int portN;
|
|
|
|
|
2020-12-01 08:21:32 +00:00
|
|
|
g_auto(GStrv) authMethodList = NULL;
|
2019-11-14 08:59:52 +00:00
|
|
|
char **authMethodNext;
|
2011-11-14 14:50:02 +00:00
|
|
|
|
|
|
|
/* port number will be verified while opening the socket */
|
|
|
|
if (virStrToLong_i(port, NULL, 10, &portN) < 0) {
|
|
|
|
virReportError(VIR_ERR_SSH, "%s",
|
|
|
|
_("Failed to parse port number"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create ssh session context */
|
|
|
|
if (!(sess = virNetSSHSessionNew()))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* set ssh session parameters */
|
|
|
|
if (virNetSSHSessionAuthSetCallback(sess, auth) != 0)
|
|
|
|
goto error;
|
|
|
|
|
2014-09-03 19:39:21 +00:00
|
|
|
if (STRCASEEQ("auto", knownHostsVerify)) {
|
2011-11-14 14:50:02 +00:00
|
|
|
verify = VIR_NET_SSH_HOSTKEY_VERIFY_AUTO_ADD;
|
2014-09-03 19:39:21 +00:00
|
|
|
} else if (STRCASEEQ("ignore", knownHostsVerify)) {
|
2011-11-14 14:50:02 +00:00
|
|
|
verify = VIR_NET_SSH_HOSTKEY_VERIFY_IGNORE;
|
2014-09-03 19:39:21 +00:00
|
|
|
} else if (STRCASEEQ("normal", knownHostsVerify)) {
|
2011-11-14 14:50:02 +00:00
|
|
|
verify = VIR_NET_SSH_HOSTKEY_VERIFY_NORMAL;
|
2014-09-03 19:39:21 +00:00
|
|
|
} else {
|
2011-11-14 14:50:02 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Invalid host key verification method: '%s'"),
|
|
|
|
knownHostsVerify);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetSSHSessionSetHostKeyVerification(sess,
|
|
|
|
host,
|
|
|
|
portN,
|
|
|
|
knownHosts,
|
2012-08-21 16:28:11 +00:00
|
|
|
verify,
|
|
|
|
VIR_NET_SSH_HOSTKEY_FILE_CREATE) != 0)
|
2011-11-14 14:50:02 +00:00
|
|
|
goto error;
|
|
|
|
|
2020-05-05 09:19:11 +00:00
|
|
|
virNetSSHSessionSetChannelCommand(sess, command);
|
2011-11-14 14:50:02 +00:00
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
if (!(authMethodList = g_strsplit(authMethods, ",", 0)))
|
2019-11-14 08:59:52 +00:00
|
|
|
goto error;
|
2013-05-03 12:47:53 +00:00
|
|
|
|
2019-11-14 08:59:52 +00:00
|
|
|
for (authMethodNext = authMethodList; *authMethodNext; authMethodNext++) {
|
|
|
|
const char *authMethod = *authMethodNext;
|
2011-11-14 14:50:02 +00:00
|
|
|
|
2014-09-03 19:39:21 +00:00
|
|
|
if (STRCASEEQ(authMethod, "keyboard-interactive")) {
|
2011-11-14 14:50:02 +00:00
|
|
|
ret = virNetSSHSessionAuthAddKeyboardAuth(sess, username, -1);
|
2014-09-03 19:39:21 +00:00
|
|
|
} else if (STRCASEEQ(authMethod, "password")) {
|
2011-11-14 14:50:02 +00:00
|
|
|
ret = virNetSSHSessionAuthAddPasswordAuth(sess,
|
2013-07-09 14:46:32 +00:00
|
|
|
uri,
|
|
|
|
username);
|
2014-09-03 19:39:21 +00:00
|
|
|
} else if (STRCASEEQ(authMethod, "privkey")) {
|
2011-11-14 14:50:02 +00:00
|
|
|
ret = virNetSSHSessionAuthAddPrivKeyAuth(sess,
|
|
|
|
username,
|
|
|
|
privkey,
|
|
|
|
NULL);
|
2014-09-03 19:39:21 +00:00
|
|
|
} else if (STRCASEEQ(authMethod, "agent")) {
|
2011-11-14 14:50:02 +00:00
|
|
|
ret = virNetSSHSessionAuthAddAgentAuth(sess, username);
|
2014-09-03 19:39:21 +00:00
|
|
|
} else {
|
2011-11-14 14:50:02 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Invalid authentication method: '%s'"),
|
|
|
|
authMethod);
|
|
|
|
ret = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* connect to remote server */
|
2015-05-21 14:51:28 +00:00
|
|
|
if ((ret = virNetSocketNewConnectTCP(host, port, family, &sock)) < 0)
|
2011-11-14 14:50:02 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* connect to the host using ssh */
|
|
|
|
if ((ret = virNetSSHSessionConnect(sess, virNetSocketGetFD(sock))) != 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
sock->sshSession = sess;
|
|
|
|
*retsock = sock;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2011-11-14 14:50:02 +00:00
|
|
|
virObjectUnref(sock);
|
|
|
|
virObjectUnref(sess);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetSocketNewConnectLibSSH2(const char *host G_GNUC_UNUSED,
|
|
|
|
const char *port G_GNUC_UNUSED,
|
|
|
|
int family G_GNUC_UNUSED,
|
|
|
|
const char *username G_GNUC_UNUSED,
|
|
|
|
const char *privkey G_GNUC_UNUSED,
|
|
|
|
const char *knownHosts G_GNUC_UNUSED,
|
|
|
|
const char *knownHostsVerify G_GNUC_UNUSED,
|
|
|
|
const char *authMethods G_GNUC_UNUSED,
|
|
|
|
const char *command G_GNUC_UNUSED,
|
|
|
|
virConnectAuthPtr auth G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virURI *uri G_GNUC_UNUSED,
|
|
|
|
virNetSocket **retsock G_GNUC_UNUSED)
|
2011-11-14 14:50:02 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("libssh2 transport support was not enabled"));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-01-08 21:34:15 +00:00
|
|
|
#endif /* WITH_SSH2 */
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
int
|
|
|
|
virNetSocketNewConnectLibssh(const char *host,
|
|
|
|
const char *port,
|
|
|
|
int family,
|
|
|
|
const char *username,
|
|
|
|
const char *privkey,
|
|
|
|
const char *knownHosts,
|
|
|
|
const char *knownHostsVerify,
|
|
|
|
const char *authMethods,
|
|
|
|
const char *command,
|
|
|
|
virConnectAuthPtr auth,
|
2021-03-11 07:16:13 +00:00
|
|
|
virURI *uri,
|
|
|
|
virNetSocket **retsock)
|
2016-11-09 14:28:36 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = NULL;
|
|
|
|
virNetLibsshSession *sess = NULL;
|
2016-11-09 14:28:36 +00:00
|
|
|
unsigned int verify;
|
|
|
|
int ret = -1;
|
|
|
|
int portN;
|
|
|
|
|
2020-12-01 08:21:32 +00:00
|
|
|
g_auto(GStrv) authMethodList = NULL;
|
2019-11-14 08:59:52 +00:00
|
|
|
char **authMethodNext;
|
2016-11-09 14:28:36 +00:00
|
|
|
|
|
|
|
/* port number will be verified while opening the socket */
|
|
|
|
if (virStrToLong_i(port, NULL, 10, &portN) < 0) {
|
|
|
|
virReportError(VIR_ERR_LIBSSH, "%s",
|
|
|
|
_("Failed to parse port number"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create ssh session context */
|
|
|
|
if (!(sess = virNetLibsshSessionNew(username)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* set ssh session parameters */
|
|
|
|
if (virNetLibsshSessionAuthSetCallback(sess, auth) != 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (STRCASEEQ("auto", knownHostsVerify)) {
|
|
|
|
verify = VIR_NET_LIBSSH_HOSTKEY_VERIFY_AUTO_ADD;
|
|
|
|
} else if (STRCASEEQ("ignore", knownHostsVerify)) {
|
|
|
|
verify = VIR_NET_LIBSSH_HOSTKEY_VERIFY_IGNORE;
|
|
|
|
} else if (STRCASEEQ("normal", knownHostsVerify)) {
|
|
|
|
verify = VIR_NET_LIBSSH_HOSTKEY_VERIFY_NORMAL;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Invalid host key verification method: '%s'"),
|
|
|
|
knownHostsVerify);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetLibsshSessionSetHostKeyVerification(sess,
|
|
|
|
host,
|
|
|
|
portN,
|
|
|
|
knownHosts,
|
|
|
|
verify) != 0)
|
|
|
|
goto error;
|
|
|
|
|
2020-05-05 09:19:11 +00:00
|
|
|
virNetLibsshSessionSetChannelCommand(sess, command);
|
2016-11-09 14:28:36 +00:00
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
if (!(authMethodList = g_strsplit(authMethods, ",", 0)))
|
2019-11-14 08:59:52 +00:00
|
|
|
goto error;
|
2016-11-09 14:28:36 +00:00
|
|
|
|
2019-11-14 08:59:52 +00:00
|
|
|
for (authMethodNext = authMethodList; *authMethodNext; authMethodNext++) {
|
|
|
|
const char *authMethod = *authMethodNext;
|
2016-11-09 14:28:36 +00:00
|
|
|
|
|
|
|
if (STRCASEEQ(authMethod, "keyboard-interactive")) {
|
|
|
|
ret = virNetLibsshSessionAuthAddKeyboardAuth(sess, -1);
|
|
|
|
} else if (STRCASEEQ(authMethod, "password")) {
|
|
|
|
ret = virNetLibsshSessionAuthAddPasswordAuth(sess, uri);
|
|
|
|
} else if (STRCASEEQ(authMethod, "privkey")) {
|
|
|
|
ret = virNetLibsshSessionAuthAddPrivKeyAuth(sess,
|
|
|
|
privkey,
|
|
|
|
NULL);
|
|
|
|
} else if (STRCASEEQ(authMethod, "agent")) {
|
|
|
|
ret = virNetLibsshSessionAuthAddAgentAuth(sess);
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Invalid authentication method: '%s'"),
|
|
|
|
authMethod);
|
|
|
|
ret = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* connect to remote server */
|
|
|
|
if ((ret = virNetSocketNewConnectTCP(host, port, family, &sock)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* connect to the host using ssh */
|
|
|
|
if ((ret = virNetLibsshSessionConnect(sess, virNetSocketGetFD(sock))) != 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
sock->libsshSession = sess;
|
|
|
|
/* libssh owns the FD and closes it on its own, and thus
|
|
|
|
* we must not close it (otherwise there are warnings about
|
|
|
|
* trying to close an invalid FD).
|
|
|
|
*/
|
|
|
|
sock->ownsFd = false;
|
|
|
|
*retsock = sock;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virObjectUnref(sock);
|
|
|
|
virObjectUnref(sess);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
2019-10-14 12:45:33 +00:00
|
|
|
virNetSocketNewConnectLibssh(const char *host G_GNUC_UNUSED,
|
|
|
|
const char *port G_GNUC_UNUSED,
|
|
|
|
int family G_GNUC_UNUSED,
|
|
|
|
const char *username G_GNUC_UNUSED,
|
|
|
|
const char *privkey G_GNUC_UNUSED,
|
|
|
|
const char *knownHosts G_GNUC_UNUSED,
|
|
|
|
const char *knownHostsVerify G_GNUC_UNUSED,
|
|
|
|
const char *authMethods G_GNUC_UNUSED,
|
|
|
|
const char *command G_GNUC_UNUSED,
|
|
|
|
virConnectAuthPtr auth G_GNUC_UNUSED,
|
2021-03-11 07:16:13 +00:00
|
|
|
virURI *uri G_GNUC_UNUSED,
|
|
|
|
virNetSocket **retsock G_GNUC_UNUSED)
|
2016-11-09 14:28:36 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("libssh transport support was not enabled"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif /* WITH_LIBSSH */
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
int virNetSocketNewConnectExternal(const char **cmdargv,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virCommand *cmd;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
cmd = virCommandNewArgs(cmdargv);
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
|
|
|
virCommandClearCaps(cmd);
|
|
|
|
|
|
|
|
return virNetSocketNewConnectCommand(cmd, retsock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-23 10:58:26 +00:00
|
|
|
int virNetSocketNewConnectSockFD(int sockfd,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket **retsock)
|
2013-09-23 10:58:26 +00:00
|
|
|
{
|
|
|
|
virSocketAddr localAddr;
|
|
|
|
|
|
|
|
localAddr.len = sizeof(localAddr.data);
|
|
|
|
if (getsockname(sockfd, &localAddr.data.sa, &localAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (!(*retsock = virNetSocketNew(&localAddr, NULL, true, sockfd, -1, -1, false)))
|
2013-09-23 10:58:26 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *virNetSocketNewPostExecRestart(virJSONValue *object)
|
2012-08-09 11:54:54 +00:00
|
|
|
{
|
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
|
|
|
int fd, thepid, errfd;
|
|
|
|
bool isClient;
|
2019-06-25 19:17:27 +00:00
|
|
|
bool unlinkUNIX;
|
2012-08-09 11:54:54 +00:00
|
|
|
|
|
|
|
if (virJSONValueObjectGetNumberInt(object, "fd", &fd) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing fd data in JSON document"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueObjectGetNumberInt(object, "pid", &thepid) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing pid data in JSON document"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virJSONValueObjectGetNumberInt(object, "errfd", &errfd) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing errfd data in JSON document"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-06-25 19:17:27 +00:00
|
|
|
|
2012-08-09 11:54:54 +00:00
|
|
|
if (virJSONValueObjectGetBoolean(object, "isClient", &isClient) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing isClient data in JSON document"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (virJSONValueObjectGetBoolean(object, "unlinkUNIX", &unlinkUNIX) < 0)
|
|
|
|
unlinkUNIX = !isClient;
|
|
|
|
|
2012-08-09 11:54:54 +00:00
|
|
|
memset(&localAddr, 0, sizeof(localAddr));
|
|
|
|
memset(&remoteAddr, 0, sizeof(remoteAddr));
|
|
|
|
|
|
|
|
remoteAddr.len = sizeof(remoteAddr.data.stor);
|
|
|
|
if (getsockname(fd, &remoteAddr.data.sa, &remoteAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get peer socket name"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
localAddr.len = sizeof(localAddr.data.stor);
|
|
|
|
if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
return virNetSocketNew(&localAddr, &remoteAddr, isClient,
|
|
|
|
fd, errfd, thepid, unlinkUNIX);
|
2012-08-09 11:54:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *virNetSocketPreExecRestart(virNetSocket *sock)
|
2012-08-09 11:54:54 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *object = NULL;
|
2012-08-09 11:54:54 +00:00
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-08-09 11:54:54 +00:00
|
|
|
|
2013-01-11 17:29:03 +00:00
|
|
|
#if WITH_SASL
|
2012-08-09 11:54:54 +00:00
|
|
|
if (sock->saslSession) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Unable to save socket state when SASL session is active"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (sock->tlsSession) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Unable to save socket state when TLS session is active"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-03-04 09:04:33 +00:00
|
|
|
object = virJSONValueNewObject();
|
2012-08-09 11:54:54 +00:00
|
|
|
|
|
|
|
if (virJSONValueObjectAppendNumberInt(object, "fd", sock->fd) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppendNumberInt(object, "errfd", sock->errfd) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppendNumberInt(object, "pid", sock->pid) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2019-06-25 19:17:27 +00:00
|
|
|
if (virJSONValueObjectAppendBoolean(object, "isClient", sock->isClient) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppendBoolean(object, "unlinkUNIX", sock->unlinkUNIX) < 0)
|
2012-08-09 11:54:54 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virSetInherit(sock->fd, true) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot disable close-on-exec flag on socket %d"),
|
|
|
|
sock->fd);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (sock->errfd != -1 &&
|
|
|
|
virSetInherit(sock->errfd, true) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot disable close-on-exec flag on pipe %d"),
|
|
|
|
sock->errfd);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2012-08-09 11:54:54 +00:00
|
|
|
return object;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2012-08-09 11:54:54 +00:00
|
|
|
virJSONValueFree(object);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-11 13:35:51 +00:00
|
|
|
void virNetSocketDispose(void *obj)
|
2011-10-07 15:39:37 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = obj;
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2013-03-13 19:17:32 +00:00
|
|
|
PROBE(RPC_SOCKET_DISPOSE,
|
|
|
|
"sock=%p", sock);
|
|
|
|
|
2015-06-18 12:22:10 +00:00
|
|
|
if (sock->watch >= 0) {
|
2010-12-06 17:03:35 +00:00
|
|
|
virEventRemoveHandle(sock->watch);
|
|
|
|
sock->watch = -1;
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:38:59 +00:00
|
|
|
#ifndef WIN32
|
2010-12-06 17:03:35 +00:00
|
|
|
/* If a server socket, then unlink UNIX path */
|
2019-06-25 19:17:27 +00:00
|
|
|
if (sock->unlinkUNIX &&
|
2010-12-06 17:03:35 +00:00
|
|
|
sock->localAddr.data.sa.sa_family == AF_UNIX &&
|
|
|
|
sock->localAddr.data.un.sun_path[0] != '\0')
|
|
|
|
unlink(sock->localAddr.data.un.sun_path);
|
|
|
|
#endif
|
|
|
|
|
2010-12-10 12:22:03 +00:00
|
|
|
/* Make sure it can't send any more I/O during shutdown */
|
|
|
|
if (sock->tlsSession)
|
|
|
|
virNetTLSSessionSetIOCallbacks(sock->tlsSession, NULL, NULL, NULL);
|
2012-07-11 13:35:48 +00:00
|
|
|
virObjectUnref(sock->tlsSession);
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2012-07-11 13:35:49 +00:00
|
|
|
virObjectUnref(sock->saslSession);
|
2010-12-10 12:22:03 +00:00
|
|
|
#endif
|
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
virObjectUnref(sock->sshSession);
|
|
|
|
#endif
|
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
virObjectUnref(sock->libsshSession);
|
|
|
|
#endif
|
|
|
|
|
2020-01-08 12:11:16 +00:00
|
|
|
if (sock->ownsFd && sock->fd != -1) {
|
|
|
|
closesocket(sock->fd);
|
|
|
|
sock->fd = -1;
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FORCE_CLOSE(sock->errfd);
|
|
|
|
|
2012-09-24 16:59:31 +00:00
|
|
|
virProcessAbort(sock->pid);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2021-02-03 20:14:57 +00:00
|
|
|
g_free(sock->localAddrStrSASL);
|
|
|
|
g_free(sock->remoteAddrStrSASL);
|
|
|
|
g_free(sock->remoteAddrStrURI);
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetFD(virNetSocket *sock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
int fd;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
fd = sock->fd;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return fd;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketDupFD(virNetSocket *sock, bool cloexec)
|
2011-07-07 14:17:21 +00:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2020-01-22 11:45:55 +00:00
|
|
|
#ifdef F_DUPFD_CLOEXEC
|
2011-07-07 14:17:21 +00:00
|
|
|
if (cloexec)
|
2013-05-03 10:10:50 +00:00
|
|
|
fd = fcntl(sock->fd, F_DUPFD_CLOEXEC, 0);
|
2011-07-07 14:17:21 +00:00
|
|
|
else
|
2020-01-22 11:45:55 +00:00
|
|
|
#endif /* F_DUPFD_CLOEXEC */
|
2011-07-07 14:17:21 +00:00
|
|
|
fd = dup(sock->fd);
|
|
|
|
if (fd < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to copy socket file handle"));
|
|
|
|
return -1;
|
|
|
|
}
|
2020-01-22 11:45:55 +00:00
|
|
|
#ifndef F_DUPFD_CLOEXEC
|
|
|
|
if (cloexec &&
|
2020-09-22 20:29:25 +00:00
|
|
|
virSetCloseExec(fd) < 0) {
|
2020-01-22 11:45:55 +00:00
|
|
|
int saveerr = errno;
|
|
|
|
closesocket(fd);
|
|
|
|
errno = saveerr;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif /* F_DUPFD_CLOEXEC */
|
|
|
|
|
2011-07-07 14:17:21 +00:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
bool virNetSocketIsLocal(virNetSocket *sock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
bool isLocal = false;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
if (sock->localAddr.data.sa.sa_family == AF_UNIX)
|
2011-07-19 13:00:24 +00:00
|
|
|
isLocal = true;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return isLocal;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
bool virNetSocketHasPassFD(virNetSocket *sock)
|
2011-10-21 10:13:21 +00:00
|
|
|
{
|
|
|
|
bool hasPassFD = false;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-10-21 10:13:21 +00:00
|
|
|
if (sock->localAddr.data.sa.sa_family == AF_UNIX)
|
|
|
|
hasPassFD = true;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-10-21 10:13:21 +00:00
|
|
|
return hasPassFD;
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
char *virNetSocketGetPath(virNetSocket *sock)
|
2019-06-24 10:48:12 +00:00
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
virObjectLock(sock);
|
|
|
|
path = virSocketAddrGetPath(&sock->localAddr);
|
|
|
|
virObjectUnlock(sock);
|
|
|
|
return path;
|
|
|
|
}
|
2011-10-21 10:13:21 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetPort(virNetSocket *sock)
|
2011-03-02 17:11:42 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
int port;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
port = virSocketAddrGetPort(&sock->localAddr);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return port;
|
2011-03-02 17:11:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-14 18:06:33 +00:00
|
|
|
#if defined(SO_PEERCRED)
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetUNIXIdentity(virNetSocket *sock,
|
2012-01-18 17:41:36 +00:00
|
|
|
uid_t *uid,
|
|
|
|
gid_t *gid,
|
2013-04-25 16:05:00 +00:00
|
|
|
pid_t *pid,
|
|
|
|
unsigned long long *timestamp)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2020-09-01 11:27:44 +00:00
|
|
|
# if defined(WITH_STRUCT_SOCKPEERCRED)
|
2016-01-07 21:31:17 +00:00
|
|
|
struct sockpeercred cr;
|
|
|
|
# else
|
2010-12-06 17:03:35 +00:00
|
|
|
struct ucred cr;
|
2016-01-07 21:31:17 +00:00
|
|
|
# endif
|
2012-03-29 09:52:04 +00:00
|
|
|
socklen_t cr_len = sizeof(cr);
|
2013-04-25 16:05:00 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
if (getsockopt(sock->fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Failed to get client socket identity"));
|
2013-04-25 16:05:00 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2014-11-19 14:54:14 +00:00
|
|
|
*timestamp = -1;
|
|
|
|
if (cr.pid && virProcessGetStartTime(cr.pid, timestamp) < 0)
|
2013-04-25 16:05:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2014-11-19 14:54:14 +00:00
|
|
|
if (cr.pid)
|
|
|
|
*pid = cr.pid;
|
|
|
|
else
|
|
|
|
*pid = -1;
|
2010-12-06 17:03:35 +00:00
|
|
|
*uid = cr.uid;
|
2011-12-16 00:18:22 +00:00
|
|
|
*gid = cr.gid;
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2013-04-25 16:05:00 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2013-04-25 16:05:00 +00:00
|
|
|
return ret;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
2012-12-14 18:06:33 +00:00
|
|
|
#elif defined(LOCAL_PEERCRED)
|
2013-04-25 16:05:00 +00:00
|
|
|
|
2013-10-10 21:31:47 +00:00
|
|
|
/* VIR_SOL_PEERCRED - the value needed to let getsockopt() work with
|
|
|
|
* LOCAL_PEERCRED
|
|
|
|
*/
|
2013-10-24 15:48:25 +00:00
|
|
|
|
|
|
|
/* Mac OS X 10.8 provides SOL_LOCAL for LOCAL_PEERCRED */
|
|
|
|
# ifdef SOL_LOCAL
|
|
|
|
# define VIR_SOL_PEERCRED SOL_LOCAL
|
2013-10-10 21:31:47 +00:00
|
|
|
# else
|
2013-10-24 15:48:25 +00:00
|
|
|
/* FreeBSD and Mac OS X prior to 10.7, SOL_LOCAL is not defined and
|
|
|
|
* users are expected to supply 0 as the second value for getsockopt()
|
|
|
|
* when using LOCAL_PEERCRED. NB SOL_SOCKET cannot be used instead
|
|
|
|
* of SOL_LOCAL
|
|
|
|
*/
|
|
|
|
# define VIR_SOL_PEERCRED 0
|
2013-10-10 21:31:47 +00:00
|
|
|
# endif
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetUNIXIdentity(virNetSocket *sock,
|
2012-12-14 18:06:33 +00:00
|
|
|
uid_t *uid,
|
|
|
|
gid_t *gid,
|
2013-04-25 16:05:00 +00:00
|
|
|
pid_t *pid,
|
2013-09-21 16:02:08 +00:00
|
|
|
unsigned long long *timestamp)
|
2012-12-14 18:06:33 +00:00
|
|
|
{
|
|
|
|
struct xucred cr;
|
|
|
|
socklen_t cr_len = sizeof(cr);
|
2013-10-17 12:21:57 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-12-14 18:06:33 +00:00
|
|
|
|
2013-10-17 12:21:57 +00:00
|
|
|
cr.cr_ngroups = -1;
|
2013-10-10 21:31:47 +00:00
|
|
|
if (getsockopt(sock->fd, VIR_SOL_PEERCRED, LOCAL_PEERCRED, &cr, &cr_len) < 0) {
|
2012-12-14 18:06:33 +00:00
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Failed to get client socket identity"));
|
2013-10-17 12:21:57 +00:00
|
|
|
goto cleanup;
|
2012-12-14 18:06:33 +00:00
|
|
|
}
|
|
|
|
|
2013-09-04 17:21:45 +00:00
|
|
|
if (cr.cr_version != XUCRED_VERSION) {
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
|
|
|
|
_("Failed to get valid client socket identity"));
|
2013-10-17 12:21:57 +00:00
|
|
|
goto cleanup;
|
2013-09-04 17:21:45 +00:00
|
|
|
}
|
|
|
|
|
2013-10-17 12:21:57 +00:00
|
|
|
if (cr.cr_ngroups <= 0 || cr.cr_ngroups > NGROUPS) {
|
2013-09-04 17:21:45 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
|
|
|
|
_("Failed to get valid client socket identity groups"));
|
2013-10-17 12:21:57 +00:00
|
|
|
goto cleanup;
|
2013-09-04 17:21:45 +00:00
|
|
|
}
|
|
|
|
|
2013-10-12 17:06:27 +00:00
|
|
|
/* PID and process creation time are not supported on BSDs by
|
|
|
|
* LOCAL_PEERCRED.
|
|
|
|
*/
|
2012-12-14 18:06:33 +00:00
|
|
|
*pid = -1;
|
2013-09-21 16:02:08 +00:00
|
|
|
*timestamp = -1;
|
2012-12-14 18:06:33 +00:00
|
|
|
*uid = cr.cr_uid;
|
|
|
|
*gid = cr.cr_gid;
|
|
|
|
|
2013-10-12 17:06:27 +00:00
|
|
|
# ifdef LOCAL_PEERPID
|
|
|
|
/* Exists on Mac OS X 10.8 for retrieving the peer's PID */
|
|
|
|
cr_len = sizeof(*pid);
|
|
|
|
|
|
|
|
if (getsockopt(sock->fd, VIR_SOL_PEERCRED, LOCAL_PEERPID, pid, &cr_len) < 0) {
|
|
|
|
/* Ensure this is set to something sane as there are no guarantees
|
|
|
|
* as to what its set to now.
|
|
|
|
*/
|
|
|
|
*pid = -1;
|
|
|
|
|
|
|
|
/* If this was built on a system with LOCAL_PEERPID defined but
|
|
|
|
* the kernel doesn't support it we'll get back EOPNOTSUPP so
|
|
|
|
* treat all errors but EOPNOTSUPP as fatal
|
|
|
|
*/
|
|
|
|
if (errno != EOPNOTSUPP) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Failed to get client socket PID"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
2013-10-17 12:21:57 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2013-10-17 12:21:57 +00:00
|
|
|
return ret;
|
2012-12-14 18:06:33 +00:00
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
#else
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetUNIXIdentity(virNetSocket *sock G_GNUC_UNUSED,
|
2019-10-14 12:45:33 +00:00
|
|
|
uid_t *uid G_GNUC_UNUSED,
|
|
|
|
gid_t *gid G_GNUC_UNUSED,
|
|
|
|
pid_t *pid G_GNUC_UNUSED,
|
|
|
|
unsigned long long *timestamp G_GNUC_UNUSED)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
/* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Client socket identity not available"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-20 13:06:04 +00:00
|
|
|
#ifdef WITH_SELINUX
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetSELinuxContext(virNetSocket *sock,
|
2013-04-25 10:33:43 +00:00
|
|
|
char **context)
|
2012-01-20 17:18:28 +00:00
|
|
|
{
|
2020-07-15 10:32:48 +00:00
|
|
|
char *seccon = NULL;
|
2012-01-20 17:18:28 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*context = NULL;
|
|
|
|
|
2013-03-20 13:06:04 +00:00
|
|
|
virObjectLock(sock);
|
2012-01-20 17:18:28 +00:00
|
|
|
if (getpeercon(sock->fd, &seccon) < 0) {
|
2013-03-20 19:01:18 +00:00
|
|
|
if (errno == ENOSYS || errno == ENOPROTOOPT) {
|
2012-01-20 17:18:28 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to query peer security context"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
*context = g_strdup(seccon);
|
2012-01-20 17:18:28 +00:00
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2012-01-20 17:18:28 +00:00
|
|
|
freecon(seccon);
|
2013-03-20 13:06:04 +00:00
|
|
|
virObjectUnlock(sock);
|
2012-01-20 17:18:28 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketGetSELinuxContext(virNetSocket *sock G_GNUC_UNUSED,
|
2013-04-25 10:33:43 +00:00
|
|
|
char **context)
|
2012-01-20 17:18:28 +00:00
|
|
|
{
|
|
|
|
*context = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketSetBlocking(virNetSocket *sock,
|
2010-12-06 17:03:35 +00:00
|
|
|
bool blocking)
|
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
int ret;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
ret = virSetBlocking(sock->fd, blocking);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return ret;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
const char *virNetSocketLocalAddrStringSASL(virNetSocket *sock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2016-06-20 13:55:55 +00:00
|
|
|
return sock->localAddrStrSASL;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
const char *virNetSocketRemoteAddrStringSASL(virNetSocket *sock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2016-06-20 13:55:55 +00:00
|
|
|
return sock->remoteAddrStrSASL;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
const char *virNetSocketRemoteAddrStringURI(virNetSocket *sock)
|
2016-06-20 13:48:47 +00:00
|
|
|
{
|
|
|
|
return sock->remoteAddrStrURI;
|
|
|
|
}
|
2010-12-10 12:22:03 +00:00
|
|
|
|
|
|
|
static ssize_t virNetSocketTLSSessionWrite(const char *buf,
|
|
|
|
size_t len,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = opaque;
|
2010-12-10 12:22:03 +00:00
|
|
|
return write(sock->fd, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t virNetSocketTLSSessionRead(char *buf,
|
|
|
|
size_t len,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = opaque;
|
2010-12-10 12:22:03 +00:00
|
|
|
return read(sock->fd, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
void virNetSocketSetTLSSession(virNetSocket *sock,
|
|
|
|
virNetTLSSession *sess)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-07-11 13:35:48 +00:00
|
|
|
virObjectUnref(sock->tlsSession);
|
|
|
|
sock->tlsSession = virObjectRef(sess);
|
2010-12-10 12:22:03 +00:00
|
|
|
virNetTLSSessionSetIOCallbacks(sess,
|
|
|
|
virNetSocketTLSSessionWrite,
|
|
|
|
virNetSocketTLSSessionRead,
|
|
|
|
sock);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
|
|
|
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2021-03-11 07:16:13 +00:00
|
|
|
void virNetSocketSetSASLSession(virNetSocket *sock,
|
|
|
|
virNetSASLSession *sess)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-07-11 13:35:49 +00:00
|
|
|
virObjectUnref(sock->saslSession);
|
|
|
|
sock->saslSession = virObjectRef(sess);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
bool virNetSocketHasCachedData(virNetSocket *sock G_GNUC_UNUSED)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
bool hasCached = false;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-11-14 14:50:02 +00:00
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
if (virNetSSHSessionHasCachedData(sock->sshSession))
|
|
|
|
hasCached = true;
|
|
|
|
#endif
|
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
if (virNetLibsshSessionHasCachedData(sock->libsshSession))
|
|
|
|
hasCached = true;
|
|
|
|
#endif
|
|
|
|
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2010-12-10 12:22:03 +00:00
|
|
|
if (sock->saslDecoded)
|
2011-07-19 13:00:24 +00:00
|
|
|
hasCached = true;
|
2010-12-10 12:22:03 +00:00
|
|
|
#endif
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return hasCached;
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketLibSSH2Read(virNetSocket *sock,
|
2011-11-14 14:50:02 +00:00
|
|
|
char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetSSHChannelRead(sock->sshSession, buf, len);
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketLibSSH2Write(virNetSocket *sock,
|
2011-11-14 14:50:02 +00:00
|
|
|
const char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetSSHChannelWrite(sock->sshSession, buf, len);
|
|
|
|
}
|
|
|
|
#endif
|
2010-12-10 12:22:03 +00:00
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketLibsshRead(virNetSocket *sock,
|
2016-11-09 14:28:36 +00:00
|
|
|
char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetLibsshChannelRead(sock->libsshSession, buf, len);
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketLibsshWrite(virNetSocket *sock,
|
2016-11-09 14:28:36 +00:00
|
|
|
const char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetLibsshChannelWrite(sock->libsshSession, buf, len);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
bool virNetSocketHasPendingData(virNetSocket *sock G_GNUC_UNUSED)
|
2011-11-08 09:13:27 +00:00
|
|
|
{
|
|
|
|
bool hasPending = false;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2011-11-08 09:13:27 +00:00
|
|
|
if (sock->saslEncoded)
|
|
|
|
hasPending = true;
|
|
|
|
#endif
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-11-08 09:13:27 +00:00
|
|
|
return hasPending;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketReadWire(virNetSocket *sock, char *buf, size_t len)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
char *errout = NULL;
|
|
|
|
ssize_t ret;
|
2011-11-14 14:50:02 +00:00
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
if (sock->sshSession)
|
|
|
|
return virNetSocketLibSSH2Read(sock, buf, len);
|
|
|
|
#endif
|
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
if (sock->libsshSession)
|
|
|
|
return virNetSocketLibsshRead(sock, buf, len);
|
|
|
|
#endif
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
reread:
|
2010-12-10 12:22:03 +00:00
|
|
|
if (sock->tlsSession &&
|
|
|
|
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
|
|
|
|
VIR_NET_TLS_HANDSHAKE_COMPLETE) {
|
|
|
|
ret = virNetTLSSessionRead(sock->tlsSession, buf, len);
|
|
|
|
} else {
|
|
|
|
ret = read(sock->fd, buf, len);
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
if ((ret < 0) && (errno == EINTR))
|
|
|
|
goto reread;
|
|
|
|
if ((ret < 0) && (errno == EAGAIN))
|
|
|
|
return 0;
|
2010-12-10 12:22:03 +00:00
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
if (ret <= 0 &&
|
|
|
|
sock->errfd != -1 &&
|
|
|
|
virFileReadLimFD(sock->errfd, 1024, &errout) >= 0 &&
|
|
|
|
errout != NULL) {
|
|
|
|
size_t elen = strlen(errout);
|
rpc: remove trailing whitespace character in error string
Instead of only removing the ending newline character, it is
better to remove all of standard whitespace character for the
sake of log format.
One example that we have to do this is:
After three times incorrect password input, virsh command
virsh -c qemu://remoteserver/system will report error like:
: Connection reset by peerey,gssapi-keyex,gssapi-with-mic,password).
But it should be:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
: Connection reset by peer
The reason is that we dropped the newline, but have a '\r' left.
The terminal interprets it as "move the cursor back to the start
of the current line", so the error string is messed up.
2012-07-18 15:02:02 +00:00
|
|
|
/* remove trailing whitespace */
|
2019-11-18 14:10:02 +00:00
|
|
|
while (elen && g_ascii_isspace(errout[elen - 1]))
|
rpc: remove trailing whitespace character in error string
Instead of only removing the ending newline character, it is
better to remove all of standard whitespace character for the
sake of log format.
One example that we have to do this is:
After three times incorrect password input, virsh command
virsh -c qemu://remoteserver/system will report error like:
: Connection reset by peerey,gssapi-keyex,gssapi-with-mic,password).
But it should be:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
: Connection reset by peer
The reason is that we dropped the newline, but have a '\r' left.
The terminal interprets it as "move the cursor back to the start
of the current line", so the error string is messed up.
2012-07-18 15:02:02 +00:00
|
|
|
errout[--elen] = '\0';
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errout)
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot recv data: %s"), errout);
|
|
|
|
else
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot recv data"));
|
|
|
|
ret = -1;
|
|
|
|
} else if (ret == 0) {
|
2017-03-17 15:01:45 +00:00
|
|
|
if (sock->quietEOF) {
|
|
|
|
VIR_DEBUG("socket='%p' EOF while reading: errout='%s'",
|
|
|
|
socket, NULLSTR(errout));
|
|
|
|
|
|
|
|
ret = -2;
|
|
|
|
} else {
|
|
|
|
if (errout)
|
|
|
|
virReportSystemError(EIO,
|
|
|
|
_("End of file while reading data: %s"),
|
|
|
|
errout);
|
|
|
|
else
|
|
|
|
virReportSystemError(EIO, "%s",
|
|
|
|
_("End of file while reading data"));
|
|
|
|
|
|
|
|
ret = -1;
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(errout);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketWriteWire(virNetSocket *sock, const char *buf, size_t len)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
|
|
|
ssize_t ret;
|
2011-11-14 14:50:02 +00:00
|
|
|
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
if (sock->sshSession)
|
|
|
|
return virNetSocketLibSSH2Write(sock, buf, len);
|
|
|
|
#endif
|
|
|
|
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
if (sock->libsshSession)
|
|
|
|
return virNetSocketLibsshWrite(sock, buf, len);
|
|
|
|
#endif
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
rewrite:
|
2010-12-10 12:22:03 +00:00
|
|
|
if (sock->tlsSession &&
|
|
|
|
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
|
|
|
|
VIR_NET_TLS_HANDSHAKE_COMPLETE) {
|
|
|
|
ret = virNetTLSSessionWrite(sock->tlsSession, buf, len);
|
|
|
|
} else {
|
|
|
|
ret = write(sock->fd, buf, len);
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto rewrite;
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot write data"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (ret == 0) {
|
|
|
|
virReportSystemError(EIO, "%s",
|
|
|
|
_("End of file while writing data"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketReadSASL(virNetSocket *sock, char *buf, size_t len)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
|
|
|
ssize_t got;
|
|
|
|
|
|
|
|
/* Need to read some more data off the wire */
|
|
|
|
if (sock->saslDecoded == NULL) {
|
|
|
|
ssize_t encodedLen = virNetSASLSessionGetMaxBufSize(sock->saslSession);
|
|
|
|
char *encoded;
|
2020-09-24 18:58:46 +00:00
|
|
|
encoded = g_new0(char, encodedLen);
|
2010-12-10 12:22:03 +00:00
|
|
|
encodedLen = virNetSocketReadWire(sock, encoded, encodedLen);
|
|
|
|
|
|
|
|
if (encodedLen <= 0) {
|
|
|
|
VIR_FREE(encoded);
|
|
|
|
return encodedLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetSASLSessionDecode(sock->saslSession,
|
|
|
|
encoded, encodedLen,
|
|
|
|
&sock->saslDecoded, &sock->saslDecodedLength) < 0) {
|
|
|
|
VIR_FREE(encoded);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(encoded);
|
|
|
|
|
|
|
|
sock->saslDecodedOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Some buffered decoded data to return now */
|
|
|
|
got = sock->saslDecodedLength - sock->saslDecodedOffset;
|
|
|
|
|
|
|
|
if (len > got)
|
|
|
|
len = got;
|
|
|
|
|
|
|
|
memcpy(buf, sock->saslDecoded + sock->saslDecodedOffset, len);
|
|
|
|
sock->saslDecodedOffset += len;
|
|
|
|
|
|
|
|
if (sock->saslDecodedOffset == sock->saslDecodedLength) {
|
|
|
|
sock->saslDecoded = NULL;
|
|
|
|
sock->saslDecodedOffset = sock->saslDecodedLength = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static ssize_t virNetSocketWriteSASL(virNetSocket *sock, const char *buf, size_t len)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
size_t tosend = virNetSASLSessionGetMaxBufSize(sock->saslSession);
|
|
|
|
|
|
|
|
/* SASL doesn't necessarily let us send the whole
|
|
|
|
buffer at once */
|
|
|
|
if (tosend > len)
|
|
|
|
tosend = len;
|
|
|
|
|
|
|
|
/* Not got any pending encoded data, so we need to encode raw stuff */
|
|
|
|
if (sock->saslEncoded == NULL) {
|
|
|
|
if (virNetSASLSessionEncode(sock->saslSession,
|
|
|
|
buf, tosend,
|
|
|
|
&sock->saslEncoded,
|
|
|
|
&sock->saslEncodedLength) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-12-18 17:41:12 +00:00
|
|
|
sock->saslEncodedRawLength = tosend;
|
2010-12-10 12:22:03 +00:00
|
|
|
sock->saslEncodedOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send some of the encoded stuff out on the wire */
|
|
|
|
ret = virNetSocketWriteWire(sock,
|
|
|
|
sock->saslEncoded + sock->saslEncodedOffset,
|
|
|
|
sock->saslEncodedLength - sock->saslEncodedOffset);
|
|
|
|
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret; /* -1 error, 0 == egain */
|
|
|
|
|
|
|
|
/* Note how much we sent */
|
|
|
|
sock->saslEncodedOffset += ret;
|
|
|
|
|
|
|
|
/* Sent all encoded, so update raw buffer to indicate completion */
|
|
|
|
if (sock->saslEncodedOffset == sock->saslEncodedLength) {
|
2017-12-18 17:41:12 +00:00
|
|
|
ssize_t done = sock->saslEncodedRawLength;
|
2010-12-10 12:22:03 +00:00
|
|
|
sock->saslEncoded = NULL;
|
2017-12-18 17:41:12 +00:00
|
|
|
sock->saslEncodedOffset = sock->saslEncodedLength = sock->saslEncodedRawLength = 0;
|
|
|
|
|
|
|
|
/* Mark as complete, so caller detects completion.
|
|
|
|
*
|
|
|
|
* Note that 'done' is possibly less than our current
|
|
|
|
* 'tosend' value, since if virNetSocketWriteWire
|
|
|
|
* only partially sent the data, we might have been
|
|
|
|
* called a 2nd time to write remaining cached
|
|
|
|
* encoded data. This means that the caller might
|
|
|
|
* also have further raw data pending that's included
|
|
|
|
* in 'tosend' */
|
|
|
|
return done;
|
2010-12-10 12:22:03 +00:00
|
|
|
} else {
|
|
|
|
/* Still have stuff pending in saslEncoded buffer.
|
|
|
|
* Pretend to caller that we didn't send any yet.
|
|
|
|
* The caller will then retry with same buffer
|
|
|
|
* shortly, which lets us finish saslEncoded.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
ssize_t virNetSocketRead(virNetSocket *sock, char *buf, size_t len)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
ssize_t ret;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2010-12-10 12:22:03 +00:00
|
|
|
if (sock->saslSession)
|
2011-07-19 13:00:24 +00:00
|
|
|
ret = virNetSocketReadSASL(sock, buf, len);
|
2010-12-10 12:22:03 +00:00
|
|
|
else
|
|
|
|
#endif
|
2011-07-19 13:00:24 +00:00
|
|
|
ret = virNetSocketReadWire(sock, buf, len);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return ret;
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
ssize_t virNetSocketWrite(virNetSocket *sock, const char *buf, size_t len)
|
2010-12-10 12:22:03 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
ssize_t ret;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2010-12-10 12:22:03 +00:00
|
|
|
if (sock->saslSession)
|
2011-07-19 13:00:24 +00:00
|
|
|
ret = virNetSocketWriteSASL(sock, buf, len);
|
2010-12-10 12:22:03 +00:00
|
|
|
else
|
|
|
|
#endif
|
2011-07-19 13:00:24 +00:00
|
|
|
ret = virNetSocketWriteWire(sock, buf, len);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return ret;
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-04 16:02:14 +00:00
|
|
|
/*
|
|
|
|
* Returns 1 if an FD was sent, 0 if it would block, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketSendFD(virNetSocket *sock, int fd)
|
2011-10-21 10:13:21 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
if (!virNetSocketHasPassFD(sock)) {
|
maint: don't permit format strings without %
Any time we have a string with no % passed through gettext, a
translator can inject a % to cause a stack overread. When there
is nothing to format, it's easier to ask for a string that cannot
be used as a formatter, by using a trivial "%s" format instead.
In the past, we have used --disable-nls to catch some of the
offenders, but that doesn't get run very often, and many more
uses have crept in. Syntax check to the rescue!
The syntax check can catch uses such as
virReportError(code,
_("split "
"string"));
by using a sed script to fold context lines into one pattern
space before checking for a string without %.
This patch is just mechanical insertion of %s; there are probably
several messages touched by this patch where we would be better
off giving the user more information than a fixed string.
* cfg.mk (sc_prohibit_diagnostic_without_format): New rule.
* src/datatypes.c (virUnrefConnect, virGetDomain)
(virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface)
(virUnrefInterface, virGetStoragePool, virUnrefStoragePool)
(virGetStorageVol, virUnrefStorageVol, virGetNodeDevice)
(virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter)
(virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper.
* src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters)
(lxcDomainGetBlkioParameters): Likewise.
* src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML)
(virDomainDiskDefParseXML, virDomainGraphicsDefParseXML):
Likewise.
* src/conf/network_conf.c (virNetworkDNSHostsDefParseXML)
(virNetworkDefParseXML): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterIsValidChainName):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple)
(virNWFilterVarAccessParse): Likewise.
* src/libvirt.c (virDomainSave, virDomainSaveFlags)
(virDomainRestore, virDomainRestoreFlags)
(virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML)
(virDomainCoreDump, virDomainGetXMLDesc)
(virDomainMigrateVersion1, virDomainMigrateVersion2)
(virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2)
(virStreamSendAll, virStreamRecvAll)
(virDomainSnapshotGetXMLDesc): Likewise.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterDHCPSnoopReq): Likewise.
* src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise.
* src/openvz/openvz_util.c (openvzKBPerPages): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise.
* src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr)
(qemuBuildCommandLine): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity):
Likewise.
* src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX)
(virNetSocketSendFD, virNetSocketRecvFD): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskBuildPool): Likewise.
* src/storage/storage_backend_fs.c
(virStorageBackendFileSystemProbe)
(virStorageBackendFileSystemBuild): Likewise.
* src/storage/storage_backend_rbd.c
(virStorageBackendRBDOpenRADOSConn): Likewise.
* src/storage/storage_driver.c (storageVolumeResize): Likewise.
* src/test/test_driver.c (testInterfaceChangeBegin)
(testInterfaceChangeCommit, testInterfaceChangeRollback):
Likewise.
* src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise.
* src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr):
Likewise.
* src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk)
(xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2012-07-18 10:41:47 +00:00
|
|
|
_("Sending file descriptors is not supported on this socket"));
|
2011-10-21 10:13:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-10-21 10:13:21 +00:00
|
|
|
PROBE(RPC_SOCKET_SEND_FD,
|
|
|
|
"sock=%p fd=%d", sock, fd);
|
2020-01-17 11:57:17 +00:00
|
|
|
if (virSocketSendFD(sock->fd, fd) < 0) {
|
2011-11-04 16:02:14 +00:00
|
|
|
if (errno == EAGAIN)
|
|
|
|
ret = 0;
|
|
|
|
else
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to send file descriptor %d"),
|
|
|
|
fd);
|
2011-10-21 10:13:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-11-04 16:02:14 +00:00
|
|
|
ret = 1;
|
2011-10-21 10:13:21 +00:00
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-10-21 10:13:21 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-04 16:02:14 +00:00
|
|
|
/*
|
|
|
|
* Returns 1 if an FD was read, 0 if it would block, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketRecvFD(virNetSocket *sock, int *fd)
|
2011-10-21 10:13:21 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
2011-11-04 16:02:14 +00:00
|
|
|
|
|
|
|
*fd = -1;
|
|
|
|
|
2011-10-21 10:13:21 +00:00
|
|
|
if (!virNetSocketHasPassFD(sock)) {
|
maint: don't permit format strings without %
Any time we have a string with no % passed through gettext, a
translator can inject a % to cause a stack overread. When there
is nothing to format, it's easier to ask for a string that cannot
be used as a formatter, by using a trivial "%s" format instead.
In the past, we have used --disable-nls to catch some of the
offenders, but that doesn't get run very often, and many more
uses have crept in. Syntax check to the rescue!
The syntax check can catch uses such as
virReportError(code,
_("split "
"string"));
by using a sed script to fold context lines into one pattern
space before checking for a string without %.
This patch is just mechanical insertion of %s; there are probably
several messages touched by this patch where we would be better
off giving the user more information than a fixed string.
* cfg.mk (sc_prohibit_diagnostic_without_format): New rule.
* src/datatypes.c (virUnrefConnect, virGetDomain)
(virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface)
(virUnrefInterface, virGetStoragePool, virUnrefStoragePool)
(virGetStorageVol, virUnrefStorageVol, virGetNodeDevice)
(virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter)
(virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper.
* src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters)
(lxcDomainGetBlkioParameters): Likewise.
* src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML)
(virDomainDiskDefParseXML, virDomainGraphicsDefParseXML):
Likewise.
* src/conf/network_conf.c (virNetworkDNSHostsDefParseXML)
(virNetworkDefParseXML): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterIsValidChainName):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple)
(virNWFilterVarAccessParse): Likewise.
* src/libvirt.c (virDomainSave, virDomainSaveFlags)
(virDomainRestore, virDomainRestoreFlags)
(virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML)
(virDomainCoreDump, virDomainGetXMLDesc)
(virDomainMigrateVersion1, virDomainMigrateVersion2)
(virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2)
(virStreamSendAll, virStreamRecvAll)
(virDomainSnapshotGetXMLDesc): Likewise.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterDHCPSnoopReq): Likewise.
* src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise.
* src/openvz/openvz_util.c (openvzKBPerPages): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise.
* src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr)
(qemuBuildCommandLine): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity):
Likewise.
* src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX)
(virNetSocketSendFD, virNetSocketRecvFD): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskBuildPool): Likewise.
* src/storage/storage_backend_fs.c
(virStorageBackendFileSystemProbe)
(virStorageBackendFileSystemBuild): Likewise.
* src/storage/storage_backend_rbd.c
(virStorageBackendRBDOpenRADOSConn): Likewise.
* src/storage/storage_driver.c (storageVolumeResize): Likewise.
* src/test/test_driver.c (testInterfaceChangeBegin)
(testInterfaceChangeCommit, testInterfaceChangeRollback):
Likewise.
* src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise.
* src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr):
Likewise.
* src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk)
(xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2012-07-18 10:41:47 +00:00
|
|
|
_("Receiving file descriptors is not supported on this socket"));
|
2011-10-21 10:13:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-10-21 10:13:21 +00:00
|
|
|
|
2020-01-17 11:57:17 +00:00
|
|
|
if ((*fd = virSocketRecvFD(sock->fd, O_CLOEXEC)) < 0) {
|
2011-11-04 16:02:14 +00:00
|
|
|
if (errno == EAGAIN)
|
|
|
|
ret = 0;
|
|
|
|
else
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Failed to recv file descriptor"));
|
2011-10-21 10:13:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
PROBE(RPC_SOCKET_RECV_FD,
|
2011-11-04 16:02:14 +00:00
|
|
|
"sock=%p fd=%d", sock, *fd);
|
|
|
|
ret = 1;
|
2011-10-21 10:13:21 +00:00
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-10-21 10:13:21 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketListen(virNetSocket *sock, int backlog)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-08-12 09:07:51 +00:00
|
|
|
if (listen(sock->fd, backlog > 0 ? backlog : 30) < 0) {
|
2010-12-06 17:03:35 +00:00
|
|
|
virReportSystemError(errno, "%s", _("Unable to listen on socket"));
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketAccept(virNetSocket *sock, virNetSocket **clientsock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
int fd = -1;
|
2010-12-06 17:03:35 +00:00
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
2011-07-19 13:00:24 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
*clientsock = NULL;
|
|
|
|
|
|
|
|
memset(&localAddr, 0, sizeof(localAddr));
|
|
|
|
memset(&remoteAddr, 0, sizeof(remoteAddr));
|
|
|
|
|
|
|
|
remoteAddr.len = sizeof(remoteAddr.data.stor);
|
|
|
|
if ((fd = accept(sock->fd, &remoteAddr.data.sa, &remoteAddr.len)) < 0) {
|
|
|
|
if (errno == ECONNABORTED ||
|
2011-07-19 13:00:24 +00:00
|
|
|
errno == EAGAIN) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to accept client"));
|
2011-07-19 13:00:24 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
localAddr.len = sizeof(localAddr.data);
|
|
|
|
if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to get local socket name"));
|
2011-07-19 13:00:24 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*clientsock = virNetSocketNew(&localAddr,
|
|
|
|
&remoteAddr,
|
|
|
|
true,
|
2019-06-25 19:17:27 +00:00
|
|
|
fd, -1, 0,
|
|
|
|
false)))
|
2011-07-19 13:00:24 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2011-07-19 13:00:24 +00:00
|
|
|
fd = -1;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2020-01-08 12:11:16 +00:00
|
|
|
if (fd != -1)
|
|
|
|
closesocket(fd);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return ret;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-14 12:45:33 +00:00
|
|
|
static void virNetSocketEventHandle(int watch G_GNUC_UNUSED,
|
|
|
|
int fd G_GNUC_UNUSED,
|
2010-12-06 17:03:35 +00:00
|
|
|
int events,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = opaque;
|
2011-07-19 13:00:24 +00:00
|
|
|
virNetSocketIOFunc func;
|
|
|
|
void *eopaque;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
func = sock->func;
|
|
|
|
eopaque = sock->opaque;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
|
|
|
|
if (func)
|
|
|
|
func(sock, events, eopaque);
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2011-07-19 13:11:33 +00:00
|
|
|
static void virNetSocketEventFree(void *opaque)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocket *sock = opaque;
|
2011-07-19 13:11:33 +00:00
|
|
|
virFreeCallback ff;
|
|
|
|
void *eopaque;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2021-03-24 15:49:39 +00:00
|
|
|
ff = sock->ff;
|
2021-03-24 09:32:58 +00:00
|
|
|
eopaque = g_steal_pointer(&sock->opaque);
|
2011-07-19 13:11:33 +00:00
|
|
|
sock->func = NULL;
|
2021-03-24 15:49:39 +00:00
|
|
|
sock->ff = NULL;
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-07-19 13:11:33 +00:00
|
|
|
|
|
|
|
if (ff)
|
|
|
|
ff(eopaque);
|
|
|
|
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(sock);
|
2011-07-19 13:11:33 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
int virNetSocketAddIOCallback(virNetSocket *sock,
|
2010-12-06 17:03:35 +00:00
|
|
|
int events,
|
|
|
|
virNetSocketIOFunc func,
|
2011-07-19 13:11:33 +00:00
|
|
|
void *opaque,
|
|
|
|
virFreeCallback ff)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2011-07-19 13:00:24 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectRef(sock);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2015-06-18 12:22:10 +00:00
|
|
|
if (sock->watch >= 0) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Watch already registered on socket %p", sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((sock->watch = virEventAddHandle(sock->fd,
|
|
|
|
events,
|
|
|
|
virNetSocketEventHandle,
|
|
|
|
sock,
|
2011-07-19 13:11:33 +00:00
|
|
|
virNetSocketEventFree)) < 0) {
|
2011-06-28 16:39:02 +00:00
|
|
|
VIR_DEBUG("Failed to register watch on socket %p", sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
goto cleanup;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
sock->func = func;
|
|
|
|
sock->opaque = opaque;
|
2011-07-19 13:11:33 +00:00
|
|
|
sock->ff = ff;
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2011-07-19 13:00:24 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
cleanup:
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-10-07 15:39:37 +00:00
|
|
|
if (ret != 0)
|
2012-07-11 13:35:51 +00:00
|
|
|
virObjectUnref(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
return ret;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
void virNetSocketUpdateIOCallback(virNetSocket *sock,
|
2010-12-06 17:03:35 +00:00
|
|
|
int events)
|
|
|
|
{
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2015-06-18 12:22:10 +00:00
|
|
|
if (sock->watch < 0) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Watch not registered on socket %p", sock);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
virEventUpdateHandle(sock->watch, events);
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
void virNetSocketRemoveIOCallback(virNetSocket *sock)
|
2010-12-06 17:03:35 +00:00
|
|
|
{
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2015-06-18 12:22:10 +00:00
|
|
|
if (sock->watch < 0) {
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_DEBUG("Watch not registered on socket %p", sock);
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
virEventRemoveHandle(sock->watch);
|
2015-06-18 12:15:08 +00:00
|
|
|
/* Don't unref @sock, it's done via eventloop callback. */
|
2015-06-18 12:22:10 +00:00
|
|
|
sock->watch = -1;
|
2011-07-19 13:00:24 +00:00
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
2011-08-04 08:54:58 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
void virNetSocketClose(virNetSocket *sock)
|
2011-08-04 08:54:58 +00:00
|
|
|
{
|
|
|
|
if (!sock)
|
|
|
|
return;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-08-04 08:54:58 +00:00
|
|
|
|
2020-01-08 12:11:16 +00:00
|
|
|
if (sock->fd != -1) {
|
|
|
|
closesocket(sock->fd);
|
|
|
|
sock->fd = -1;
|
|
|
|
}
|
2011-08-04 08:54:58 +00:00
|
|
|
|
2020-01-14 17:38:59 +00:00
|
|
|
#ifndef WIN32
|
2011-08-04 08:54:58 +00:00
|
|
|
/* If a server socket, then unlink UNIX path */
|
2019-06-25 19:17:27 +00:00
|
|
|
if (sock->unlinkUNIX &&
|
2011-08-04 08:54:58 +00:00
|
|
|
sock->localAddr.data.sa.sa_family == AF_UNIX &&
|
|
|
|
sock->localAddr.data.un.sun_path[0] != '\0') {
|
|
|
|
if (unlink(sock->localAddr.data.un.sun_path) == 0)
|
|
|
|
sock->localAddr.data.un.sun_path[0] = '\0';
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectUnlock(sock);
|
2011-08-04 08:54:58 +00:00
|
|
|
}
|
2017-03-17 15:01:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetSocketSetQuietEOF:
|
|
|
|
* @sock: socket object pointer
|
|
|
|
*
|
|
|
|
* Disables reporting I/O errors as a virError when @socket is closed while
|
|
|
|
* reading data.
|
|
|
|
*/
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetSocketSetQuietEOF(virNetSocket *sock)
|
2017-03-17 15:01:45 +00:00
|
|
|
{
|
|
|
|
sock->quietEOF = true;
|
|
|
|
}
|