From nobody Mon Feb 9 01:17:15 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) client-ip=205.139.110.120; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-1.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1583771107; cv=none; d=zohomail.com; s=zohoarc; b=ACfSdF0/6jS+68UalvM/v94mrB6gm3Q3PUG5wBLFmyYBqw0Gu4tpkIIexAWzGiwfhQ2d1PPIKIwFyO0+X/v8MOqWGDSO+ydE8GwaRXq2USCYY6rBEmBTt5bmVkdRo34hTqGbY0INtqy+HUnAfj+voFn2emrpfnUi9i1LDn9bof4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1583771107; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=d8KsGEJVo4q0hga81k2FNVhWSg4POdM36jACtUaB280=; b=gmLKgUQtobzNod11RI69sofFhwFaTzEwLNJ4iKYr1cf58LCfc3UOoL7DsQjbwbKgiEczWClu8n8orzPqsHCCJhEfsgyccAswBMt/U1cdrtLWzWcNSTPp9F1npU8F5NSbYbT3fXf3M0/76UFRumCbcHC4tbdjhc5bgJXkKGdhPXk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by mx.zohomail.com with SMTPS id 1583771107335119.94080435876856; Mon, 9 Mar 2020 09:25:07 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-378-dtnl3wYZPlesOogeTPOJFg-1; Mon, 09 Mar 2020 12:23:58 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9D7211088380; Mon, 9 Mar 2020 16:23:52 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6F6598F358; Mon, 9 Mar 2020 16:23:52 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 2524086A13; Mon, 9 Mar 2020 16:23:52 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 029GNQkK020802 for ; Mon, 9 Mar 2020 12:23:26 -0400 Received: by smtp.corp.redhat.com (Postfix) id 5FE9F909E9; Mon, 9 Mar 2020 16:23:26 +0000 (UTC) Received: from angien.redhat.com (unknown [10.43.2.48]) by smtp.corp.redhat.com (Postfix) with ESMTP id D9C6C9051C for ; Mon, 9 Mar 2020 16:23:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1583771106; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=d8KsGEJVo4q0hga81k2FNVhWSg4POdM36jACtUaB280=; b=FKdmRoxDtKmCeAmetGEwytDp2aUQosdisEW4vvhe7F6Mv8yDJVEI6feFYNAubrRCeJHX3T s8EURxHzAH5jrCoSS0EjUr8qGWQHwKzrUtw64Y1wBr5Txl7pgtUqPCFvTfzngAiBNT0/ST ALmE/fXel58xdZh/z6gZkmzphciZ+og= X-MC-Unique: dtnl3wYZPlesOogeTPOJFg-1 From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 14/30] conf: Add support for cookies for HTTP based disks Date: Mon, 9 Mar 2020 17:22:54 +0100 Message-Id: <9a0c534ed8385d4646e96f88db56c166be211858.1583770683.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" Add possibility to specify one or more cookies for http based disks. This patch adds the config parser, storage and validation of the cookies. Signed-off-by: Peter Krempa Reviewed-by: J=C3=A1n Tomko --- docs/formatdomain.html.in | 10 ++ docs/schemas/domaincommon.rng | 24 ++++ src/conf/domain_conf.c | 82 +++++++++++++ src/libvirt_private.syms | 1 + src/util/virstoragefile.c | 115 ++++++++++++++++++ src/util/virstoragefile.h | 15 +++ .../disk-network-http.xml | 8 ++ 7 files changed, 255 insertions(+) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 8f503f6967..dfea614907 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2849,6 +2849,9 @@ <driver name=3D'qemu' type=3D'raw'/> <source protocol=3D"http" name=3D"url_path"> <host name=3D"hostname" port=3D"80"/> + <cookies> + <cookie name=3D"test">somevalue</cookie> + </cookies> </source> <target dev=3D'hde' bus=3D'ide' tray=3D'open'/> <readonly/> @@ -3392,6 +3395,13 @@ certificate validation. Supported values are yes = and no. Since 6.1.0 +
cookies
+
+ For http and https accessed storage = it's + possible to pass one or more cookies. The cookie name and value + must conform to the HTTP specification. + Since 6.2.0 +

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d179a25ee6..85d6484dbd 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1817,6 +1817,24 @@ + + + + + + + [!#$%&'*+\-.0-9A-Z\^_`a-z|~]+ + + + + [!#$%&'()*+\-./0-9:>=3D<?@A-= Z\^_`\[\]a-z|~]+ + + + + + + + @@ -1833,6 +1851,9 @@ + + + @@ -1849,6 +1870,9 @@ + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index dd3a3a1439..dc7a47dd21 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9340,6 +9340,62 @@ virDomainDiskSourcePoolDefParse(xmlNodePtr node, } +static virStorageNetCookieDefPtr +virDomainStorageCookieParse(xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + g_autoptr(virStorageNetCookieDef) cookie =3D NULL; + + ctxt->node =3D node; + + cookie =3D g_new0(virStorageNetCookieDef, 1); + + if (!(cookie->name =3D virXPathString("string(./@name)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", _("missing cookie name")); + return NULL; + } + + if (!(cookie->value =3D virXPathString("string(.)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, _("missing value for cookie '%s'= "), + cookie->name); + return NULL; + } + + return g_steal_pointer(&cookie); +} + + +static int +virDomainStorageCookiesParse(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virStorageSourcePtr src) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + g_autofree xmlNodePtr *nodes =3D NULL; + ssize_t nnodes; + size_t i; + + ctxt->node =3D node; + + if ((nnodes =3D virXPathNodeSet("./cookie", ctxt, &nodes)) < 0) + return -1; + + src->cookies =3D g_new0(virStorageNetCookieDefPtr, nnodes); + src->ncookies =3D nnodes; + + for (i =3D 0; i < nnodes; i++) { + if (!(src->cookies[i] =3D virDomainStorageCookieParse(nodes[i], ct= xt))) + return -1; + } + + if (virStorageSourceNetCookiesValidate(src) < 0) + return -1; + + return 0; +} + + static int virDomainDiskSourceNetworkParse(xmlNodePtr node, xmlXPathContextPtr ctxt, @@ -9351,6 +9407,7 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node, g_autofree char *haveTLS =3D NULL; g_autofree char *tlsCfg =3D NULL; g_autofree char *sslverifystr =3D NULL; + xmlNodePtr tmpnode; if (!(protocol =3D virXMLPropString(node, "protocol"))) { virReportError(VIR_ERR_XML_ERROR, "%s", @@ -9436,6 +9493,13 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node, src->sslverify =3D verify; } + if ((src->protocol =3D=3D VIR_STORAGE_NET_PROTOCOL_HTTP || + src->protocol =3D=3D VIR_STORAGE_NET_PROTOCOL_HTTPS) && + (tmpnode =3D virXPathNode("./cookies", ctxt))) { + if (virDomainStorageCookiesParse(tmpnode, ctxt, src) < 0) + return -1; + } + return 0; } @@ -24500,6 +24564,22 @@ virDomainSourceDefFormatSeclabel(virBufferPtr buf, } +static void +virDomainDiskSourceFormatNetworkCookies(virBufferPtr buf, + virStorageSourcePtr src) +{ + g_auto(virBuffer) childBuf =3D VIR_BUFFER_INIT_CHILD(buf); + size_t i; + + for (i =3D 0; i < src->ncookies; i++) { + virBufferEscapeString(&childBuf, "", src->cook= ies[i]->name); + virBufferEscapeString(&childBuf, "%s\n", src->cookies[i]-= >value); + } + + virXMLFormatElement(buf, "cookies", NULL, &childBuf); +} + + static int virDomainDiskSourceFormatNetwork(virBufferPtr attrBuf, virBufferPtr childBuf, @@ -24549,6 +24629,8 @@ virDomainDiskSourceFormatNetwork(virBufferPtr attrB= uf, virBufferAsprintf(childBuf, "\n", virTristateBoolTypeToString(src->sslverify)); + virDomainDiskSourceFormatNetworkCookies(childBuf, src); + return 0; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 511fb88872..73db753652 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3143,6 +3143,7 @@ virStorageSourceIsEmpty; virStorageSourceIsLocalStorage; virStorageSourceIsRelative; virStorageSourceIsSameLocation; +virStorageSourceNetCookiesValidate; virStorageSourceNetworkAssignDefaultPorts; virStorageSourceNew; virStorageSourceNewFromBacking; diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index ca91fc65ba..fb5fff5c5f 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -2157,6 +2157,118 @@ virStorageSourceSeclabelsCopy(virStorageSourcePtr t= o, } +void +virStorageNetCookieDefFree(virStorageNetCookieDefPtr def) +{ + if (!def) + return; + + g_free(def->name); + g_free(def->value); + + g_free(def); +} + + +static void +virStorageSourceCookiesClear(virStorageSourcePtr src) +{ + size_t i; + + if (!src || !src->cookies) + return; + + for (i =3D 0; i < src->ncookies; i++) + virStorageNetCookieDefFree(src->cookies[i]); + + g_clear_pointer(&src->cookies, g_free); + src->ncookies =3D 0; +} + + +static void +virStorageSourceNetCookiesCopy(virStorageSourcePtr to, + const virStorageSource *from) +{ + size_t i; + + if (from->ncookies =3D=3D 0) + return; + + to->cookies =3D g_new0(virStorageNetCookieDefPtr, from->ncookies); + to->ncookies =3D from->ncookies; + + for (i =3D 0; i < from->ncookies; i++) { + to->cookies[i]->name =3D g_strdup(from->cookies[i]->name); + to->cookies[i]->value =3D g_strdup(from->cookies[i]->value); + } +} + + +/* see https://tools.ietf.org/html/rfc6265#section-4.1.1 */ +static const char virStorageSourceCookieValueInvalidChars[] =3D + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + " \",;\\"; + +/* in addition cookie name can't contain these */ +static const char virStorageSourceCookieNameInvalidChars[] =3D + "()<>@:/[]?=3D{}"; + +static int +virStorageSourceNetCookieValidate(virStorageNetCookieDefPtr def) +{ + /* name must have at least 1 character */ + if (*(def->name) =3D=3D '\0') { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("cookie name must not be empty")); + return -1; + } + + /* check invalid characters in name */ + if (virStringHasChars(def->name, virStorageSourceCookieValueInvalidCha= rs) || + virStringHasChars(def->name, virStorageSourceCookieNameInvalidChar= s)) { + virReportError(VIR_ERR_XML_ERROR, + _("cookie name '%s' contains invalid characters"), + def->name); + return -1; + } + + /* check invalid characters in value */ + if (virStringHasChars(def->value, virStorageSourceCookieValueInvalidCh= ars)) { + virReportError(VIR_ERR_XML_ERROR, + _("value of cookie '%s' contains invalid characters= "), + def->name); + return -1; + } + + return 0; +} + + +int +virStorageSourceNetCookiesValidate(virStorageSourcePtr src) +{ + size_t i; + size_t j; + + for (i =3D 0; i < src->ncookies; i++) { + if (virStorageSourceNetCookieValidate(src->cookies[i]) < 0) + return -1; + + for (j =3D i + 1; j < src->ncookies; j++) { + if (STREQ(src->cookies[i]->name, src->cookies[j]->name)) { + virReportError(VIR_ERR_XML_ERROR, _("duplicate cookie '%s'= "), + src->cookies[i]->name); + return -1; + } + } + } + + return 0; +} + + static virStorageTimestampsPtr virStorageTimestampsCopy(const virStorageTimestamps *src) { @@ -2299,6 +2411,8 @@ virStorageSourceCopy(const virStorageSource *src, def->nhosts =3D src->nhosts; } + virStorageSourceNetCookiesCopy(def, src); + if (src->srcpool && !(def->srcpool =3D virStorageSourcePoolDefCopy(src->srcpool))) return NULL; @@ -2560,6 +2674,7 @@ virStorageSourceClear(virStorageSourcePtr def) VIR_FREE(def->volume); VIR_FREE(def->snapshot); VIR_FREE(def->configFile); + virStorageSourceCookiesClear(def); virStorageSourcePoolDefFree(def->srcpool); virBitmapFree(def->features); VIR_FREE(def->compat); diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 49718b51d8..95d9501dd8 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -161,6 +161,17 @@ struct _virStorageNetHostDef { char *socket; /* path to unix socket */ }; +typedef struct _virStorageNetCookieDef virStorageNetCookieDef; +typedef virStorageNetCookieDef *virStorageNetCookieDefPtr; +struct _virStorageNetCookieDef { + char *name; + char *value; +}; + +void virStorageNetCookieDefFree(virStorageNetCookieDefPtr def); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageNetCookieDef, virStorageNetCookieD= efFree); + /* Information for a storage volume from a virStoragePool */ /* @@ -275,6 +286,8 @@ struct _virStorageSource { the source definition */ size_t nhosts; virStorageNetHostDefPtr hosts; + size_t ncookies; + virStorageNetCookieDefPtr *cookies; virStorageSourcePoolDefPtr srcpool; virStorageAuthDefPtr auth; bool authInherited; @@ -476,6 +489,8 @@ int virStorageSourceUpdateCapacity(virStorageSourcePtr = src, int virStorageSourceNewFromBacking(virStorageSourcePtr parent, virStorageSourcePtr *backing); +int virStorageSourceNetCookiesValidate(virStorageSourcePtr src); + virStorageSourcePtr virStorageSourceCopy(const virStorageSource *src, bool backingChain) ATTRIBUTE_NONNULL(1); diff --git a/tests/genericxml2xmlindata/disk-network-http.xml b/tests/gener= icxml2xmlindata/disk-network-http.xml index bdcc1977f2..bafb77c8ec 100644 --- a/tests/genericxml2xmlindata/disk-network-http.xml +++ b/tests/genericxml2xmlindata/disk-network-http.xml @@ -33,6 +33,10 @@ + + testcookievalue + blurb + @@ -41,6 +45,10 @@ + + testcookievalue + blurb + --=20 2.24.1