mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
Introduce OpenSSH authorized key file mgmt APIs
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 <mprivozn@redhat.com> Reviewed-by: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
parent
7dc12ac2f8
commit
de0b6dd63e
@ -5101,4 +5101,21 @@ int virDomainBackupBegin(virDomainPtr domain,
|
||||
char *virDomainBackupGetXMLDesc(virDomainPtr domain,
|
||||
unsigned int flags);
|
||||
|
||||
int virDomainAuthorizedSSHKeysGet(virDomainPtr domain,
|
||||
const char *user,
|
||||
char ***keys,
|
||||
unsigned int flags);
|
||||
|
||||
typedef enum {
|
||||
VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND = (1 << 0), /* don't truncate file, just append */
|
||||
VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE = (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 */
|
||||
|
@ -1387,6 +1387,19 @@ typedef char *
|
||||
(*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain,
|
||||
unsigned int flags);
|
||||
|
||||
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;
|
||||
|
||||
@ -1650,4 +1663,6 @@ struct _virHypervisorDriver {
|
||||
virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
|
||||
virDrvDomainBackupBegin domainBackupBegin;
|
||||
virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
|
||||
virDrvDomainAuthorizedSSHKeysGet domainAuthorizedSSHKeysGet;
|
||||
virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet;
|
||||
};
|
||||
|
@ -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=%s, keys=%p, flags=0x%x",
|
||||
user, keys, flags);
|
||||
|
||||
virResetLastError();
|
||||
|
||||
virCheckDomainReturn(domain, -1);
|
||||
conn = domain->conn;
|
||||
virCheckNonNullArgGoto(user, error);
|
||||
virCheckNonNullArgGoto(keys, error);
|
||||
|
||||
virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->domainAuthorizedSSHKeysGet) {
|
||||
int ret;
|
||||
ret = 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 = 0, @keys = NULL
|
||||
* and @flags = 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=%s, keys=%p, nkeys=%d, flags=0x%x",
|
||||
user, keys, nkeys, flags);
|
||||
|
||||
virResetLastError();
|
||||
|
||||
virCheckDomainReturn(domain, -1);
|
||||
conn = 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 = conn->driver->domainAuthorizedSSHKeysSet(domain, user,
|
||||
keys, nkeys, flags);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
virReportUnsupportedError();
|
||||
error:
|
||||
virDispatchError(conn);
|
||||
return -1;
|
||||
}
|
||||
|
@ -873,4 +873,10 @@ LIBVIRT_6.0.0 {
|
||||
virDomainBackupGetXMLDesc;
|
||||
} LIBVIRT_5.10.0;
|
||||
|
||||
LIBVIRT_6.10.0 {
|
||||
global:
|
||||
virDomainAuthorizedSSHKeysGet;
|
||||
virDomainAuthorizedSSHKeysSet;
|
||||
} LIBVIRT_6.0.0;
|
||||
|
||||
# .... define new API here using predicted next version number ....
|
||||
|
Loading…
Reference in New Issue
Block a user