/* * libvirt-secret.c: entry points for virSecretPtr APIs * * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include #include "datatypes.h" #include "virlog.h" VIR_LOG_INIT("libvirt.secret"); #define VIR_FROM_THIS VIR_FROM_SECRET /** * virSecretGetConnect: * @secret: A virSecret secret * * Provides the connection pointer associated with a secret. The reference * counter on the connection is not increased by this call. * * Returns the virConnectPtr or NULL in case of failure. */ virConnectPtr virSecretGetConnect(virSecretPtr secret) { VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, NULL); return secret->conn; } /** * virConnectNumOfSecrets: * @conn: virConnect connection * * Fetch number of currently defined secrets. * * Returns the number currently defined secrets. */ int virConnectNumOfSecrets(virConnectPtr conn) { VIR_DEBUG("conn=%p", conn); virResetLastError(); virCheckConnectReturn(conn, -1); if (conn->secretDriver != NULL && conn->secretDriver->connectNumOfSecrets != NULL) { int ret; ret = conn->secretDriver->connectNumOfSecrets(conn); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virConnectListAllSecrets: * @conn: Pointer to the hypervisor connection. * @secrets: Pointer to a variable to store the array containing the secret * objects or NULL if the list is not required (just returns the * number of secrets). * @flags: bitwise-OR of virConnectListAllSecretsFlags. * * Collect the list of secrets, and allocate an array to store those * objects. * * Normally, all secrets are returned; however, @flags can be used to * filter the results for a smaller list of targeted secrets. The valid * flags are divided into groups, where each group contains bits that * describe mutually exclusive attributes of a secret, and where all bits * within a group describe all possible secrets. * * The first group of @flags is used to filter secrets by its storage * location. Flag VIR_CONNECT_LIST_SECRETS_EPHEMERAL selects secrets that * are kept only in memory. Flag VIR_CONNECT_LIST_SECRETS_NO_EPHEMERAL * selects secrets that are kept in persistent storage. * * The second group of @flags is used to filter secrets by privacy. Flag * VIR_CONNECT_LIST_SECRETS_PRIVATE selects secrets that are never revealed * to any caller of libvirt nor to any other node. Flag * VIR_CONNECT_LIST_SECRETS_NO_PRIVATE selects non-private secrets. * * Returns the number of secrets found or -1 and sets @secrets to NULL in case * of error. On success, the array stored into @secrets is guaranteed to * have an extra allocated element set to NULL but not included in the return count, * to make iteration easier. The caller is responsible for calling * virSecretFree() on each array element, then calling free() on @secrets. */ int virConnectListAllSecrets(virConnectPtr conn, virSecretPtr **secrets, unsigned int flags) { VIR_DEBUG("conn=%p, secrets=%p, flags=0x%x", conn, secrets, flags); virResetLastError(); if (secrets) *secrets = NULL; virCheckConnectReturn(conn, -1); if (conn->secretDriver && conn->secretDriver->connectListAllSecrets) { int ret; ret = conn->secretDriver->connectListAllSecrets(conn, secrets, flags); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virConnectListSecrets: * @conn: virConnect connection * @uuids: Pointer to an array to store the UUIDs * @maxuuids: size of the array. * * List UUIDs of defined secrets, store pointers to names in uuids. * * The use of this function is discouraged. Instead, use * virConnectListAllSecrets(). * * Returns the number of UUIDs provided in the array, or -1 on failure. */ int virConnectListSecrets(virConnectPtr conn, char **uuids, int maxuuids) { VIR_DEBUG("conn=%p, uuids=%p, maxuuids=%d", conn, uuids, maxuuids); virResetLastError(); virCheckConnectReturn(conn, -1); virCheckNonNullArrayArgGoto(uuids, maxuuids, error); virCheckNonNegativeArgGoto(maxuuids, error); if (conn->secretDriver != NULL && conn->secretDriver->connectListSecrets != NULL) { int ret; ret = conn->secretDriver->connectListSecrets(conn, uuids, maxuuids); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virSecretLookupByUUID: * @conn: pointer to the hypervisor connection * @uuid: the raw UUID for the secret * * Try to lookup a secret on the given hypervisor based on its UUID. * Uses the 16 bytes of raw data to describe the UUID * * virSecretFree should be used to free the resources after the * secret object is no longer needed. * * Returns a new secret object or NULL in case of failure. If the * secret cannot be found, then VIR_ERR_NO_SECRET error is raised. */ virSecretPtr virSecretLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { VIR_UUID_DEBUG(conn, uuid); virResetLastError(); virCheckConnectReturn(conn, NULL); virCheckNonNullArgGoto(uuid, error); if (conn->secretDriver && conn->secretDriver->secretLookupByUUID) { virSecretPtr ret; ret = conn->secretDriver->secretLookupByUUID(conn, uuid); if (!ret) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virSecretLookupByUUIDString: * @conn: pointer to the hypervisor connection * @uuidstr: the string UUID for the secret * * Try to lookup a secret on the given hypervisor based on its UUID. * Uses the printable string value to describe the UUID * * virSecretFree should be used to free the resources after the * secret object is no longer needed. * * Returns a new secret object or NULL in case of failure. If the * secret cannot be found, then VIR_ERR_NO_SECRET error is raised. */ virSecretPtr virSecretLookupByUUIDString(virConnectPtr conn, const char *uuidstr) { unsigned char uuid[VIR_UUID_BUFLEN]; VIR_DEBUG("conn=%p, uuidstr=%s", conn, NULLSTR(uuidstr)); virResetLastError(); virCheckConnectReturn(conn, NULL); virCheckNonNullArgGoto(uuidstr, error); if (virUUIDParse(uuidstr, uuid) < 0) { virReportInvalidArg(uuidstr, _("uuidstr in %s must be a valid UUID"), __FUNCTION__); goto error; } return virSecretLookupByUUID(conn, &uuid[0]); error: virDispatchError(conn); return NULL; } /** * virSecretLookupByUsage: * @conn: pointer to the hypervisor connection * @usageType: the type of secret usage * @usageID: identifier of the object using the secret * * Try to lookup a secret on the given hypervisor based on its usage * The usageID is unique within the set of secrets sharing the * same usageType value. * * virSecretFree should be used to free the resources after the * secret object is no longer needed. * * Returns a new secret object or NULL in case of failure. If the * secret cannot be found, then VIR_ERR_NO_SECRET error is raised. */ virSecretPtr virSecretLookupByUsage(virConnectPtr conn, int usageType, const char *usageID) { VIR_DEBUG("conn=%p, usageType=%d usageID=%s", conn, usageType, NULLSTR(usageID)); virResetLastError(); virCheckConnectReturn(conn, NULL); virCheckNonNullArgGoto(usageID, error); if (conn->secretDriver && conn->secretDriver->secretLookupByUsage) { virSecretPtr ret; ret = conn->secretDriver->secretLookupByUsage(conn, usageType, usageID); if (!ret) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virSecretDefineXML: * @conn: virConnect connection * @xml: XML describing the secret. * @flags: bitwise-OR of virSecretDefineFlags * * If XML specifies a UUID, locates the specified secret and replaces all * attributes of the secret specified by UUID by attributes specified in xml * (any attributes not specified in xml are discarded). * * Otherwise, creates a new secret with an automatically chosen UUID, and * initializes its attributes from xml. * * virSecretFree should be used to free the resources after the * secret object is no longer needed. * * Returns a secret on success, NULL on failure. */ virSecretPtr virSecretDefineXML(virConnectPtr conn, const char *xml, unsigned int flags) { VIR_DEBUG("conn=%p, xml=%s, flags=0x%x", conn, NULLSTR(xml), flags); virResetLastError(); virCheckConnectReturn(conn, NULL); virCheckReadOnlyGoto(conn->flags, error); virCheckNonNullArgGoto(xml, error); if (conn->secretDriver != NULL && conn->secretDriver->secretDefineXML != NULL) { virSecretPtr ret; ret = conn->secretDriver->secretDefineXML(conn, xml, flags); if (ret == NULL) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virSecretGetUUID: * @secret: A virSecret secret * @uuid: buffer of VIR_UUID_BUFLEN bytes in size * * Fetches the UUID of the secret. * * Returns 0 on success with the uuid buffer being filled, or * -1 upon failure. */ int virSecretGetUUID(virSecretPtr secret, unsigned char *uuid) { VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, -1); virCheckNonNullArgGoto(uuid, error); memcpy(uuid, &secret->uuid[0], VIR_UUID_BUFLEN); return 0; error: virDispatchError(secret->conn); return -1; } /** * virSecretGetUUIDString: * @secret: a secret object * @buf: pointer to a VIR_UUID_STRING_BUFLEN bytes array * * Get the UUID for a secret as string. For more information about * UUID see RFC4122. * * Returns -1 in case of error, 0 in case of success */ int virSecretGetUUIDString(virSecretPtr secret, char *buf) { VIR_DEBUG("secret=%p, buf=%p", secret, buf); virResetLastError(); virCheckSecretReturn(secret, -1); virCheckNonNullArgGoto(buf, error); virUUIDFormat(secret->uuid, buf); return 0; error: virDispatchError(secret->conn); return -1; } /** * virSecretGetUsageType: * @secret: a secret object * * Get the type of object which uses this secret. The returned * value is one of the constants defined in the virSecretUsageType * enumeration. More values may be added to this enumeration in * the future, so callers should expect to see usage types they * do not explicitly know about. * * Returns a positive integer identifying the type of object, * or -1 upon error. */ int virSecretGetUsageType(virSecretPtr secret) { VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, -1); return secret->usageType; } /** * virSecretGetUsageID: * @secret: a secret object * * Get the unique identifier of the object with which this * secret is to be used. The format of the identifier is * dependent on the usage type of the secret. For a secret * with a usage type of VIR_SECRET_USAGE_TYPE_VOLUME the * identifier will be a fully qualified path name. The * identifiers are intended to be unique within the set of * all secrets sharing the same usage type. ie, there shall * only ever be one secret for each volume path. * * Returns a string identifying the object using the secret, * or NULL upon error */ const char * virSecretGetUsageID(virSecretPtr secret) { VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, NULL); return secret->usageID; } /** * virSecretGetXMLDesc: * @secret: A virSecret secret * @flags: extra flags; not used yet, so callers should always pass 0 * * Fetches an XML document describing attributes of the secret. * * Returns the XML document on success, NULL on failure. The caller must * free() the XML. */ char * virSecretGetXMLDesc(virSecretPtr secret, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("secret=%p, flags=0x%x", secret, flags); virResetLastError(); virCheckSecretReturn(secret, NULL); conn = secret->conn; if (conn->secretDriver != NULL && conn->secretDriver->secretGetXMLDesc != NULL) { char *ret; ret = conn->secretDriver->secretGetXMLDesc(secret, flags); if (ret == NULL) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virSecretSetValue: * @secret: A virSecret secret * @value: Value of the secret * @value_size: Size of the value * @flags: extra flags; not used yet, so callers should always pass 0 * * Sets the value of a secret. * * Returns 0 on success, -1 on failure. */ int virSecretSetValue(virSecretPtr secret, const unsigned char *value, size_t value_size, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("secret=%p, value=%p, value_size=%zu, flags=0x%x", secret, value, value_size, flags); virResetLastError(); virCheckSecretReturn(secret, -1); conn = secret->conn; virCheckReadOnlyGoto(conn->flags, error); virCheckNonNullArgGoto(value, error); if (conn->secretDriver != NULL && conn->secretDriver->secretSetValue != NULL) { int ret; ret = conn->secretDriver->secretSetValue(secret, value, value_size, flags); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virSecretGetValue: * @secret: A virSecret connection * @value_size: Place for storing size of the secret value * @flags: extra flags; not used yet, so callers should always pass 0 * * Fetches the value of a secret. * * Returns the secret value on success, NULL on failure. The caller must * free() the secret value. */ unsigned char * virSecretGetValue(virSecretPtr secret, size_t *value_size, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("secret=%p, value_size=%p, flags=0x%x", secret, value_size, flags); virResetLastError(); virCheckSecretReturn(secret, NULL); conn = secret->conn; virCheckReadOnlyGoto(conn->flags, error); virCheckNonNullArgGoto(value_size, error); if (conn->secretDriver != NULL && conn->secretDriver->secretGetValue != NULL) { unsigned char *ret; ret = conn->secretDriver->secretGetValue(secret, value_size, flags); if (ret == NULL) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virSecretUndefine: * @secret: A virSecret secret * * Deletes the specified secret. This does not free the associated * virSecretPtr object. * * Returns 0 on success, -1 on failure. */ int virSecretUndefine(virSecretPtr secret) { virConnectPtr conn; VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, -1); conn = secret->conn; virCheckReadOnlyGoto(conn->flags, error); if (conn->secretDriver != NULL && conn->secretDriver->secretUndefine != NULL) { int ret; ret = conn->secretDriver->secretUndefine(secret); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virSecretRef: * @secret: the secret to hold a reference on * * Increment the reference count on the secret. For each additional call to * this method, there shall be a corresponding call to virSecretFree to release * the reference count, once the caller no longer needs the reference to this * object. * * This method is typically useful for applications where multiple threads are * using a connection, and it is required that the connection remain open until * all threads have finished using it. ie, each new thread using a secret would * increment the reference count. * * Returns 0 in case of success, -1 in case of failure. */ int virSecretRef(virSecretPtr secret) { VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, -1); virObjectRef(secret); return 0; } /** * virSecretFree: * @secret: pointer to a secret * * Release the secret handle. The underlying secret continues to exist. * * Returns 0 on success, or -1 on error */ int virSecretFree(virSecretPtr secret) { VIR_DEBUG("secret=%p", secret); virResetLastError(); virCheckSecretReturn(secret, -1); virObjectUnref(secret); return 0; } /** * virConnectSecretEventRegisterAny: * @conn: pointer to the connection * @secret: pointer to the secret * @eventID: the event type to receive * @cb: callback to the function handling secret events * @opaque: opaque data to pass on to the callback * @freecb: optional function to deallocate opaque when not used anymore * * Adds a callback to receive notifications of arbitrary secret events * occurring on a secret. This function requires that an event loop * has been previously registered with virEventRegisterImpl() or * virEventRegisterDefaultImpl(). * * If @secret is NULL, then events will be monitored for any secret. * If @secret is non-NULL, then only the specific secret will be monitored. * * Most types of events have a callback providing a custom set of parameters * for the event. When registering an event, it is thus necessary to use * the VIR_SECRET_EVENT_CALLBACK() macro to cast the * supplied function pointer to match the signature of this method. * * The virSecretPtr object handle passed into the callback upon delivery * of an event is only valid for the duration of execution of the callback. * If the callback wishes to keep the secret object after the callback * returns, it shall take a reference to it, by calling virSecretRef(). * The reference can be released once the object is no longer required * by calling virSecretFree(). * * The return value from this method is a positive integer identifier * for the callback. To unregister a callback, this callback ID should * be passed to the virConnectSecretEventDeregisterAny() method. * * Returns a callback identifier on success, -1 on failure. */ int virConnectSecretEventRegisterAny(virConnectPtr conn, virSecretPtr secret, int eventID, virConnectSecretEventGenericCallback cb, void *opaque, virFreeCallback freecb) { VIR_DEBUG("conn=%p, secret=%p, eventID=%d, cb=%p, opaque=%p, freecb=%p", conn, secret, eventID, cb, opaque, freecb); virResetLastError(); virCheckConnectReturn(conn, -1); if (secret) { virCheckSecretGoto(secret, error); if (secret->conn != conn) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(secret->uuid, uuidstr); virReportInvalidArg(secret, _("secret '%s' in %s must match connection"), uuidstr, __FUNCTION__); goto error; } } virCheckNonNullArgGoto(cb, error); virCheckNonNegativeArgGoto(eventID, error); if (eventID >= VIR_SECRET_EVENT_ID_LAST) { virReportInvalidArg(eventID, _("eventID in %s must be less than %d"), __FUNCTION__, VIR_SECRET_EVENT_ID_LAST); goto error; } if (conn->secretDriver && conn->secretDriver->connectSecretEventRegisterAny) { int ret; ret = conn->secretDriver->connectSecretEventRegisterAny(conn, secret, eventID, cb, opaque, freecb); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virConnectSecretEventDeregisterAny: * @conn: pointer to the connection * @callbackID: the callback identifier * * Removes an event callback. The callbackID parameter should be the * value obtained from a previous virConnectSecretEventRegisterAny() method. * * Returns 0 on success, -1 on failure. */ int virConnectSecretEventDeregisterAny(virConnectPtr conn, int callbackID) { VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID); virResetLastError(); virCheckConnectReturn(conn, -1); virCheckNonNegativeArgGoto(callbackID, error); if (conn->secretDriver && conn->secretDriver->connectSecretEventDeregisterAny) { int ret; ret = conn->secretDriver->connectSecretEventDeregisterAny(conn, callbackID); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; }