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