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
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/wait.h>
|
2011-06-30 15:06:48 +00:00
|
|
|
#include <signal.h>
|
2011-07-07 14:17:21 +00:00
|
|
|
#include <fcntl.h>
|
2015-05-21 15:27:15 +00:00
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
# include <ifaddrs.h>
|
|
|
|
#endif
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
#include <netdb.h>
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_NETINET_TCP_H
|
|
|
|
# include <netinet/tcp.h>
|
|
|
|
#endif
|
|
|
|
|
2012-12-14 18:06:33 +00:00
|
|
|
#ifdef HAVE_SYS_UCRED_H
|
|
|
|
# include <sys/ucred.h>
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
#include "c-ctype.h"
|
2013-03-20 13:06:04 +00:00
|
|
|
#ifdef WITH_SELINUX
|
2012-01-20 17:18:28 +00:00
|
|
|
# include <selinux/selinux.h>
|
|
|
|
#endif
|
|
|
|
|
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"
|
2014-09-07 18:41:11 +00:00
|
|
|
#include "dirname.h"
|
2011-10-21 10:13:21 +00:00
|
|
|
#include "passfd.h"
|
|
|
|
|
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;
|
|
|
|
bool client;
|
2016-11-09 14:28:32 +00:00
|
|
|
bool ownsFd;
|
2017-03-17 15:01:45 +00:00
|
|
|
bool quietEOF;
|
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
|
|
|
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
2010-12-10 12:22:03 +00:00
|
|
|
virNetTLSSessionPtr tlsSession;
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2010-12-10 12:22:03 +00:00
|
|
|
virNetSASLSessionPtr saslSession;
|
|
|
|
|
|
|
|
const char *saslDecoded;
|
|
|
|
size_t saslDecodedLength;
|
|
|
|
size_t saslDecodedOffset;
|
|
|
|
|
|
|
|
const char *saslEncoded;
|
|
|
|
size_t saslEncodedLength;
|
|
|
|
size_t saslEncodedOffset;
|
|
|
|
#endif
|
2013-01-08 21:34:15 +00:00
|
|
|
#if WITH_SSH2
|
2011-11-14 14:50:02 +00:00
|
|
|
virNetSSHSessionPtr sshSession;
|
|
|
|
#endif
|
2016-11-09 14:28:36 +00:00
|
|
|
#if WITH_LIBSSH
|
|
|
|
virNetLibsshSessionPtr libsshSession;
|
|
|
|
#endif
|
2010-12-06 17:03:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-07-11 13:35:51 +00:00
|
|
|
static virClassPtr virNetSocketClass;
|
|
|
|
static void virNetSocketDispose(void *obj);
|
|
|
|
|
|
|
|
static int virNetSocketOnceInit(void)
|
|
|
|
{
|
2013-01-09 21:27:28 +00:00
|
|
|
if (!(virNetSocketClass = virClassNew(virClassForObjectLockable(),
|
2013-01-09 17:37:27 +00:00
|
|
|
"virNetSocket",
|
2012-07-11 13:35:51 +00:00
|
|
|
sizeof(virNetSocket),
|
|
|
|
virNetSocketDispose)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virNetSocket)
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
virCommandPtr cmd = virCommandNewArgList(binary,
|
|
|
|
"--timeout=30",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
2013-10-09 10:03:02 +00:00
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "XDG_CACHE_HOME", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "XDG_CONFIG_HOME", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "XDG_RUNTIME_DIR", NULL);
|
2010-12-06 17:03:35 +00:00
|
|
|
virCommandClearCaps(cmd);
|
|
|
|
virCommandDaemonize(cmd);
|
|
|
|
ret = virCommandRun(cmd, NULL);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-05-21 15:27:15 +00:00
|
|
|
int virNetSocketCheckProtocols(bool *hasIPv4,
|
|
|
|
bool *hasIPv6)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
struct ifaddrs *ifaddr = NULL, *ifa;
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
int gaierr;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
|
|
|
|
*hasIPv4 = *hasIPv6 = false;
|
|
|
|
|
|
|
|
if (getifaddrs(&ifaddr) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot get host interface addresses"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
|
|
|
hints.ai_family = AF_INET6;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
|
|
if ((gaierr = getaddrinfo("::1", NULL, &hints, &ai)) != 0) {
|
|
|
|
if (gaierr == EAI_ADDRFAMILY ||
|
2015-08-11 09:49:18 +00:00
|
|
|
gaierr == EAI_FAMILY ||
|
|
|
|
gaierr == EAI_NONAME) {
|
2015-05-21 15:27:15 +00:00
|
|
|
*hasIPv6 = false;
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot resolve ::1 address: %s"),
|
|
|
|
gai_strerror(gaierr));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
|
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
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
#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
|
|
|
|
|
|
|
static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr,
|
|
|
|
virSocketAddrPtr remoteAddr,
|
|
|
|
bool isClient,
|
|
|
|
int fd, int errfd, pid_t pid)
|
|
|
|
{
|
|
|
|
virNetSocketPtr sock;
|
|
|
|
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,
|
2012-02-10 23:52:01 +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;
|
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;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
sock->client = isClient;
|
|
|
|
|
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",
|
|
|
|
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,
|
2010-12-06 17:03:35 +00:00
|
|
|
virNetSocketPtr **retsocks,
|
|
|
|
size_t *nretsocks)
|
|
|
|
{
|
|
|
|
virNetSocketPtr *socks = NULL;
|
|
|
|
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;
|
2014-05-29 09:21:25 +00:00
|
|
|
bool addrInUse = false;
|
|
|
|
bool familyNotSupported = false;
|
|
|
|
virSocketAddr tmp_addr;
|
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 &&
|
|
|
|
!(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 &&
|
|
|
|
virSocketAddrIsWildcard(&tmp_addr)))
|
|
|
|
hints.ai_flags |= AI_ADDRCONFIG;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
int e = getaddrinfo(nodename, service, &hints, &ai);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct addrinfo *runp = ai;
|
|
|
|
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) {
|
|
|
|
familyNotSupported = true;
|
|
|
|
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
|
|
|
|
|
|
|
|
if (bind(fd, runp->ai_addr, runp->ai_addrlen) < 0) {
|
|
|
|
if (errno != EADDRINUSE) {
|
|
|
|
virReportSystemError(errno, "%s", _("Unable to bind to port"));
|
|
|
|
goto error;
|
|
|
|
}
|
2011-07-26 00:14:02 +00:00
|
|
|
addrInUse = true;
|
2010-12-06 17:03:35 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family);
|
|
|
|
|
2013-07-04 10:15:05 +00:00
|
|
|
if (VIR_EXPAND_N(socks, nsocks, 1) < 0)
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, false, fd, -1, 0)))
|
|
|
|
goto error;
|
|
|
|
runp = runp->ai_next;
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
|
2014-05-29 09:21:25 +00:00
|
|
|
if (nsocks == 0 && familyNotSupported) {
|
|
|
|
virReportSystemError(EAFNOSUPPORT, "%s", _("Unable to bind to port"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2011-07-26 00:14:02 +00:00
|
|
|
if (nsocks == 0 &&
|
|
|
|
addrInUse) {
|
|
|
|
virReportSystemError(EADDRINUSE, "%s", _("Unable to bind to port"));
|
|
|
|
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);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if HAVE_SYS_UN_H
|
|
|
|
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,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
if (virStrcpyStatic(addr.data.un.sun_path, path) == NULL) {
|
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"),
|
|
|
|
path, (int) user, (int) grp);
|
2010-12-06 17:03:35 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0)))
|
|
|
|
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);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetSocketNewListenUNIX(const char *path ATTRIBUTE_UNUSED,
|
|
|
|
mode_t mask ATTRIBUTE_UNUSED,
|
2011-08-17 17:52:38 +00:00
|
|
|
uid_t user ATTRIBUTE_UNUSED,
|
2010-12-06 17:03:35 +00:00
|
|
|
gid_t grp ATTRIBUTE_UNUSED,
|
|
|
|
virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0)))
|
|
|
|
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,
|
2010-12-06 17:03:35 +00:00
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
struct addrinfo hints;
|
|
|
|
int fd = -1;
|
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
|
|
|
struct addrinfo *runp;
|
|
|
|
int savedErrno = ENOENT;
|
|
|
|
|
|
|
|
*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;
|
2010-12-06 17:03:35 +00:00
|
|
|
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
|
|
int e = getaddrinfo(nodename, service, &hints, &ai);
|
|
|
|
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;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0)))
|
|
|
|
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);
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-10 12:22:03 +00:00
|
|
|
#ifdef HAVE_SYS_UN_H
|
2010-12-06 17:03:35 +00:00
|
|
|
int virNetSocketNewConnectUNIX(const char *path,
|
|
|
|
bool spawnDaemon,
|
|
|
|
const char *binary,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
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
|
|
|
|
2016-01-12 01:01:24 +00:00
|
|
|
VIR_DEBUG("path=%s spawnDaemon=%d binary=%s", path, spawnDaemon,
|
|
|
|
NULLSTR(binary));
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
memset(&localAddr, 0, sizeof(localAddr));
|
|
|
|
memset(&remoteAddr, 0, sizeof(remoteAddr));
|
|
|
|
|
|
|
|
remoteAddr.len = sizeof(remoteAddr.data.un);
|
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if (spawnDaemon) {
|
|
|
|
const char *binname;
|
2011-12-06 21:46:22 +00:00
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if (spawnDaemon && !binary) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Auto-spawn of daemon requested, "
|
|
|
|
"but no binary specified"));
|
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
|
|
|
|
2014-09-07 18:41:11 +00:00
|
|
|
if (!(binname = last_component(binary)) || binname[0] == '\0') {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot determine basename for binary '%s'"),
|
|
|
|
binary);
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2014-09-07 18:41:11 +00:00
|
|
|
}
|
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if (!(rundir = virGetUserRuntimeDirectory()))
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
2014-09-07 18:41:11 +00:00
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if (virFileMakePathWithMode(rundir, 0700) < 0) {
|
|
|
|
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
|
|
|
|
2015-04-02 12:41:17 +00:00
|
|
|
if (virAsprintf(&lockpath, "%s/%s.lock", rundir, binname) < 0)
|
2015-04-24 09:56:34 +00:00
|
|
|
goto cleanup;
|
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;
|
|
|
|
if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) == NULL) {
|
|
|
|
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--;
|
2016-01-12 01:01:24 +00:00
|
|
|
if (!spawnDaemon ||
|
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) {
|
|
|
|
if (virNetSocketForkDaemon(binary) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
daemonLaunched = true;
|
|
|
|
}
|
2015-04-02 12:41:17 +00:00
|
|
|
|
2016-03-15 21:04:32 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0)))
|
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
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
|
|
|
|
return ret;
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
int virNetSocketNewConnectUNIX(const char *path ATTRIBUTE_UNUSED,
|
|
|
|
bool spawnDaemon ATTRIBUTE_UNUSED,
|
|
|
|
const char *binary ATTRIBUTE_UNUSED,
|
|
|
|
virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("UNIX sockets are not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
int virNetSocketNewConnectCommand(virCommandPtr cmd,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pipe(errfd) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("unable to create socket pair"));
|
|
|
|
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]);
|
|
|
|
|
|
|
|
if (!(*retsock = virNetSocketNew(NULL, NULL, true, sv[0], errfd[0], pid)))
|
|
|
|
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
|
|
|
|
int virNetSocketNewConnectCommand(virCommandPtr cmd ATTRIBUTE_UNUSED,
|
|
|
|
virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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,
|
2010-12-06 17:03:35 +00:00
|
|
|
const char *netcat,
|
2011-07-19 17:52:21 +00:00
|
|
|
const char *keyfile,
|
2010-12-06 17:03:35 +00:00
|
|
|
const char *path,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
2011-10-13 19:49:01 +00:00
|
|
|
char *quoted;
|
2010-12-06 17:03:35 +00:00
|
|
|
virCommandPtr cmd;
|
2011-10-13 19:49:01 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
*retsock = NULL;
|
|
|
|
|
|
|
|
cmd = virCommandNew(binary ? binary : "ssh");
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
2013-10-09 10:03:02 +00:00
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "KRB5CCNAME", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "SSH_AUTH_SOCK", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "SSH_ASKPASS", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "DISPLAY", NULL);
|
|
|
|
virCommandAddEnvPassBlockSUID(cmd, "XAUTHORITY", NULL);
|
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);
|
2010-12-06 17:03:35 +00:00
|
|
|
if (noTTY)
|
|
|
|
virCommandAddArgList(cmd, "-T", "-o", "BatchMode=yes",
|
|
|
|
"-e", "none", 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
|
|
|
|
|
|
|
if (!netcat)
|
|
|
|
netcat = "nc";
|
|
|
|
|
2017-08-11 16:19:53 +00:00
|
|
|
virCommandAddArgList(cmd, "--", nodename, "sh", "-c", NULL);
|
2011-10-13 19:49:01 +00:00
|
|
|
|
|
|
|
virBufferEscapeShell(&buf, netcat);
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0) {
|
2013-01-30 15:05:24 +00:00
|
|
|
virCommandFree(cmd);
|
2011-10-13 19:49:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
quoted = virBufferContentAndReset(&buf);
|
2011-07-08 19:07:29 +00:00
|
|
|
/*
|
|
|
|
* This ugly thing is a shell script to detect availability of
|
|
|
|
* the -q option for 'nc': debian and suse based distros need this
|
|
|
|
* flag to ensure the remote nc will exit on EOF, so it will go away
|
|
|
|
* when we close the connection tunnel. If it doesn't go away, subsequent
|
|
|
|
* connection attempts will hang.
|
|
|
|
*
|
|
|
|
* Fedora's 'nc' doesn't have this option, and defaults to the desired
|
|
|
|
* behavior.
|
|
|
|
*/
|
|
|
|
virCommandAddArgFormat(cmd,
|
2011-10-13 19:49:01 +00:00
|
|
|
"'if '%s' -q 2>&1 | grep \"requires an argument\" >/dev/null 2>&1; then "
|
2011-07-08 19:07:29 +00:00
|
|
|
"ARG=-q0;"
|
|
|
|
"else "
|
|
|
|
"ARG=;"
|
|
|
|
"fi;"
|
2011-10-13 19:49:01 +00:00
|
|
|
"'%s' $ARG -U %s'",
|
|
|
|
quoted, quoted, path);
|
2010-12-06 17:03:35 +00:00
|
|
|
|
2011-10-13 19:49:01 +00:00
|
|
|
VIR_FREE(quoted);
|
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,
|
2013-07-09 14:46:32 +00:00
|
|
|
virURIPtr uri,
|
2011-11-14 14:50:02 +00:00
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
virNetSocketPtr sock = NULL;
|
|
|
|
virNetSSHSessionPtr sess = NULL;
|
|
|
|
unsigned int verify;
|
|
|
|
int ret = -1;
|
|
|
|
int portN;
|
|
|
|
|
|
|
|
char *authMethodNext = NULL;
|
|
|
|
char *authMethodsCopy = NULL;
|
|
|
|
char *authMethod;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
if (virNetSSHSessionSetChannelCommand(sess, command) != 0)
|
|
|
|
goto error;
|
|
|
|
|
2013-05-03 12:47:53 +00:00
|
|
|
if (VIR_STRDUP(authMethodsCopy, authMethods) < 0)
|
2011-11-14 14:50:02 +00:00
|
|
|
goto error;
|
2013-05-03 12:47:53 +00:00
|
|
|
|
|
|
|
authMethodNext = authMethodsCopy;
|
2011-11-14 14:50:02 +00:00
|
|
|
|
|
|
|
while ((authMethod = strsep(&authMethodNext, ","))) {
|
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;
|
|
|
|
|
|
|
|
VIR_FREE(authMethodsCopy);
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:52:31 +00:00
|
|
|
error:
|
2011-11-14 14:50:02 +00:00
|
|
|
virObjectUnref(sock);
|
|
|
|
virObjectUnref(sess);
|
|
|
|
VIR_FREE(authMethodsCopy);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
|
|
|
virNetSocketNewConnectLibSSH2(const char *host ATTRIBUTE_UNUSED,
|
|
|
|
const char *port ATTRIBUTE_UNUSED,
|
2015-05-21 14:51:28 +00:00
|
|
|
int family ATTRIBUTE_UNUSED,
|
2011-11-14 14:50:02 +00:00
|
|
|
const char *username ATTRIBUTE_UNUSED,
|
|
|
|
const char *privkey ATTRIBUTE_UNUSED,
|
|
|
|
const char *knownHosts ATTRIBUTE_UNUSED,
|
|
|
|
const char *knownHostsVerify ATTRIBUTE_UNUSED,
|
|
|
|
const char *authMethods ATTRIBUTE_UNUSED,
|
|
|
|
const char *command ATTRIBUTE_UNUSED,
|
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
2013-07-09 14:46:32 +00:00
|
|
|
virURIPtr uri ATTRIBUTE_UNUSED,
|
2011-11-14 14:50:02 +00:00
|
|
|
virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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,
|
|
|
|
virURIPtr uri,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
virNetSocketPtr sock = NULL;
|
|
|
|
virNetLibsshSessionPtr sess = NULL;
|
|
|
|
unsigned int verify;
|
|
|
|
int ret = -1;
|
|
|
|
int portN;
|
|
|
|
|
|
|
|
char *authMethodNext = NULL;
|
|
|
|
char *authMethodsCopy = NULL;
|
|
|
|
char *authMethod;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
if (virNetLibsshSessionSetChannelCommand(sess, command) != 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (VIR_STRDUP(authMethodsCopy, authMethods) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
authMethodNext = authMethodsCopy;
|
|
|
|
|
|
|
|
while ((authMethod = strsep(&authMethodNext, ","))) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
VIR_FREE(authMethodsCopy);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virObjectUnref(sock);
|
|
|
|
virObjectUnref(sess);
|
|
|
|
VIR_FREE(authMethodsCopy);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int
|
|
|
|
virNetSocketNewConnectLibssh(const char *host ATTRIBUTE_UNUSED,
|
|
|
|
const char *port ATTRIBUTE_UNUSED,
|
|
|
|
int family ATTRIBUTE_UNUSED,
|
|
|
|
const char *username ATTRIBUTE_UNUSED,
|
|
|
|
const char *privkey ATTRIBUTE_UNUSED,
|
|
|
|
const char *knownHosts ATTRIBUTE_UNUSED,
|
|
|
|
const char *knownHostsVerify ATTRIBUTE_UNUSED,
|
|
|
|
const char *authMethods ATTRIBUTE_UNUSED,
|
|
|
|
const char *command ATTRIBUTE_UNUSED,
|
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
|
|
|
virURIPtr uri ATTRIBUTE_UNUSED,
|
|
|
|
virNetSocketPtr *retsock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
virCommandPtr cmd;
|
|
|
|
|
|
|
|
*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,
|
|
|
|
virNetSocketPtr *retsock)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*retsock = virNetSocketNew(&localAddr, NULL, true, sockfd, -1, -1)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-09 11:54:54 +00:00
|
|
|
virNetSocketPtr virNetSocketNewPostExecRestart(virJSONValuePtr object)
|
|
|
|
{
|
|
|
|
virSocketAddr localAddr;
|
|
|
|
virSocketAddr remoteAddr;
|
|
|
|
int fd, thepid, errfd;
|
|
|
|
bool isClient;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (virJSONValueObjectGetBoolean(object, "isClient", &isClient) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing isClient data in JSON document"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virNetSocketNew(&localAddr, &remoteAddr,
|
|
|
|
isClient, fd, errfd, thepid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virJSONValuePtr virNetSocketPreExecRestart(virNetSocketPtr sock)
|
|
|
|
{
|
|
|
|
virJSONValuePtr object = NULL;
|
|
|
|
|
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
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
2012-08-09 11:54:54 +00:00
|
|
|
if (sock->tlsSession) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("Unable to save socket state when TLS session is active"));
|
|
|
|
goto error;
|
|
|
|
}
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
2012-08-09 11:54:54 +00:00
|
|
|
|
|
|
|
if (!(object = virJSONValueNewObject()))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (virJSONValueObjectAppendBoolean(object, "isClient", sock->client) < 0)
|
|
|
|
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
|
|
|
{
|
2012-07-11 13:35:51 +00:00
|
|
|
virNetSocketPtr 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
/* If a server socket, then unlink UNIX path */
|
|
|
|
if (!sock->client &&
|
|
|
|
sock->localAddr.data.sa.sa_family == AF_UNIX &&
|
|
|
|
sock->localAddr.data.un.sun_path[0] != '\0')
|
|
|
|
unlink(sock->localAddr.data.un.sun_path);
|
|
|
|
#endif
|
|
|
|
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
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);
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
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
|
|
|
|
|
2016-11-09 14:28:32 +00:00
|
|
|
if (sock->ownsFd)
|
|
|
|
VIR_FORCE_CLOSE(sock->fd);
|
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
|
|
|
|
2016-06-20 13:55:55 +00:00
|
|
|
VIR_FREE(sock->localAddrStrSASL);
|
|
|
|
VIR_FREE(sock->remoteAddrStrSASL);
|
2016-06-20 13:48:47 +00:00
|
|
|
VIR_FREE(sock->remoteAddrStrURI);
|
2010-12-06 17:03:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virNetSocketGetFD(virNetSocketPtr sock)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-07 14:17:21 +00:00
|
|
|
int virNetSocketDupFD(virNetSocketPtr sock, bool cloexec)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
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
|
|
|
|
fd = dup(sock->fd);
|
|
|
|
if (fd < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to copy socket file handle"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
bool virNetSocketIsLocal(virNetSocketPtr sock)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-21 10:13:21 +00:00
|
|
|
bool virNetSocketHasPassFD(virNetSocketPtr sock)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-02 17:11:42 +00:00
|
|
|
int virNetSocketGetPort(virNetSocketPtr sock)
|
|
|
|
{
|
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)
|
2012-01-18 17:41:36 +00:00
|
|
|
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
|
|
|
|
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
|
|
|
{
|
2016-01-07 21:31:17 +00:00
|
|
|
# if defined(HAVE_STRUCT_SOCKPEERCRED)
|
|
|
|
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
|
|
|
|
|
2012-12-14 18:06:33 +00:00
|
|
|
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
|
|
|
|
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
|
2012-01-18 17:41:36 +00:00
|
|
|
int virNetSocketGetUNIXIdentity(virNetSocketPtr sock ATTRIBUTE_UNUSED,
|
|
|
|
uid_t *uid ATTRIBUTE_UNUSED,
|
|
|
|
gid_t *gid ATTRIBUTE_UNUSED,
|
2013-04-25 16:05:00 +00:00
|
|
|
pid_t *pid ATTRIBUTE_UNUSED,
|
|
|
|
unsigned long long *timestamp ATTRIBUTE_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
|
2013-04-25 10:33:43 +00:00
|
|
|
int virNetSocketGetSELinuxContext(virNetSocketPtr sock,
|
|
|
|
char **context)
|
2012-01-20 17:18:28 +00:00
|
|
|
{
|
|
|
|
security_context_t seccon = NULL;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-05-03 12:47:53 +00:00
|
|
|
if (VIR_STRDUP(*context, seccon) < 0)
|
2012-01-20 17:18:28 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
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
|
2013-04-25 10:33:43 +00:00
|
|
|
int virNetSocketGetSELinuxContext(virNetSocketPtr sock ATTRIBUTE_UNUSED,
|
|
|
|
char **context)
|
2012-01-20 17:18:28 +00:00
|
|
|
{
|
|
|
|
*context = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
|
|
|
|
int virNetSocketSetBlocking(virNetSocketPtr sock,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
const char *virNetSocketLocalAddrStringSASL(virNetSocketPtr 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
|
|
|
}
|
|
|
|
|
2016-06-20 14:01:50 +00:00
|
|
|
const char *virNetSocketRemoteAddrStringSASL(virNetSocketPtr 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
|
|
|
}
|
|
|
|
|
2016-06-20 13:48:47 +00:00
|
|
|
const char *virNetSocketRemoteAddrStringURI(virNetSocketPtr sock)
|
|
|
|
{
|
|
|
|
return sock->remoteAddrStrURI;
|
|
|
|
}
|
2010-12-10 12:22:03 +00:00
|
|
|
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
2010-12-10 12:22:03 +00:00
|
|
|
static ssize_t virNetSocketTLSSessionWrite(const char *buf,
|
|
|
|
size_t len,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetSocketPtr sock = opaque;
|
|
|
|
return write(sock->fd, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t virNetSocketTLSSessionRead(char *buf,
|
|
|
|
size_t len,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetSocketPtr sock = opaque;
|
|
|
|
return read(sock->fd, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void virNetSocketSetTLSSession(virNetSocketPtr sock,
|
|
|
|
virNetTLSSessionPtr sess)
|
|
|
|
{
|
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
|
|
|
}
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
2010-12-10 12:22:03 +00:00
|
|
|
|
2012-09-20 11:58:29 +00:00
|
|
|
#if WITH_SASL
|
2010-12-10 12:22:03 +00:00
|
|
|
void virNetSocketSetSASLSession(virNetSocketPtr sock,
|
|
|
|
virNetSASLSessionPtr sess)
|
|
|
|
{
|
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
|
|
|
|
|
|
|
|
|
|
|
|
bool virNetSocketHasCachedData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
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
|
2011-11-14 14:50:02 +00:00
|
|
|
static ssize_t virNetSocketLibSSH2Read(virNetSocketPtr sock,
|
|
|
|
char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetSSHChannelRead(sock->sshSession, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t virNetSocketLibSSH2Write(virNetSocketPtr sock,
|
|
|
|
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
|
|
|
|
static ssize_t virNetSocketLibsshRead(virNetSocketPtr sock,
|
|
|
|
char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetLibsshChannelRead(sock->libsshSession, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t virNetSocketLibsshWrite(virNetSocketPtr sock,
|
|
|
|
const char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
return virNetLibsshChannelWrite(sock->libsshSession, buf, len);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-11-08 09:13:27 +00:00
|
|
|
bool virNetSocketHasPendingData(virNetSocketPtr sock ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-10 12:22:03 +00:00
|
|
|
static ssize_t virNetSocketReadWire(virNetSocketPtr 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:
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
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 {
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
2010-12-10 12:22:03 +00:00
|
|
|
ret = read(sock->fd, buf, len);
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
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 */
|
|
|
|
while (elen && c_isspace(errout[elen - 1]))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-12-10 12:22:03 +00:00
|
|
|
static ssize_t virNetSocketWriteWire(virNetSocketPtr 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:
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
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 {
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
2010-12-10 12:22:03 +00:00
|
|
|
ret = write(sock->fd, buf, len);
|
2013-01-08 21:02:05 +00:00
|
|
|
#if WITH_GNUTLS
|
2010-12-10 12:22:03 +00:00
|
|
|
}
|
2013-01-07 14:54:18 +00:00
|
|
|
#endif
|
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
|
2010-12-10 12:22:03 +00:00
|
|
|
static ssize_t virNetSocketReadSASL(virNetSocketPtr sock, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
ssize_t got;
|
|
|
|
|
|
|
|
/* Need to read some more data off the wire */
|
|
|
|
if (sock->saslDecoded == NULL) {
|
|
|
|
ssize_t encodedLen = virNetSASLSessionGetMaxBufSize(sock->saslSession);
|
|
|
|
char *encoded;
|
2013-07-04 10:15:05 +00:00
|
|
|
if (VIR_ALLOC_N(encoded, encodedLen) < 0)
|
2010-12-10 12:22:03 +00:00
|
|
|
return -1;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t virNetSocketWriteSASL(virNetSocketPtr sock, const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
sock->saslEncoded = NULL;
|
|
|
|
sock->saslEncodedOffset = sock->saslEncodedLength = 0;
|
|
|
|
|
|
|
|
/* Mark as complete, so caller detects completion */
|
|
|
|
return tosend;
|
|
|
|
} 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
|
|
|
|
|
|
|
|
ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len)
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len)
|
|
|
|
{
|
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
|
|
|
|
*/
|
2011-10-21 10:13:21 +00:00
|
|
|
int virNetSocketSendFD(virNetSocketPtr sock, int fd)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
if (sendfd(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
|
|
|
|
*/
|
|
|
|
int virNetSocketRecvFD(virNetSocketPtr 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
|
|
|
|
2011-11-04 16:02:14 +00:00
|
|
|
if ((*fd = recvfd(sock->fd, O_CLOEXEC)) < 0) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-12 09:07:51 +00:00
|
|
|
int virNetSocketListen(virNetSocketPtr 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virNetSocketAccept(virNetSocketPtr sock, virNetSocketPtr *clientsock)
|
|
|
|
{
|
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,
|
2011-07-19 13:00:24 +00:00
|
|
|
fd, -1, 0)))
|
|
|
|
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:
|
2011-07-19 13:00:24 +00:00
|
|
|
VIR_FORCE_CLOSE(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
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-11 08:26:34 +00:00
|
|
|
static void virNetSocketEventHandle(int watch ATTRIBUTE_UNUSED,
|
|
|
|
int fd ATTRIBUTE_UNUSED,
|
2010-12-06 17:03:35 +00:00
|
|
|
int events,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetSocketPtr 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)
|
|
|
|
{
|
|
|
|
virNetSocketPtr sock = opaque;
|
|
|
|
virFreeCallback ff;
|
|
|
|
void *eopaque;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-07-19 13:11:33 +00:00
|
|
|
ff = sock->ff;
|
|
|
|
eopaque = sock->opaque;
|
|
|
|
sock->func = NULL;
|
|
|
|
sock->ff = NULL;
|
|
|
|
sock->opaque = 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
|
|
|
}
|
|
|
|
|
2010-12-06 17:03:35 +00:00
|
|
|
int virNetSocketAddIOCallback(virNetSocketPtr sock,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void virNetSocketUpdateIOCallback(virNetSocketPtr sock,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void virNetSocketRemoveIOCallback(virNetSocketPtr sock)
|
|
|
|
{
|
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
|
|
|
|
|
|
|
void virNetSocketClose(virNetSocketPtr sock)
|
|
|
|
{
|
|
|
|
if (!sock)
|
|
|
|
return;
|
|
|
|
|
2013-01-09 21:27:28 +00:00
|
|
|
virObjectLock(sock);
|
2011-08-04 08:54:58 +00:00
|
|
|
|
|
|
|
VIR_FORCE_CLOSE(sock->fd);
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
/* If a server socket, then unlink UNIX path */
|
|
|
|
if (!sock->client &&
|
|
|
|
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
|
|
|
|
virNetSocketSetQuietEOF(virNetSocketPtr sock)
|
|
|
|
{
|
|
|
|
sock->quietEOF = true;
|
|
|
|
}
|