<xi:include href="libsystemd-pkgconfig.xml" />
+ <refsect1>
+ <title>Directories</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>/usr/lib/systemd/varlink-bridges/</filename></term>
+ <listitem>
+ <para>When <function>sd_varlink_connect_url()</function> encounters a URL with a scheme that is not
+ natively supported, it looks for a bridge helper binary named after the URL scheme in this
+ directory. The binary is invoked the same way as <literal>exec:</literal> binaries but with the full
+ URL passed as the first command line argument.</para>
+
+ <para>For example, if
+ <command>varlinkctl introspect https://example.com/ws/sockets/io.systemd.Hostname</command>
+ is called, <command>varlinkctl</command> will look for an executable
+ <filename>/usr/lib/systemd/varlink-bridges/https</filename> and invoke it with
+ <literal>https://example.com/ws/sockets/io.systemd.Hostname</literal> as its only
+ argument.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
credstoredir = prefixdir / 'lib/credstore'
pcrlockdir = prefixdir / 'lib/pcrlock.d'
mimepackagesdir = prefixdir / 'share/mime/packages'
+varlinkbridgesdir = libexecdir / 'varlink-bridges'
configfiledir = get_option('configfiledir')
if configfiledir == ''
conf.set_quoted('USER_KEYRING_PATH', pkgsysconfdir / 'import-pubring.pgp')
conf.set_quoted('USER_KEYRING_PATH_LEGACY', pkgsysconfdir / 'import-pubring.gpg')
conf.set_quoted('USER_PRESET_DIR', userpresetdir)
+conf.set_quoted('VARLINK_BRIDGES_DIR', varlinkbridgesdir)
conf.set_quoted('VENDOR_KEYRING_PATH', libexecdir / 'import-pubring.pgp')
conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper())
return 0;
}
+/* Do basic validation of the URL scheme (loosely following RFC 1738) */
+static bool is_valid_url_scheme(const char *s) {
+ return !isempty(s) &&
+ strchr(LOWERCASE_LETTERS, s[0]) &&
+ in_charset(s, LOWERCASE_LETTERS DIGITS "+.-") &&
+ filename_is_valid(s);
+}
+
_public_ int sd_varlink_connect_url(sd_varlink **ret, const char *url) {
_cleanup_free_ char *c = NULL;
const char *p;
assert_return(ret, -EINVAL);
assert_return(url, -EINVAL);
- // FIXME: Maybe add support for vsock: and ssh-exec: URL schemes here.
+ // FIXME: Maybe add support for vsock: URL schemes here.
/* The Varlink URL scheme is a bit underdefined. We support only the spec-defined unix: transport for
* now, plus exec:, ssh: transports we made up ourselves. Strictly speaking this shouldn't even be
scheme = SCHEME_SSH_UNIX;
else if ((p = startswith(url, "ssh-exec:")))
scheme = SCHEME_SSH_EXEC;
- else
- return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "URL scheme not supported.");
+ else {
+ /* scheme is not built-in: check if we have a bridge helper binary */
+ const char *colon = strchr(url, ':');
+ if (!colon)
+ return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
+ "Invalid URL '%s': does not contain a ':'", url);
+
+ _cleanup_free_ char *scheme_name = strndup(url, colon - url);
+ if (!scheme_name)
+ return log_oom_debug();
+
+ if (!is_valid_url_scheme(scheme_name))
+ return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
+ "URL scheme not valid as bridge name: %s", scheme_name);
+
+ const char *bridges_dir = secure_getenv("SYSTEMD_VARLINK_BRIDGES_DIR") ?: VARLINK_BRIDGES_DIR;
+ _cleanup_free_ char *bridge = path_join(bridges_dir, scheme_name);
+ if (!bridge)
+ return log_oom_debug();
+
+ if (access(bridge, X_OK) < 0) {
+ if (errno == ENOENT)
+ return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "URL scheme '%s' not supported (and no auxiliary bridge binary is available).", scheme_name);
+
+ return log_debug_errno(errno, "Failed to look up varlink bridge binary '%s': %m", bridge);
+ }
+
+ return sd_varlink_connect_exec(ret, bridge, STRV_MAKE(bridge, url));
+ }
/* The varlink.org reference C library supports more than just file system paths. We might want to
- * support that one day too. For now simply refuse that. */
+ * support that one day too. For now simply refuse that for our built-in schemes. It is fine for
+ * external scheme handled via plugins (see above). */
if (p[strcspn(p, ";?#")] != '\0')
return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "URL parameterization with ';', '?', '#' not supported.");