From nobody Fri Apr 19 22:28:26 2024 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=1605706486; cv=none; d=zohomail.com; s=zohoarc; b=SQ1g7tqTwPg9zCg4G8kX78A+EoNU9GYZVj9zK8aG6Zi0NKh9u6o3BEfDqAgVWvSY7dKfiCMXTKLSEeD1yRHJXpUfzHfhPCxwWl8GLyDBKjN3rR9nrzCRu2b1B0jxRQ7Dzypvk67v/24t4iQxgJWYRCw3fu7koTb7ecd/OYK1NjM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1605706486; 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=FczyXGd12r383qf1AYwftxwBbqz7DUhXrievpbxPb1E=; b=YqUOOC6VCN8Tokbqe8v7k4E9dNEiJutfOpxW3t0nBCZ4IhHs9q8w4K5ud6h441blt2Sq1YNfnGQ7RnXlV2ZNx3JX0CjufeqcTZvmsmZiSk8BBhXQZfVz3+PRORrH0PT0jpXGs4XT5N+vTj9LqrCtneH4HussFgaMhgfJnCbtIuU= 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 160570648678779.12328508498194; Wed, 18 Nov 2020 05:34:46 -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-356-NXQ6xcw7OGiyfXtrk-uciA-1; Wed, 18 Nov 2020 08:34:42 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 837BF1882FD0; Wed, 18 Nov 2020 13:34:37 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 46CF46EF5E; Wed, 18 Nov 2020 13:34:37 +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 863E7183D023; Wed, 18 Nov 2020 13:34:36 +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 0AIDYZMh003919 for ; Wed, 18 Nov 2020 08:34:35 -0500 Received: by smtp.corp.redhat.com (Postfix) id 922A56EF68; Wed, 18 Nov 2020 13:34:35 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id DF8716EF4F for ; Wed, 18 Nov 2020 13:34:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1605706485; 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=FczyXGd12r383qf1AYwftxwBbqz7DUhXrievpbxPb1E=; b=hzZKCiBW0gjhhh5tCQU9bAdKQ2gEWNwHW2yF59OjCKug6V8YwWmKZ5t1arc8cgzuCRMg1L emoswvW7636JGvU7TeU7ziw6UlnWEM9ofu6KjLi9XZRgM3Sa6tcTWVYi1Fgq8aqz8XHCaT 2JnO8+cjGzHkXHe9HqWKKOK+GIKi6QA= X-MC-Unique: NXQ6xcw7OGiyfXtrk-uciA-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 1/6] Introduce OpenSSH authorized key file mgmt APIs Date: Wed, 18 Nov 2020 14:34:19 +0100 Message-Id: <434863f8948c08341733a91317b22cf4a730d23e.1605706277.git.mprivozn@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.13 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" When setting up a new guest or when a management software wants to allow access to an existing guest the virDomainSetUserPassword() API can be used, but that might be not good enough if user want to ssh into the guest. Not only sshd has to be configured to accept password authentication (which is usually not the case for root), user have to type in their password. Using SSH keys is more convenient. Therefore, two new APIs are introduced: virDomainAuthorizedSSHKeysGet() which lists authorized keys for given user, and virDomainAuthorizedSSHKeysSet() which modifies the authorized keys file for given user (append, set or remove keys from the file). It's worth nothing that while authorized_keys file entries have some structure (as defined by sshd(8)), expressing that structure goes beyond libvirt's focus and thus "keys" are nothing but an opaque string to libvirt. Signed-off-by: Michal Privoznik Reviewed-by: Peter Krempa --- include/libvirt/libvirt-domain.h | 17 ++++ src/driver-hypervisor.h | 15 ++++ src/libvirt-domain.c | 133 +++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 ++ 4 files changed, 171 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-dom= ain.h index e1095a193d..d81157ccaf 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -5101,4 +5101,21 @@ int virDomainBackupBegin(virDomainPtr domain, char *virDomainBackupGetXMLDesc(virDomainPtr domain, unsigned int flags); =20 +int virDomainAuthorizedSSHKeysGet(virDomainPtr domain, + const char *user, + char ***keys, + unsigned int flags); + +typedef enum { + VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND =3D (1 << 0), /* don't trunc= ate file, just append */ + VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE =3D (1 << 1), /* remove keys= , instead of adding them */ + +} virDomainAuthorizedSSHKeysSetFlags; + +int virDomainAuthorizedSSHKeysSet(virDomainPtr domain, + const char *user, + const char **keys, + int nkeys, + unsigned int flags); + #endif /* LIBVIRT_DOMAIN_H */ diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index bce023017d..5a5ea95c51 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1387,6 +1387,19 @@ typedef char * (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain, unsigned int flags); =20 +typedef int +(*virDrvDomainAuthorizedSSHKeysGet)(virDomainPtr domain, + const char *user, + char ***keys, + unsigned int flags); + +typedef int +(*virDrvDomainAuthorizedSSHKeysSet)(virDomainPtr domain, + const char *user, + const char **keys, + int nkeys, + unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; =20 @@ -1650,4 +1663,6 @@ struct _virHypervisorDriver { virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout; virDrvDomainBackupBegin domainBackupBegin; virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc; + virDrvDomainAuthorizedSSHKeysGet domainAuthorizedSSHKeysGet; + virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 3c5f55176a..63d4954e68 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -12758,3 +12758,136 @@ virDomainBackupGetXMLDesc(virDomainPtr domain, virDispatchError(conn); return NULL; } + + +/** + * virDomainAuthorizedSSHKeysGet: + * @domain: a domain object + * @user: user to list keys for + * @keys: pointer to a variable to store authorized keys + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * For given @user in @domain fetch list of public SSH authorized + * keys and store them into @keys array which is allocated upon + * successful return and is NULL terminated. The caller is + * responsible for freeing @keys when no longer needed. + * + * Keys are in OpenSSH format (see sshd(8)) but from libvirt's + * point of view are opaque strings, i.e. not interpreted. + * + * Please note that some hypervisors may require guest agent to + * be configured and running in order to be able to run this API. + * + * Returns: number of keys stored in @keys, + * -1 otherwise. + */ +int +virDomainAuthorizedSSHKeysGet(virDomainPtr domain, + const char *user, + char ***keys, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "user=3D%s, keys=3D%p, flags=3D0x%x", + user, keys, flags); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn =3D domain->conn; + virCheckNonNullArgGoto(user, error); + virCheckNonNullArgGoto(keys, error); + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->driver->domainAuthorizedSSHKeysGet) { + int ret; + ret =3D conn->driver->domainAuthorizedSSHKeysGet(domain, user, + keys, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(conn); + return -1; +} + + +/** + * virDomainAuthorizedSSHKeysSet: + * @domain: a domain object + * @user: user to add keys for + * @keys: authorized keys to set + * @nkeys: number of keys in @keys array + * @flags: bitwise or of virDomainAuthorizedSSHKeysSetFlags + * + * For given @user in @domain set @keys in authorized keys file. + * Any previous content of the file is overwritten with new keys. + * That is, if this API is called with @nkeys =3D 0, @keys =3D NULL + * and @flags =3D 0 then the authorized keys file for @user is + * cleared out. + * + * Keys are in OpenSSH format (see sshd(8)) but from libvirt's + * point of view are opaque strings, i.e. not interpreted. + * + * If VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND flag is set + * then the file is not overwritten and new @keys are appended + * instead. + * + * If VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE flag is set then + * instead of adding any new keys, provided @keys are removed + * from the file. It's not considered error if the key doesn't + * exist. + * + * Please note that some hypervisors may require guest agent to + * be configured and running in order to be able to run this API. + * + * Returns: 0 on success, + * -1 otherwise. + */ +int +virDomainAuthorizedSSHKeysSet(virDomainPtr domain, + const char *user, + const char **keys, + int nkeys, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "user=3D%s, keys=3D%p, nkeys=3D%d, flags=3D0x= %x", + user, keys, nkeys, flags); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn =3D domain->conn; + virCheckNonNullArgGoto(user, error); + + if (flags & VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND || + flags & VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE) + virCheckNonNullArgGoto(keys, error); + + VIR_EXCLUSIVE_FLAGS_RET(VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND, + VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE, + -1); + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->driver->domainAuthorizedSSHKeysSet) { + int ret; + ret =3D conn->driver->domainAuthorizedSSHKeysSet(domain, user, + keys, nkeys, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 539d2e3943..cf31f937d5 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -873,4 +873,10 @@ LIBVIRT_6.0.0 { virDomainBackupGetXMLDesc; } LIBVIRT_5.10.0; =20 +LIBVIRT_6.10.0 { + global: + virDomainAuthorizedSSHKeysGet; + virDomainAuthorizedSSHKeysSet; +} LIBVIRT_6.0.0; + # .... define new API here using predicted next version number .... --=20 2.26.2 From nobody Fri Apr 19 22:28:26 2024 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 From nobody Fri Apr 19 22:28:26 2024 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=jDDNdcWs9EPJOMyyBmRlsOolc+kXdiggte2gfgkFTuewwRZ4Y7jYFldv6Z8bqWakSRlY/UFdJQ9P8V0WyNzTyEZpKb7iJGbyk9W18IAWOOkl5QfCd4Zp5DKB3UmczuZ7kxuHiqmwAcXEZvEcs7yW37Ou3xhK5xuvcPL0H4/y8oo= 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=NcxR1+B84Nl1wY3TeI6zVS7vlkrL4ofK9//EWzuywvE=; b=BAlDf8wJIyFEg+ML5oHeJDL9CLyDMJ/6+IK2UDeqUmagO99x1cVIm3Ti0qdNhDwmM+CObMvc4OWJMU2TQEjR8sx2EVvau/qwcoMfkld8kLOOd16aCl38Ddez3w56ZqVlijWWk7R73qS3mvTYuqkl7nBgNPRPhR4QHqbDRlE6CHA= 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 1605706497341824.6551771836199; 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-476-khBae3v3PSCvnxRjA0vuFQ-1; Wed, 18 Nov 2020 08:34:53 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 786811028D53; Wed, 18 Nov 2020 13:34:47 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 539756EF4F; Wed, 18 Nov 2020 13:34:47 +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 178AD183D025; Wed, 18 Nov 2020 13:34:47 +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 0AIDYbZg003930 for ; Wed, 18 Nov 2020 08:34:37 -0500 Received: by smtp.corp.redhat.com (Postfix) id 5ABB96EF4F; Wed, 18 Nov 2020 13:34:37 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id C678673667 for ; Wed, 18 Nov 2020 13:34:36 +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=NcxR1+B84Nl1wY3TeI6zVS7vlkrL4ofK9//EWzuywvE=; b=VVOt4xFvXio/o6FnnrnjPonDu1JLp+Hh5afnojW8Ci91J0LIk7UwezbS8AG4Ue21sz6EtH Te7wQwBWf+8PB75pq7isuDj196zqdAR0VFMDiiqtxJnPA1mwUAqrRx5nrUP41UTUwrNeK+ uzk88npDDhHAMlFhEn9CydgxZWGygME= X-MC-Unique: khBae3v3PSCvnxRjA0vuFQ-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 3/6] virsh: Expose OpenSSH authorized key file mgmt APIs Date: Wed, 18 Nov 2020 14:34:21 +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.13 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" The new virsh commands are: get-user-sshkeys set-user-sshkeys Signed-off-by: Michal Privoznik Reviewed-by: Peter Krempa --- docs/manpages/virsh.rst | 38 ++++++++++ tools/virsh-domain.c | 164 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index bfd26e3120..543f62d429 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -2636,6 +2636,21 @@ When *--timestamp* is used, a human-readable timesta= mp will be printed before the event. =20 =20 +get-user-sshkeys +---------------- + +**Syntax:** + +:: + + get-user-sshkeys domain user + +Print SSH authorized keys for given *user* in the guest *domain*. Please n= ote, +that an entry in the file has internal structure as defined by *sshd(8)* a= nd +virsh/libvirt does handle keys as opaque strings, i.e. does not interpret +them. + + guest-agent-timeout ------------------- =20 @@ -4004,6 +4019,29 @@ For QEMU/KVM, this requires the guest agent to be co= nfigured and running. =20 =20 +set-user-sshkeys +---------------- + +**Syntax:** + +:: + + set-user-sshkeys domain user [--file FILE] [{--reset | --remove}] + +Append keys read from *FILE* into *user*'sSSH authorized keys file in the = guest +*domain*. In the *FILE* keys must be on separate lines and each line must +follow authorized keys format as defined by *sshd(8)*. + +If *--reset* is specified, then the guest authorized keys file content is +removed before appending new keys. As a special case, if *--reset* is prov= ided +and no *FILE* was provided then no new keys are added and the authorized k= eys +file is cleared out. + +If *--remove* is specified, then instead of adding any new keys then keys = read +from *FILE* are removed from the authorized keys file. It is not considere= d an +error if the key does not exist in the file. + + setmaxmem --------- =20 diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 12b35c037d..c999458d72 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -14263,6 +14263,158 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd) return ret; } =20 +/* + * "get-user-sshkeys" command + */ +static const vshCmdInfo info_get_user_sshkeys[] =3D { + {.name =3D "help", + .data =3D N_("list authorized SSH keys for given user (via agent)") + }, + {.name =3D "desc", + .data =3D N_("Use the guest agent to query authorized SSH keys for gi= ven " + "user") + }, + {.name =3D NULL} +}; + +static const vshCmdOptDef opts_get_user_sshkeys[] =3D { + VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), + {.name =3D "user", + .type =3D VSH_OT_DATA, + .flags =3D VSH_OFLAG_REQ, + .help =3D N_("user to list authorized keys for"), + }, + {.name =3D NULL} +}; + +static bool +cmdGetUserSSHKeys(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom =3D NULL; + const char *user; + VIR_AUTOSTRINGLIST keys =3D NULL; + int nkeys =3D 0; + size_t i; + const unsigned int flags =3D 0; + bool ret =3D false; + + if (!(dom =3D virshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0) + goto cleanup; + + nkeys =3D virDomainAuthorizedSSHKeysGet(dom, user, &keys, flags); + if (nkeys < 0) + goto cleanup; + + for (i =3D 0; i < nkeys; i++) { + vshPrint(ctl, "%s", keys[i]); + } + + ret =3D true; + cleanup: + virshDomainFree(dom); + return ret; +} + + +/* + * "set-user-sshkeys" command + */ +static const vshCmdInfo info_set_user_sshkeys[] =3D { + {.name =3D "help", + .data =3D N_("manipulate authorized SSH keys file for given user (via= agent)") + }, + {.name =3D "desc", + .data =3D N_("Append, reset or remove specified key from the authoriz= ed " + "keys file for given user") + }, + {.name =3D NULL} +}; + +static const vshCmdOptDef opts_set_user_sshkeys[] =3D { + VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), + {.name =3D "user", + .type =3D VSH_OT_DATA, + .flags =3D VSH_OFLAG_REQ, + .help =3D N_("user to set authorized keys for"), + }, + {.name =3D "file", + .type =3D VSH_OT_STRING, + .help =3D N_("optional file to read keys from"), + }, + {.name =3D "reset", + .type =3D VSH_OT_BOOL, + .help =3D N_("clear out authorized keys file before adding new keys"), + }, + {.name =3D "remove", + .type =3D VSH_OT_BOOL, + .help =3D N_("remove keys from the authorized keys file"), + }, + {.name =3D NULL} +}; + +static bool +cmdSetUserSSHKeys(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom =3D NULL; + const char *user; + const char *from; + g_autofree char *buffer =3D NULL; + VIR_AUTOSTRINGLIST keys =3D NULL; + int nkeys =3D 0; + unsigned int flags =3D 0; + bool ret =3D false; + + VSH_REQUIRE_OPTION("remove", "file"); + VSH_EXCLUSIVE_OPTIONS("reset", "remove"); + + if (!(dom =3D virshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0) + goto cleanup; + + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) + goto cleanup; + + if (!vshCommandOptBool(cmd, "reset")) { + flags |=3D VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND; + + if (!from) { + vshError(ctl, _("Option --file is required")); + goto cleanup; + } + } + + if (vshCommandOptBool(cmd, "remove")) + flags |=3D VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE; + + if (from) { + if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) { + vshSaveLibvirtError(); + goto cleanup; + } + + if (!(keys =3D virStringSplit(buffer, "\n", -1))) + goto cleanup; + + nkeys =3D virStringListLength((const char **) keys); + } + + if (virDomainAuthorizedSSHKeysSet(dom, user, + (const char **) keys, nkeys, flags) = < 0) { + goto cleanup; + } + + ret =3D true; + cleanup: + virshDomainFree(dom); + return ret; +} + + const vshCmdDef domManagementCmds[] =3D { {.name =3D "attach-device", .handler =3D cmdAttachDevice, @@ -14530,6 +14682,12 @@ const vshCmdDef domManagementCmds[] =3D { .info =3D info_event, .flags =3D 0 }, + {.name =3D "get-user-sshkeys", + .handler =3D cmdGetUserSSHKeys, + .opts =3D opts_get_user_sshkeys, + .info =3D info_get_user_sshkeys, + .flags =3D 0 + }, {.name =3D "inject-nmi", .handler =3D cmdInjectNMI, .opts =3D opts_inject_nmi, @@ -14776,6 +14934,12 @@ const vshCmdDef domManagementCmds[] =3D { .info =3D info_setLifecycleAction, .flags =3D 0 }, + {.name =3D "set-user-sshkeys", + .handler =3D cmdSetUserSSHKeys, + .opts =3D opts_set_user_sshkeys, + .info =3D info_set_user_sshkeys, + .flags =3D 0 + }, {.name =3D "set-user-password", .handler =3D cmdSetUserPassword, .opts =3D opts_set_user_password, --=20 2.26.2 From nobody Fri Apr 19 22:28:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.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 216.205.24.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=1605706572; cv=none; d=zohomail.com; s=zohoarc; b=h9FlYKR7fkek9WSqbJn3l7VpCMYCUky274cRv2dKsv9YFXzYDosCRrqY7nzG7n2mvsaBIXjvz1pBXvE+//hVOf4tXp58R0jDQdTUCh96hlx3vyQkPXoG8M47M/B/BDfM1L/NwGgYaftSpScMcBRJdkfmWPj8sBmVwK92q1rkC5U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1605706572; 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=NpvaK4o6/TliXjuH3FdUTUiBdnvQSMEj9pHvKSz757U=; b=Wowhvszy2vw0Tzgp+uYQgIzwe/6v9dlxbRYs1oOOG3tqZhD0UgEjA3+pz2+au7klUE02DD1fukWYHznU/1jEK5QHO6tvZKUncbPvKo7+ounSJONTvp0UtYCvIL8/ERgbKKHdra+eDx5zBHpxhuwltRkl+UCogTTs/OVX6UqnwTY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.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 [216.205.24.124]) by mx.zohomail.com with SMTPS id 1605706572637161.23423350735004; Wed, 18 Nov 2020 05:36:12 -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-478-PkvamzdsPD2UzXbvRk1QsA-1; Wed, 18 Nov 2020 08:34:53 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id AE876802691; Wed, 18 Nov 2020 13:34:47 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8B4815C1A3; Wed, 18 Nov 2020 13:34:47 +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 4CCB7183D026; Wed, 18 Nov 2020 13:34:47 +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 0AIDYclM003936 for ; Wed, 18 Nov 2020 08:34:38 -0500 Received: by smtp.corp.redhat.com (Postfix) id 2ED8F6EF4F; Wed, 18 Nov 2020 13:34:38 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id A2CDE6EF69 for ; Wed, 18 Nov 2020 13:34:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1605706571; 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=NpvaK4o6/TliXjuH3FdUTUiBdnvQSMEj9pHvKSz757U=; b=KcXwc1shubXk9XlXJLuefzgHAJNUq/unSeRO21MmpFPMpV69845Hv1KSmJh3/nNFLD6RPo 1Qb0hL4M1JAsfI5RTtEsdXC3cjdlMBPvuWmcfMdlcYJop1lhG1plc6idEyq0JBDNLb/0b5 lQuHkyXR4H06YRqjkKnj2BhyKopxVbk= X-MC-Unique: PkvamzdsPD2UzXbvRk1QsA-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 4/6] qemu_agent: add qemuAgentSSH{Add, Remove, Get}AuthorizedKeys Date: Wed, 18 Nov 2020 14:34:22 +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.16 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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) From: Marc-Andr=C3=A9 Lureau In QEMU 5.2, the guest agent learned to manipulate a user ~/.ssh/authorized_keys. Bind the JSON API to libvirt. https://wiki.qemu.org/ChangeLog/5.2#Guest_agent Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Michal Privoznik Reviewed-by: Peter Krempa --- src/qemu/qemu_agent.c | 141 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_agent.h | 15 +++++ tests/qemuagenttest.c | 79 +++++++++++++++++++++++ 3 files changed, 235 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 7fbb4a9431..230253d404 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -2496,3 +2496,144 @@ qemuAgentSetResponseTimeout(qemuAgentPtr agent, { agent->timeout =3D timeout; } + +/** + * qemuAgentSSHGetAuthorizedKeys: + * @agent: agent object + * @user: user to get authorized keys for + * @keys: Array of authorized keys + * + * Fetch the public keys from @user's $HOME/.ssh/authorized_keys. + * + * Returns: number of keys returned on success, + * -1 otherwise (error is reported) + */ +int +qemuAgentSSHGetAuthorizedKeys(qemuAgentPtr agent, + const char *user, + char ***keys) +{ + g_autoptr(virJSONValue) cmd =3D NULL; + g_autoptr(virJSONValue) reply =3D NULL; + virJSONValuePtr data =3D NULL; + size_t ndata; + size_t i; + char **keys_ret =3D NULL; + + if (!(cmd =3D qemuAgentMakeCommand("guest-ssh-get-authorized-keys", + "s:username", user, + NULL))) + return -1; + + if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0) + return -1; + + if (!(data =3D virJSONValueObjectGetObject(reply, "return")) || + !(data =3D virJSONValueObjectGetArray(data, "keys"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qemu agent didn't return an array of keys")); + return -1; + } + + ndata =3D virJSONValueArraySize(data); + + keys_ret =3D g_new0(char *, ndata + 1); + + for (i =3D 0; i < ndata; i++) { + virJSONValuePtr entry =3D virJSONValueArrayGet(data, i); + + if (!entry) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("array element missing in guest-ssh-get-autho= rized-keys return value")); + goto error; + } + + keys_ret[i] =3D g_strdup(virJSONValueGetString(entry)); + } + + *keys =3D g_steal_pointer(&keys_ret); + return ndata; + + error: + virStringListFreeCount(keys_ret, ndata); + return -1; +} + + +/** + * qemuAgentSSHAddAuthorizedKeys: + * @agent: agent object + * @user: user to add authorized keys for + * @keys: Array of authorized keys + * @nkeys: number of items in @keys array + * @reset: whether to truncate authorized keys file before writing + * + * Append SSH @keys into the @user's authorized keys file. If + * @reset is true then the file is truncated before write and + * thus contains only newly added @keys. + * + * Returns: 0 on success, + * -1 otherwise (error is reported) + */ +int +qemuAgentSSHAddAuthorizedKeys(qemuAgentPtr agent, + const char *user, + const char **keys, + size_t nkeys, + bool reset) +{ + g_autoptr(virJSONValue) cmd =3D NULL; + g_autoptr(virJSONValue) reply =3D NULL; + g_autoptr(virJSONValue) jkeys =3D NULL; + + jkeys =3D qemuAgentMakeStringsArray(keys, nkeys); + if (jkeys =3D=3D NULL) + return -1; + + if (!(cmd =3D qemuAgentMakeCommand("guest-ssh-add-authorized-keys", + "s:username", user, + "a:keys", &jkeys, + "b:reset", reset, + NULL))) + return -1; + + return qemuAgentCommand(agent, cmd, &reply, agent->timeout); +} + + +/** + * qemuAgentSSHRemoveAuthorizedKeys: + * @agent: agent object + * @user: user to remove authorized keys for + * @keys: Array of authorized keys + * @nkeys: number of items in @keys array + * + * Remove SSH @keys from the @user's authorized keys file. It's + * not considered an error when trying to remove a non-existent + * key. + * + * Returns: 0 on success, + * -1 otherwise (error is reported) + */ +int +qemuAgentSSHRemoveAuthorizedKeys(qemuAgentPtr agent, + const char *user, + const char **keys, + size_t nkeys) +{ + g_autoptr(virJSONValue) cmd =3D NULL; + g_autoptr(virJSONValue) reply =3D NULL; + g_autoptr(virJSONValue) jkeys =3D NULL; + + jkeys =3D qemuAgentMakeStringsArray(keys, nkeys); + if (jkeys =3D=3D NULL) + return -1; + + if (!(cmd =3D qemuAgentMakeCommand("guest-ssh-remove-authorized-keys", + "s:username", user, + "a:keys", &jkeys, + NULL))) + return -1; + + return qemuAgentCommand(agent, cmd, &reply, agent->timeout); +} diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 2eeb376a68..7cbab489ec 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -170,3 +170,18 @@ int qemuAgentGetTimezone(qemuAgentPtr mon, =20 void qemuAgentSetResponseTimeout(qemuAgentPtr mon, int timeout); + +int qemuAgentSSHGetAuthorizedKeys(qemuAgentPtr agent, + const char *user, + char ***keys); + +int qemuAgentSSHAddAuthorizedKeys(qemuAgentPtr agent, + const char *user, + const char **keys, + size_t nkeys, + bool reset); + +int qemuAgentSSHRemoveAuthorizedKeys(qemuAgentPtr agent, + const char *user, + const char **keys, + size_t nkeys); diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 607bd97b5c..47ff92733a 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -35,6 +35,84 @@ virQEMUDriver driver; =20 =20 +static int +testQemuAgentSSHKeys(const void *data) +{ + virDomainXMLOptionPtr xmlopt =3D (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test =3D qemuMonitorTestNewAgent(xmlopt); + char **keys =3D NULL; + int nkeys =3D 0; + int ret =3D -1; + + if (!test) + return -1; + + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) + goto cleanup; + + if (qemuMonitorTestAddItem(test, "guest-ssh-get-authorized-keys", + "{\"return\": {" + " \"keys\": [" + " \"algo1 key1 comments1\"," + " \"algo2 key2 comments2\"" + " ]" + "}}") < 0) + goto cleanup; + + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) + goto cleanup; + + if (qemuMonitorTestAddItem(test, "guest-ssh-add-authorized-keys", + "{ \"return\" : {} }") < 0) + goto cleanup; + + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) + goto cleanup; + + if (qemuMonitorTestAddItem(test, "guest-ssh-remove-authorized-keys", + "{ \"return\" : {} }") < 0) + goto cleanup; + + if ((nkeys =3D qemuAgentSSHGetAuthorizedKeys(qemuMonitorTestGetAgent(t= est), + "user", + &keys)) < 0) + goto cleanup; + + if (nkeys !=3D 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "expected 2 keys, got %d", nkeys); + ret =3D -1; + goto cleanup; + } + + if (STRNEQ(keys[1], "algo2 key2 comments2")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "Unexpected key returned: %= s", keys[1]); + ret =3D -1; + goto cleanup; + } + + if ((ret =3D qemuAgentSSHAddAuthorizedKeys(qemuMonitorTestGetAgent(tes= t), + "user", + (const char **) keys, + nkeys, + true)) < 0) + goto cleanup; + + if ((ret =3D qemuAgentSSHRemoveAuthorizedKeys(qemuMonitorTestGetAgent(= test), + "user", + (const char **) keys, + nkeys)) < 0) + goto cleanup; + + ret =3D 0; + + cleanup: + virStringListFreeCount(keys, nkeys); + qemuMonitorTestFree(test); + return ret; +} + + static int testQemuAgentFSFreeze(const void *data) { @@ -1315,6 +1393,7 @@ mymain(void) DO_TEST(Users); DO_TEST(OSInfo); DO_TEST(Timezone); + DO_TEST(SSHKeys); =20 DO_TEST(Timeout); /* Timeout should always be called last */ =20 --=20 2.26.2 From nobody Fri Apr 19 22:28:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.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 216.205.24.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=1605706500; cv=none; d=zohomail.com; s=zohoarc; b=Fn2eAn69DT8jZEddZzMUyeCbp/fVijvfmynxRC0/lKmqi+VdRpf9Nfl/mzTHqnRk6kIGJACRl/xf8xn1PXCEJWXE+tKGZsEMaYFPMGOLZ+JGpnOmIWg52HOzK1KxVOiiJW1d8yQFluC9TywZ2dULDl6yLsb1O6UjdBFPpQmQCxA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1605706500; 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=nhdGJD+SRs1Dgl4TjAlorndYrWd1eQwA9RnouORA0sc=; b=HtbDIiRH9UCqlTov/8uUaItsLMfkIE9yq5DkBnbyZSz3/suwXUL8S4C2DnbwcwWX3tThOr1H/XgBhNqZ3wv6rIys+y4Bh5UfMPEtANSpHx1KjLg7XSzgUxtEKD4W8DgX3I4S2M97LfpQFNMNR/wilA5zzmhiTsCOY+8eY5QLjzc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.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 [216.205.24.124]) by mx.zohomail.com with SMTPS id 1605706500250856.412849233669; Wed, 18 Nov 2020 05:35:00 -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-317-PbZ4azByMWCIaof3hzcV4A-1; Wed, 18 Nov 2020 08:34:57 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id DF9B9188C12F; Wed, 18 Nov 2020 13:34:50 +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 B9F225D9CD; Wed, 18 Nov 2020 13:34:50 +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 7C8678C7A4; Wed, 18 Nov 2020 13:34:50 +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 0AIDYdMG003941 for ; Wed, 18 Nov 2020 08:34:39 -0500 Received: by smtp.corp.redhat.com (Postfix) id 0AFE66EF5C; Wed, 18 Nov 2020 13:34:39 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id 804416EF4F for ; Wed, 18 Nov 2020 13:34:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1605706499; 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=nhdGJD+SRs1Dgl4TjAlorndYrWd1eQwA9RnouORA0sc=; b=KPJ6JC2yDDZEFbuF5+IpkQFlPzkc2dI9mx/CcuAOXKGtwOTCOsC0vgGbY4p1rGNaHH/KTn LSqm4W7UQYRmTBgJOiK7R4skJzsTKTj7liN9zAN1RYVN4gOYJHhp0D/863fZdJPLV9SIHo Z1QypR+mkG5dplK9zX0EtVCgmPdB+Gk= X-MC-Unique: PbZ4azByMWCIaof3hzcV4A-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 5/6] qemu: Implement OpenSSH authorized key file mgmt APIs Date: Wed, 18 Nov 2020 14:34:23 +0100 Message-Id: <8af104d7259011ff6b3ec43d35494f8552f8518c.1605706277.git.mprivozn@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.14 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" Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=3D1888537 Signed-off-by: Michal Privoznik Reviewed-by: Peter Krempa --- src/qemu/qemu_driver.c | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ac38edf009..b69be1bedc 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20094,6 +20094,85 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom, } =20 =20 +static int +qemuDomainAuthorizedSSHKeysGet(virDomainPtr dom, + const char *user, + char ***keys, + unsigned int flags) +{ + virQEMUDriverPtr driver =3D dom->conn->privateData; + virDomainObjPtr vm =3D NULL; + qemuAgentPtr agent; + int rv =3D -1; + + virCheckFlags(0, -1); + + if (!(vm =3D qemuDomainObjFromDomain(dom))) + return -1; + + if (virDomainAuthorizedSshKeysGetEnsureACL(dom->conn, vm->def) < 0) + return -1; + + if (qemuDomainObjBeginAgentJob(driver, vm, QEMU_AGENT_JOB_QUERY) < 0) + return -1; + + if (!qemuDomainAgentAvailable(vm, true)) + goto endagentjob; + + agent =3D qemuDomainObjEnterAgent(vm); + rv =3D qemuAgentSSHGetAuthorizedKeys(agent, user, keys); + qemuDomainObjExitAgent(vm, agent); + + endagentjob: + qemuDomainObjEndAgentJob(vm); + virDomainObjEndAPI(&vm); + return rv; +} + + +static int +qemuDomainAuthorizedSSHKeysSet(virDomainPtr dom, + const char *user, + const char **keys, + int nkeys, + unsigned int flags) +{ + virQEMUDriverPtr driver =3D dom->conn->privateData; + g_autoptr(virDomainObj) vm =3D NULL; + qemuAgentPtr agent; + const bool append =3D flags & VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEN= D; + const bool remove =3D flags & VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOV= E; + int rv =3D -1; + + virCheckFlags(VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND | + VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE, -1); + + if (!(vm =3D qemuDomainObjFromDomain(dom))) + return -1; + + if (virDomainAuthorizedSshKeysSetEnsureACL(dom->conn, vm->def) < 0) + return -1; + + if (qemuDomainObjBeginAgentJob(driver, vm, QEMU_AGENT_JOB_QUERY) < 0) + return -1; + + if (!qemuDomainAgentAvailable(vm, true)) + goto endagentjob; + + agent =3D qemuDomainObjEnterAgent(vm); + if (remove) + rv =3D qemuAgentSSHRemoveAuthorizedKeys(agent, user, keys, nkeys); + else + rv =3D qemuAgentSSHAddAuthorizedKeys(agent, user, keys, nkeys, !ap= pend); + qemuDomainObjExitAgent(vm, agent); + + endagentjob: + qemuDomainObjEndAgentJob(vm); + virDomainObjEndAPI(&vm); + return rv; +} + + static virHypervisorDriver qemuHypervisorDriver =3D { .name =3D QEMU_DRIVER_NAME, .connectURIProbe =3D qemuConnectURIProbe, @@ -20333,6 +20412,8 @@ static virHypervisorDriver qemuHypervisorDriver =3D= { .domainAgentSetResponseTimeout =3D qemuDomainAgentSetResponseTimeout, = /* 5.10.0 */ .domainBackupBegin =3D qemuDomainBackupBegin, /* 6.0.0 */ .domainBackupGetXMLDesc =3D qemuDomainBackupGetXMLDesc, /* 6.0.0 */ + .domainAuthorizedSSHKeysGet =3D qemuDomainAuthorizedSSHKeysGet, /* 6.1= 0.0 */ + .domainAuthorizedSSHKeysSet =3D qemuDomainAuthorizedSSHKeysSet, /* 6.1= 0.0 */ }; =20 =20 --=20 2.26.2 From nobody Fri Apr 19 22:28:26 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.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 216.205.24.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=1605706504; cv=none; d=zohomail.com; s=zohoarc; b=ZqY8AXL8+J9wZojqJ6mqtXoh86QAcu9XaCtYxLJR9qdBZiytT+j0vplvKXv74F7EIhALBEauJUb5o+25r3FqodXNeHs23oDofwFirXldMLJ7qF7yQ7Nb2SNyMXS0pPM8TN+yofDVI3o4M5Wwo5lNxUp8/rJ7o/oWmlLCoAnWxwc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1605706504; 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=hj8YbBuQhGiBttzrDNQZg9DFWh4tTahYol0GytWc1gM=; b=NgyaDgLODPmGQm02sJUNsuWfYq98EwKxKJL4us7bd+gP/qumAnTTVJkLe/MvzkQJV2eRSYZcYgKrWDbgLLCwIj1V+APpvZpJDI5LwjnFYVNVoDtBY77qoJotGQXL0frkiiLWBQBDaJ/x/2nRGhuvw4a7XP9Ennido5fUSbJWNEQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.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 [216.205.24.124]) by mx.zohomail.com with SMTPS id 1605706504262166.61977894781364; Wed, 18 Nov 2020 05:35:04 -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-561-dishLateNRWtIcKFEfXMiA-1; Wed, 18 Nov 2020 08:35:00 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1BCA8809CC7; Wed, 18 Nov 2020 13:34:54 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E129D5C1D7; Wed, 18 Nov 2020 13:34:53 +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 A656F183D02B; Wed, 18 Nov 2020 13:34:53 +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 0AIDYdNG003946 for ; Wed, 18 Nov 2020 08:34:39 -0500 Received: by smtp.corp.redhat.com (Postfix) id DC1736EF5C; Wed, 18 Nov 2020 13:34:39 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5CC176EF4F for ; Wed, 18 Nov 2020 13:34:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1605706503; 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=hj8YbBuQhGiBttzrDNQZg9DFWh4tTahYol0GytWc1gM=; b=PXfjE+vojIZkHIRQTED13K4TvRLkMrJODHPRaN6sEMijERznnGN0PLTU3nat6SPO5AdkYY lCQ2s1k73SqWunVLzcGXWzWf46Ss7sL5Pi10aAosxzw4JIV5ulblh13JsY/DjVaejHKA4k GVfkEP6+lFqdRofpMDXHhYsw+HW46Pg= X-MC-Unique: dishLateNRWtIcKFEfXMiA-1 From: Michal Privoznik To: libvir-list@redhat.com Subject: [PATCH v3 6/6] news: Document recent OpenSSH authorized key file mgmt APIs Date: Wed, 18 Nov 2020 14:34:24 +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.16 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" Signed-off-by: Michal Privoznik Reviewed-by: Peter Krempa --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 16e75c5c3f..8cccc07f52 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -24,6 +24,13 @@ v6.10.0 (unreleased) =20 * **New features** =20 + * qemu: Implement OpenSSH authorized key file management APIs + + New APIs (``virDomainAuthorizedSSHKeysGet()`` and + ``virDomainAuthorizedSSHKeysSet()``) and virsh commands + (``get-user-sshkeys`` and ``set-user-sshkeys``) are added to manage + authorized_keys SSH file for user. + * hyperv: implement new APIs =20 The `virDomainGetMaxMemory()``, ``virDomainSetMaxMemory()``, --=20 2.26.2