From nobody Sun Feb 8 19:59:39 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) client-ip=63.128.21.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 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=1605706497; cv=none; d=zohomail.com; s=zohoarc; b=VgdmqaaRv2448Fphjvoig5OhgysRiWkbLY1VcQg9eP96Q5KVxvAQl7HLvjrh/RB1JjbJwECWMJznY8rPIqsvMQ9S75q/8WKWm/yNRAbQMYx8hoCrxvdnBVD5ddU6/JVh+bPiwnlNgovIhW9epIhgleWNRRs4h57lsmFXgDrm5YQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1605706497; 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=Ogrnn5FKcrylzSanU54gEMikK6sABE1gPVkrYQW9nx4=; b=S0/2P2Hiy1DEpdYjHbRJbeBef6CazDsJnhFfqD6uYppWzvr8bpkzQMOR0Hj/+GtrSYjcF56AUcpCxUMyFaZVdG/i5dhlNQGxGQ0qzfHvZu9zhgwddhIapf/BPK52onAxAa6XOyFWXwUp8Xu0Jyfn5x9ZXPkmDjEt9L7mYz5gfLI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 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-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.zohomail.com with SMTPS id 16057064974151.8942209663050562; Wed, 18 Nov 2020 05:34:57 -0800 (PST) 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-392-cWbuARL8NlOSdFIWrE0kSg-1; Wed, 18 Nov 2020 08:34:50 -0500 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 82E788026A5; Wed, 18 Nov 2020 13:34:44 +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 60A6E60F96; Wed, 18 Nov 2020 13:34:44 +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 1FF078C7A1; Wed, 18 Nov 2020 13:34:44 +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 0AIDYaZw003924 for ; Wed, 18 Nov 2020 08:34:36 -0500 Received: by smtp.corp.redhat.com (Postfix) id 73C3D6EF58; Wed, 18 Nov 2020 13:34:36 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id E50336EF4F for ; Wed, 18 Nov 2020 13:34:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1605706495; 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=Ogrnn5FKcrylzSanU54gEMikK6sABE1gPVkrYQW9nx4=; b=SjEoTND+so2H/Q61sfZBgz+ZBY100ubL+ynprG/5KgbdRKhxH1YOHMOoa8hUaVijbUUHNr OYgL/kw/6rAkNk87dXfCC0TaOw6AfgDy+hkc+IhQTiVv6K1uyuG6NFBjg6b3+a923wBQvH 80PBshbKYXYilAq7RkAFvmcmKo5ve3E= X-MC-Unique: cWbuARL8NlOSdFIWrE0kSg-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 2/6] remote: Implement OpenSSH authorized key file mgmt APIs Date: Wed, 18 Nov 2020 14:34:20 +0100 Message-Id: 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.12 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com 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" Since both APIs accept/return an array of strings we can't have client/server dispatch code generated. But implementation is fairly trivial, although verbose. Signed-off-by: Michal Privoznik Reviewed-by: Peter Krempa --- src/remote/remote_daemon_dispatch.c | 82 +++++++++++++++++++++++++++ src/remote/remote_driver.c | 87 +++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 34 ++++++++++- src/remote_protocol-structs | 22 ++++++++ 4 files changed, 224 insertions(+), 1 deletion(-) diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon= _dispatch.c index eb5f6ebb0c..46683aa4a7 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -7381,3 +7381,85 @@ remoteDispatchDomainGetGuestInfo(virNetServerPtr ser= ver G_GNUC_UNUSED, =20 return rv; } + +static int +remoteDispatchDomainAuthorizedSshKeysGet(virNetServerPtr server G_GNUC_UNU= SED, + virNetServerClientPtr client, + virNetMessagePtr msg G_GNUC_UNUSE= D, + virNetMessageErrorPtr rerr, + remote_domain_authorized_ssh_keys= _get_args *args, + remote_domain_authorized_ssh_keys= _get_ret *ret) +{ + int rv =3D -1; + virConnectPtr conn =3D remoteGetHypervisorConn(client); + int nkeys =3D 0; + char **keys =3D NULL; + virDomainPtr dom =3D NULL; + + if (!conn) + goto cleanup; + + if (!(dom =3D get_nonnull_domain(conn, args->dom))) + goto cleanup; + + if ((nkeys =3D virDomainAuthorizedSSHKeysGet(dom, args->user, + &keys, args->flags)) < 0) + goto cleanup; + + if (nkeys > REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of keys %d, which exceeds max liit: %d"), + nkeys, REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX); + goto cleanup; + } + + ret->keys.keys_val =3D g_steal_pointer(&keys); + ret->keys.keys_len =3D nkeys; + + rv =3D nkeys; + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (nkeys > 0) + virStringListFreeCount(keys, nkeys); + virObjectUnref(dom); + + return rv; +} + +static int +remoteDispatchDomainAuthorizedSshKeysSet(virNetServerPtr server G_GNUC_UNU= SED, + virNetServerClientPtr client, + virNetMessagePtr msg G_GNUC_UNUSE= D, + virNetMessageErrorPtr rerr, + remote_domain_authorized_ssh_keys= _set_args *args) +{ + int rv =3D -1; + virConnectPtr conn =3D remoteGetHypervisorConn(client); + virDomainPtr dom =3D NULL; + + if (!conn) + goto cleanup; + + if (!(dom =3D get_nonnull_domain(conn, args->dom))) + goto cleanup; + + if (args->keys.keys_len > REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of keys %d, which exceeds max liit: %d"), + args->keys.keys_len, REMOTE_DOMAIN_AUTHORIZED_SSH_K= EYS_MAX); + goto cleanup; + } + + rv =3D virDomainAuthorizedSSHKeysSet(dom, args->user, + (const char **) args->keys.keys_val, + args->keys.keys_len, args->flags); + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virObjectUnref(dom); + + return rv; +} diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index dd5e8eeed2..6c0e7f7514 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8017,6 +8017,91 @@ remoteDomainGetGuestInfo(virDomainPtr dom, return rv; } =20 +static int +remoteDomainAuthorizedSSHKeysGet(virDomainPtr domain, + const char *user, + char ***keys, + unsigned int flags) +{ + int rv =3D -1; + size_t i; + struct private_data *priv =3D domain->conn->privateData; + remote_domain_authorized_ssh_keys_get_args args; + remote_domain_authorized_ssh_keys_get_ret ret; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.dom, domain); + args.user =3D (char *) user; + args.flags =3D flags; + memset(&ret, 0, sizeof(ret)); + + if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS= _GET, + (xdrproc_t) xdr_remote_domain_authorized_ssh_keys_get_args, (= char *)&args, + (xdrproc_t) xdr_remote_domain_authorized_ssh_keys_get_ret, (c= har *)&ret) =3D=3D -1) { + goto cleanup; + } + + if (ret.keys.keys_len > REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX) { + virReportError(VIR_ERR_RPC, "%s", + _("remoteDomainAuthorizedSSHKeysGet: " + "returned number of keys exceeds limit")); + goto cleanup; + } + + *keys =3D g_new0(char *, ret.keys.keys_len + 1); + for (i =3D 0; i < ret.keys.keys_len; i++) + (*keys)[i] =3D g_strdup(ret.keys.keys_val[i]); + + rv =3D ret.keys.keys_len; + + cleanup: + remoteDriverUnlock(priv); + xdr_free((xdrproc_t)xdr_remote_domain_authorized_ssh_keys_get_ret, + (char *) &ret); + return rv; +} + +static int +remoteDomainAuthorizedSSHKeysSet(virDomainPtr domain, + const char *user, + const char **keys, + int nkeys, + unsigned int flags) +{ + int rv =3D -1; + struct private_data *priv =3D domain->conn->privateData; + remote_domain_authorized_ssh_keys_set_args args; + + remoteDriverLock(priv); + + if (nkeys > REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX) { + virReportError(VIR_ERR_RPC, "%s", + _("remoteDomainAuthorizedSSHKeysSet: " + "returned number of keys exceeds limit")); + goto cleanup; + } + + make_nonnull_domain(&args.dom, domain); + args.user =3D (char *) user; + args.keys.keys_len =3D nkeys; + args.keys.keys_val =3D (char **) keys; + args.flags =3D flags; + + if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS= _SET, + (xdrproc_t) xdr_remote_domain_authorized_ssh_keys_set_args, (= char *)&args, + (xdrproc_t) xdr_void, (char *) NULL) =3D=3D -1) { + goto cleanup; + } + + rv =3D 0; + + cleanup: + remoteDriverUnlock(priv); + return rv; +} + + /* get_nonnull_domain and get_nonnull_network turn an on-wire * (name, uuid) pair into virDomainPtr or virNetworkPtr object. * These can return NULL if underlying memory allocations fail, @@ -8448,6 +8533,8 @@ static virHypervisorDriver hypervisor_driver =3D { .domainAgentSetResponseTimeout =3D remoteDomainAgentSetResponseTimeout= , /* 5.10.0 */ .domainBackupBegin =3D remoteDomainBackupBegin, /* 6.0.0 */ .domainBackupGetXMLDesc =3D remoteDomainBackupGetXMLDesc, /* 6.0.0 */ + .domainAuthorizedSSHKeysGet =3D remoteDomainAuthorizedSSHKeysGet, /* 6= .10.0 */ + .domainAuthorizedSSHKeysSet =3D remoteDomainAuthorizedSSHKeysSet, /* 6= .10.0 */ }; =20 static virNetworkDriver network_driver =3D { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 5e5e781e76..2df38cef77 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -280,6 +280,9 @@ const REMOTE_DOMAIN_GUEST_INFO_PARAMS_MAX =3D 2048; */ const REMOTE_NETWORK_PORT_PARAMETERS_MAX =3D 16; =20 +/* Upper limit on number of SSH keys */ +const REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX =3D 2048; + =20 /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -3779,6 +3782,23 @@ struct remote_domain_backup_get_xml_desc_ret { remote_nonnull_string xml; }; =20 +struct remote_domain_authorized_ssh_keys_get_args { + remote_nonnull_domain dom; + remote_nonnull_string user; + unsigned int flags; +}; + +struct remote_domain_authorized_ssh_keys_get_ret { + remote_nonnull_string keys; +}; + +struct remote_domain_authorized_ssh_keys_set_args { + remote_nonnull_domain dom; + remote_nonnull_string user; + remote_nonnull_string keys; + unsigned int flags; +}; + /*----- Protocol. -----*/ =20 /* Define the program number, protocol version and procedure numbers here.= */ @@ -6682,5 +6702,17 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE =3D 423 + REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE =3D 423, + + /** + * @generate: none + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_GET =3D 424, + + /** + * @generate: none + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET =3D 425 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index c2ae411885..9bcd14603d 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3142,6 +3142,26 @@ struct remote_domain_backup_get_xml_desc_args { struct remote_domain_backup_get_xml_desc_ret { remote_nonnull_string xml; }; +struct remote_domain_authorized_ssh_keys_get_args { + remote_nonnull_domain dom; + remote_nonnull_string user; + u_int flags; +}; +struct remote_domain_authorized_ssh_keys_get_ret { + struct { + u_int keys_len; + remote_nonnull_string * keys_val; + } keys; +}; +struct remote_domain_authorized_ssh_keys_set_args { + remote_nonnull_domain dom; + remote_nonnull_string user; + struct { + u_int keys_len; + remote_nonnull_string * keys_val; + } keys; + u_int flags; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN =3D 1, REMOTE_PROC_CONNECT_CLOSE =3D 2, @@ -3566,4 +3586,6 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_BACKUP_BEGIN =3D 421, REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC =3D 422, REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE =3D 423, + REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_GET =3D 424, + REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET =3D 425, }; --=20 2.26.2