1 /*
2 * remote_sockets.c: helpers for getting remote driver socket paths
3 *
4 * Copyright (C) 2007-2019 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include "remote_sockets.h"
24 #include "virerror.h"
25 #include "virlog.h"
26 #include "virfile.h"
27 #include "virutil.h"
28 #include "configmake.h"
29
30 #define VIR_FROM_THIS VIR_FROM_REMOTE
31
32 VIR_LOG_INIT("remote.remote_sockets");
33
34 VIR_ENUM_IMPL(remoteDriverTransport,
35 REMOTE_DRIVER_TRANSPORT_LAST,
36 "tls",
37 "unix",
38 "ssh",
39 "libssh2",
40 "ext",
41 "tcp",
42 "libssh");
43
44 VIR_ENUM_IMPL(remoteDriverMode,
45 REMOTE_DRIVER_MODE_LAST,
46 "auto",
47 "legacy",
48 "direct");
49
50 #ifndef WIN32
51 static const char *
remoteGetDaemonPathEnv(void)52 remoteGetDaemonPathEnv(void)
53 {
54 /* We prefer a VIRTD_PATH env var to use for all daemons,
55 * but if it is not set we will fallback to LIBVIRTD_PATH
56 * for previous behaviour
57 */
58 if (getenv("VIRTD_PATH") != NULL) {
59 return "VIRTD_PATH";
60 } else {
61 return "LIBVIRTD_PATH";
62 }
63 }
64 #endif /* WIN32 */
65
66
67 int
remoteSplitURIScheme(virURI * uri,char ** driver,remoteDriverTransport * transport)68 remoteSplitURIScheme(virURI *uri,
69 char **driver,
70 remoteDriverTransport *transport)
71 {
72 char *p = strchr(uri->scheme, '+');
73
74 if (p)
75 *driver = g_strndup(uri->scheme, p - uri->scheme);
76 else
77 *driver = g_strdup(uri->scheme);
78
79 if (p) {
80 g_autofree char *tmp = g_strdup(p + 1);
81 int val;
82
83 p = tmp;
84 while (*p) {
85 *p = g_ascii_tolower(*p);
86 p++;
87 }
88
89 if ((val = remoteDriverTransportTypeFromString(tmp)) < 0) {
90 virReportError(VIR_ERR_INVALID_ARG, "%s",
91 _("remote_open: transport in URL not recognised "
92 "(should be tls|unix|ssh|ext|tcp|libssh2|libssh)"));
93 return -1;
94 }
95
96 if (val == REMOTE_DRIVER_TRANSPORT_UNIX &&
97 uri->server) {
98 virReportError(VIR_ERR_INVALID_ARG,
99 _("using unix socket and remote "
100 "server '%s' is not supported."),
101 uri->server);
102 return -1;
103 }
104
105 *transport = val;
106 } else {
107 if (uri->server)
108 *transport = REMOTE_DRIVER_TRANSPORT_TLS;
109 else
110 *transport = REMOTE_DRIVER_TRANSPORT_UNIX;
111 }
112
113 return 0;
114 }
115
116
117 static char *
remoteGetUNIXSocketHelper(remoteDriverTransport transport,const char * sock_prefix,unsigned int flags)118 remoteGetUNIXSocketHelper(remoteDriverTransport transport,
119 const char *sock_prefix,
120 unsigned int flags)
121 {
122 char *sockname = NULL;
123 g_autofree char *userdir = NULL;
124
125 if (flags & REMOTE_DRIVER_OPEN_USER) {
126 userdir = virGetUserRuntimeDirectory();
127
128 sockname = g_strdup_printf("%s/%s-sock", userdir, sock_prefix);
129 } else {
130 /* Intentionally do *NOT* use RUNSTATEDIR here. We might
131 * be connecting to a remote machine, and cannot assume
132 * the remote host has /run. The converse is ok though,
133 * any machine with /run will have a /var/run symlink.
134 * The portable option is to thus use $LOCALSTATEDIR/run
135 */
136 sockname = g_strdup_printf("%s/run/libvirt/%s-%s", LOCALSTATEDIR,
137 sock_prefix,
138 flags & REMOTE_DRIVER_OPEN_RO ?
139 "sock-ro" : "sock");
140 }
141
142 VIR_DEBUG("Built UNIX sockname=%s for transport=%s "
143 "prefix=%s flags=0x%x",
144 sockname, remoteDriverTransportTypeToString(transport),
145 sock_prefix, flags);
146 return sockname;
147 }
148
149 /*
150 * Determine which driver is probably usable based on
151 * which modular daemon binaries are installed.
152 */
153 int
remoteProbeSessionDriverFromBinary(char ** driver)154 remoteProbeSessionDriverFromBinary(char **driver)
155 {
156 /* Order these the same as virDriverLoadModule
157 * calls in daemonInitialize, so we replicate
158 * probing order that virConnectOpen would use
159 * if running inside libvirtd */
160 const char *drivers[] = {
161 #ifdef WITH_QEMU
162 "qemu",
163 #endif
164 #ifdef WITH_VBOX
165 "vbox",
166 #endif
167 };
168 ssize_t i;
169
170 VIR_DEBUG("Probing for driver from daemon binaries");
171
172 *driver = NULL;
173
174 for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) {
175 g_autofree char *daemonname = NULL;
176 g_autofree char *daemonpath = NULL;
177
178 daemonname = g_strdup_printf("virt%sd", drivers[i]);
179 VIR_DEBUG("Probing driver '%s' via daemon %s", drivers[i], daemonpath);
180
181 if (!(daemonpath = virFileFindResource(daemonname,
182 abs_top_builddir "/src",
183 SBINDIR)))
184 return -1;
185
186 if (virFileExists(daemonpath)) {
187 VIR_DEBUG("Found driver '%s' via daemon %s", drivers[i], daemonpath);
188 *driver = g_strdup(drivers[i]);
189 return 0;
190 }
191
192 VIR_DEBUG("Missing daemon %s for driver %s", daemonpath, drivers[i]);
193 }
194
195 VIR_DEBUG("No more drivers to probe for");
196 return 0;
197 }
198
199
200 int
remoteProbeSystemDriverFromSocket(bool readonly,char ** driver)201 remoteProbeSystemDriverFromSocket(bool readonly, char **driver)
202 {
203 /* Order these the same as virDriverLoadModule
204 * calls in daemonInitialize, so we replicate
205 * probing order that virConnectOpen would use
206 * if running inside libvirtd */
207 const char *drivers[] = {
208 #ifdef WITH_LIBXL
209 "xen",
210 #endif
211 #ifdef WITH_QEMU
212 "qemu",
213 #endif
214 #ifdef WITH_LXC
215 "lxc",
216 #endif
217 #ifdef WITH_VBOX
218 "vbox",
219 #endif
220 #ifdef WITH_BHYVE
221 "bhyve",
222 #endif
223 #ifdef WITH_VZ
224 "vz",
225 #endif
226 };
227 ssize_t i;
228
229 for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) {
230 g_autofree char *sockname =
231 g_strdup_printf("%s/libvirt/virt%sd-%s", RUNSTATEDIR,
232 drivers[i], readonly ? "sock-ro" : "sock");
233
234 if (virFileExists(sockname)) {
235 VIR_DEBUG("Probed driver '%s' via sock '%s'", drivers[i], sockname);
236 *driver = g_strdup(drivers[i]);
237 return 0;
238 }
239
240 VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]);
241 }
242
243 /* Even if we didn't probe any socket, we won't
244 * return error. Just let virConnectOpen's normal
245 * logic run which will likely return an error anyway
246 */
247 VIR_DEBUG("No more drivers to probe for");
248 return 0;
249 }
250
251 int
remoteProbeSessionDriverFromSocket(bool readonly,char ** driver)252 remoteProbeSessionDriverFromSocket(bool readonly, char **driver)
253 {
254 /* Order these the same as virDriverLoadModule
255 * calls in daemonInitialize */
256 const char *drivers[] = {
257 #ifdef WITH_QEMU
258 "qemu",
259 #endif
260 #ifdef WITH_VBOX
261 "vbox",
262 #endif
263 };
264 ssize_t i;
265
266 for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) {
267 g_autofree char *userdir = virGetUserRuntimeDirectory();
268 g_autofree char *sockname =
269 g_strdup_printf("%s/virt%sd-%s",
270 userdir, drivers[i], readonly ? "sock-ro" : "sock");
271
272 if (virFileExists(sockname)) {
273 VIR_DEBUG("Probed driver '%s' via sock '%s'", drivers[i], sockname);
274 *driver = g_strdup(drivers[i]);
275 return 0;
276 }
277
278 VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]);
279 }
280
281 /* Even if we didn't probe any socket, we won't
282 * return error. Just let virConnectOpen's normal
283 * logic run which will likely return an error anyway
284 */
285 VIR_DEBUG("No more drivers to probe for");
286 return 0;
287 }
288
289 char *
remoteGetUNIXSocket(remoteDriverTransport transport,remoteDriverMode mode,const char * driver,unsigned int flags,char ** daemon_path)290 remoteGetUNIXSocket(remoteDriverTransport transport,
291 remoteDriverMode mode,
292 const char *driver,
293 unsigned int flags,
294 char **daemon_path)
295 {
296 char *sock_name = NULL;
297 g_autofree char *direct_daemon = NULL;
298 g_autofree char *legacy_daemon = NULL;
299 g_autofree char *daemon_name = NULL;
300 g_autofree char *direct_sock_name = NULL;
301 g_autofree char *legacy_sock_name = NULL;
302 #ifdef REMOTE_DRIVER_AUTOSTART_DIRECT
303 g_autofree char *guessdriver = NULL;
304 #endif
305 #ifndef WIN32
306 const char *env_name = remoteGetDaemonPathEnv();
307 #else
308 const char *env_name = NULL;
309 #endif
310
311 VIR_DEBUG("Choosing remote socket for transport=%s mode=%s driver=%s flags=0x%x",
312 remoteDriverTransportTypeToString(transport),
313 remoteDriverModeTypeToString(mode),
314 driver, flags);
315
316 #ifdef REMOTE_DRIVER_AUTOSTART_DIRECT
317 if (!driver && mode != REMOTE_DRIVER_MODE_LEGACY) {
318 VIR_DEBUG("Client side modular daemon probe");
319 /*
320 * If we don't have a driver (because URI is empty)
321 * in the direct case, we don't know which daemon
322 * to connect to. This logic attempts to be a rough
323 * equivalent of auto-probing from virConnectOpen
324 * in the libvirtd days.
325 */
326 if (geteuid() != 0) {
327 if (remoteProbeSessionDriverFromSocket(false, &guessdriver) < 0)
328 return NULL;
329
330 if (guessdriver == NULL &&
331 remoteProbeSessionDriverFromBinary(&guessdriver) < 0)
332 return NULL;
333 } else {
334 if (remoteProbeSystemDriverFromSocket(flags & REMOTE_DRIVER_OPEN_RO,
335 &guessdriver) < 0)
336 return NULL;
337 }
338 driver = guessdriver;
339 }
340 #endif
341
342 if (driver) {
343 direct_daemon = g_strdup_printf("virt%sd", driver);
344 direct_sock_name = remoteGetUNIXSocketHelper(transport, direct_daemon, flags);
345 }
346
347 legacy_daemon = g_strdup("libvirtd");
348 legacy_sock_name = remoteGetUNIXSocketHelper(transport, "libvirt", flags);
349
350 if (mode == REMOTE_DRIVER_MODE_AUTO) {
351 if (transport == REMOTE_DRIVER_TRANSPORT_UNIX) {
352 /*
353 * When locally accessing libvirtd, we pick legacy or
354 * modular daemons depending on which sockets we see
355 * existing.
356 */
357 if (direct_sock_name && virFileExists(direct_sock_name)) {
358 mode = REMOTE_DRIVER_MODE_DIRECT;
359 } else if (virFileExists(legacy_sock_name)) {
360 mode = REMOTE_DRIVER_MODE_LEGACY;
361 } else {
362 #ifdef REMOTE_DRIVER_AUTOSTART_DIRECT
363 mode = REMOTE_DRIVER_MODE_DIRECT;
364 #else
365 mode = REMOTE_DRIVER_MODE_LEGACY;
366 #endif
367 }
368 } else {
369 /*
370 * When remotely accessing libvirtd, we always default to a legacy socket
371 * path, as there's no way for us to probe what's configured. This does
372 * not matter, since 'virt-ssh-helper' will be used if it is available
373 * and thus probe from context of the remote host
374 */
375 mode = REMOTE_DRIVER_MODE_LEGACY;
376 }
377 }
378
379 switch ((remoteDriverMode)mode) {
380 case REMOTE_DRIVER_MODE_LEGACY:
381 sock_name = g_steal_pointer(&legacy_sock_name);
382 daemon_name = g_steal_pointer(&legacy_daemon);
383 break;
384
385 case REMOTE_DRIVER_MODE_DIRECT:
386 if (transport != REMOTE_DRIVER_TRANSPORT_UNIX) {
387 virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
388 _("Cannot use direct socket mode for %s transport"),
389 remoteDriverTransportTypeToString(transport));
390 return NULL;
391 }
392
393 if (!direct_sock_name) {
394 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
395 _("Cannot use direct socket mode if no URI is set"));
396 return NULL;
397 }
398
399 sock_name = g_steal_pointer(&direct_sock_name);
400 daemon_name = g_steal_pointer(&direct_daemon);
401 break;
402
403 case REMOTE_DRIVER_MODE_AUTO:
404 case REMOTE_DRIVER_MODE_LAST:
405 default:
406 virReportEnumRangeError(remoteDriverMode, mode);
407 return NULL;
408 }
409
410 if (flags & REMOTE_DRIVER_OPEN_AUTOSTART) {
411 if (!(*daemon_path = virFileFindResourceFull(daemon_name,
412 NULL, NULL,
413 abs_top_builddir "/src",
414 SBINDIR,
415 env_name)))
416 return NULL;
417 } else {
418 *daemon_path = NULL;
419 }
420
421 VIR_DEBUG("Chosen UNIX sockname=%s daemon_path=%s with mode=%s",
422 sock_name, NULLSTR(*daemon_path),
423 remoteDriverModeTypeToString(mode));
424 return sock_name;
425 }
426
427
428 void
remoteGetURIDaemonInfo(virURI * uri,remoteDriverTransport transport,unsigned int * flags)429 remoteGetURIDaemonInfo(virURI *uri,
430 remoteDriverTransport transport,
431 unsigned int *flags)
432 {
433 const char *autostart_str = getenv("LIBVIRT_AUTOSTART");
434
435 *flags = 0;
436
437 /*
438 * User session daemon is used for
439 *
440 * - Any URI with /session suffix
441 * - Test driver, if a protocol is given
442 *
443 * provided we are running non-root
444 */
445 if (uri &&
446 uri->path &&
447 uri->scheme &&
448 (STREQ(uri->path, "/session") ||
449 STRPREFIX(uri->scheme, "test+")) &&
450 geteuid() > 0) {
451 VIR_DEBUG("User session daemon required");
452 *flags |= REMOTE_DRIVER_OPEN_USER;
453
454 /*
455 * Furthermore if no servername is given,
456 * and the transport is unix,
457 * and uid is unprivileged then auto-spawn a daemon.
458 */
459 if (!uri->server &&
460 (transport == REMOTE_DRIVER_TRANSPORT_UNIX) &&
461 (!autostart_str ||
462 STRNEQ(autostart_str, "0"))) {
463 VIR_DEBUG("Try daemon autostart");
464 *flags |= REMOTE_DRIVER_OPEN_AUTOSTART;
465 }
466 }
467
468 /*
469 * If URI is NULL, then do a UNIX connection possibly auto-spawning
470 * unprivileged server and probe remote server for URI.
471 */
472 if (!uri) {
473 VIR_DEBUG("Auto-probe remote URI");
474 if (geteuid() > 0) {
475 VIR_DEBUG("Auto-spawn user daemon instance");
476 *flags |= REMOTE_DRIVER_OPEN_USER;
477 if (!autostart_str ||
478 STRNEQ(autostart_str, "0"))
479 *flags |= REMOTE_DRIVER_OPEN_AUTOSTART;
480 }
481 }
482 }
483