|| (VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET == credentialType)
|| (VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET == credentialType)
|| (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType)
- || (VIX_USER_CREDENTIAL_SSPI == credentialType)) {
+ || (VIX_USER_CREDENTIAL_SSPI == credentialType)
+ || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType)) {
/*
* All of these are optional.
*/
|| (VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET == credentialType)
|| (VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET == credentialType)
|| (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType)
- || (VIX_USER_CREDENTIAL_SSPI == credentialType)) {
+ || (VIX_USER_CREDENTIAL_SSPI == credentialType)
+ || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType)) {
destPtr = (char *) commandRequest;
destPtr += commandRequest->commonHeader.headerLength;
destPtr += commandRequest->commonHeader.bodyLength;
#define VIX_USER_CREDENTIAL_NAMED_INTERACTIVE_USER 8
#define VIX_USER_CREDENTIAL_TICKETED_SESSION 9
#define VIX_USER_CREDENTIAL_SSPI 10
+#define VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN 11
#define VIX_SHARED_SECRET_CONFIG_USER_NAME "__VMware_Vix_Shared_Secret_1__"
VixCommandSSPI;
+/*
+ * **********************************************************
+ * This is a SAML bearer token with optional userName to specify
+ * an IdProvider store.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct VixCommandSAMLToken {
+ uint32 tokenLength;
+ uint32 nameLength;
+}
+#include "vmware_pack_end.h"
+VixCommandSAMLToken;
+
/*
* **********************************************************
* Basic power op request. The response is just a generic
#endif // VIX_HIDE_BORA_DEPENDENCIES
+
+/*
+ * This is an expanded view of a VixError
+ * Every VixError is a 64-bit int, so it can fit into this struct.
+ *
+ * The flags, extraErrorType, and extraError are all optional. They
+ * do not have to be set for any error. In fact, these are guaranteed
+ * to be all 0 when the error is VIX_OK. This means that any program
+ * that checks (VIX_OK == err) or (VIX_OK != err) will always work.
+ *
+ * The basic error field is a Vix error value, and it's the lsb
+ * of the new struct. This means that a 64-bit error can be assigned
+ * enum constant, like an integer. For example, err = VIX_E_FAIL; works.
+ * This just leaves the flags and extraError fields as 0.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct VixErrorFields {
+ uint16 error;
+
+ uint8 flags;
+
+ uint8 extraErrorType;
+ uint32 extraError;
+}
+#include "vmware_pack_end.h"
+VixErrorFields;
+
+/*
+ * These are the flags for a Vix error.
+ */
+enum {
+ VIX_ERRORFLAG_GUEST = 0x0001,
+ VIX_ERRORFLAG_REMOTE = 0x0002,
+};
+
+/*
+ * These are the types of extra error in a Vix error.
+ */
+enum {
+ VIX_ERROREXTRATYPE_NONE = 0,
+ VIX_ERROREXTRATYPE_SNAPSHOT = 1,
+ VIX_ERROREXTRATYPE_DISKLIB = 2,
+ VIX_ERROREXTRATYPE_WINDOWS = 3,
+ VIX_ERROREXTRATYPE_LINUX = 4,
+ VIX_ERROREXTRATYPE_FILE = 5,
+ VIX_ERROREXTRATYPE_VMDB = 6,
+ VIX_ERROREXTRATYPE_AIO = 7,
+ VIX_ERROREXTRATYPE_CRYPTO = 8,
+ VIX_ERROREXTRATYPE_KEYSAFE = 9,
+ VIX_ERROREXTRATYPE_BLOCKLIST = 10,
+ VIX_ERROREXTRATYPE_V2I = 11,
+ VIX_ERROREXTRATYPE_MSGPOST = 12,
+};
+
+
+/*
+ * These are the types of extra error in a Vix error.
+ */
+#define VIX_ERROR_BASE_ERROR(err) ((VixErrorFields *) &err)->error
+#define VIX_ERROR_EXTRA_ERROR(err) ((VixErrorFields *) &err)->extraError
+#define VIX_ERROR_EXTRA_ERROR_TYPE(err) ((VixErrorFields *) &err)->extraErrorType
+#define VIX_ERROR_FROM_GUEST(err) (((VixErrorFields *) &err)->flags & VIX_ERRORFLAG_GUEST)
+#define VIX_ERROR_FROM_REMOTE(err) (((VixErrorFields *) &err)->flags & VIX_ERRORFLAG_REMOTE)
+#define VIX_ERROR_SET_FROM_GUEST(err) (((VixErrorFields *) &err)->flags |= VIX_ERRORFLAG_GUEST)
+#define VIX_ERROR_SET_FROM_REMOTE(err) (((VixErrorFields *) &err)->flags |= VIX_ERRORFLAG_REMOTE)
+
+#define VIX_SET_GUEST_WINDOWS_ERROR(err, vixError, winError) \
+ do { \
+ err = 0; \
+ VIX_ERROR_BASE_ERROR(err) = vixError; \
+ VIX_ERROR_EXTRA_ERROR(err) = winError; \
+ VIX_ERROR_EXTRA_ERROR_TYPE(err) = VIX_ERROREXTRATYPE_WINDOWS; \
+ VIX_ERROR_SET_FROM_GUEST(err); \
+ } while (0)
+
+#define VIX_ERROR_SET_ADDITIONAL_ERROR(err, vixError, additionalError) \
+ do { \
+ err = additionalError; \
+ err = (err << 32) | vixError; \
+ } while (0)
+
/*
* This defines additional error codes.
* The public error codes are defined in vix.h
VIX_E_REG_KEY_INVALID = 20008,
VIX_E_REG_KEY_HAS_SUBKEYS = 20009,
VIX_E_REG_VALUE_NOT_FOUND = 20010,
+ VIX_E_REG_KEY_ALREADY_EXISTS = 20011,
/* Reg Errors*/
VIX_E_REG_INCORRECT_VALUE_TYPE = 25000
#error No compiler defined for Atomic_ReadAdd64
#endif
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Atomic_ReadSub64 --
+ *
+ * Atomic read (returned), sub a value, write.
+ *
+ * Results:
+ * The value of the variable before the operation.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+Atomic_ReadSub64(Atomic_uint64 *var, // IN
+ uint64 val) // IN
+{
+ // Do an sub by an add and a overflow
+ return Atomic_ReadAdd64(var, -val);
+}
#endif
uint64 result, dummy;
__asm__("mulq %3 \n\t"
- "shrdq %1, %0 \n\t"
+ "shrdq %b4, %1, %0 \n\t"
: "=a" (result),
"=d" (dummy)
: "0" (multiplier),
int64 result, dummy;
__asm__("imulq %3 \n\t"
- "shrdq %1, %0 \n\t"
+ "shrdq %b4, %1, %0 \n\t"
: "=a" (result),
"=d" (dummy)
: "0" (multiplier),
#define INVALID_LPN64 ((LPN64)-1)
#define INVALID_PAGENUM ((PageNum)-1)
+#define INVALID_MPN64 ((MPN64)-1)
/*
* Format modifier for printing VA, LA, and VPN.
* Queues with pre-mapped data pages must be small, so that we don't pin
* too much kernel memory (especially on vmkernel). We limit a queuepair to
* 32 KB, or 16 KB per queue for symmetrical pairs.
+ *
+ * XXX, we are raising this limit to 4MB to support high-throughput workloads
+ * with vioi-filter. Once we switch to rings instead of queuepairs for the
+ * page channel, we will drop this limit again. See PR 852983.
*/
-#define VMCI_MAX_PINNED_QP_MEMORY (32 * 1024)
+#define VMCI_MAX_PINNED_QP_MEMORY (4 * 1024 * 1024)
/*
* We have a fixed set of resource IDs available in the VMX.
*/
#define VMCI_CORE_DEVICE_RESOURCE_MAX VMCI_QUEUEPAIR_DETACH
+/*
+ * VMCI reserved host datagram resource IDs.
+ * vsock control channel has resource id 1.
+ */
+#define VMCI_DVFILTER_DATA_PATH_DATAGRAM 2
+
/* VMCI Ids. */
typedef uint32 VMCIId;
* Queues with pre-mapped data pages must be small, so that we don't pin
* too much kernel memory (especially on vmkernel). We limit a queuepair to
* 32 KB, or 16 KB per queue for symmetrical pairs.
+ *
+ * XXX, we are raising this limit to 4MB to support high-throughput workloads
+ * with vioi-filter. Once we switch to rings instead of queuepairs for the
+ * page channel, we will drop this limit again. See PR 852983.
*/
-#define VMCI_MAX_PINNED_QP_MEMORY (32 * 1024)
+#define VMCI_MAX_PINNED_QP_MEMORY (4 * 1024 * 1024)
/*
* We have a fixed set of resource IDs available in the VMX.
*/
#define VMCI_CORE_DEVICE_RESOURCE_MAX VMCI_QUEUEPAIR_DETACH
+/*
+ * VMCI reserved host datagram resource IDs.
+ * vsock control channel has resource id 1.
+ */
+#define VMCI_DVFILTER_DATA_PATH_DATAGRAM 2
+
/* VMCI Ids. */
typedef uint32 VMCIId;
#define VMCI_PACKET_RECV_THRESHOLD 150
+/*
+ * Maximum number of elements per DGRAM packet (for setting receive buffers).
+ */
+
+#define VMCI_PACKET_DGRAM_MAX_ELEMS \
+ ((VMCI_MAX_DG_PAYLOAD_SIZE - sizeof(VPageChannelPacket)) / \
+ sizeof(VPageChannelElem))
+
/*
* All flags. We use this to check the validity of the flags, so put it here
* instead of in the header, otherwise people might assume we mean for them
*/
struct VPageChannel {
+ VPageChannelState state;
+
VMCIHandle dgHandle;
uint32 flags;
VPageChannelRecvCB recvCB;
uint64 consumeQSize;
VMCIId attachSubId;
VMCIId detachSubId;
- Bool qpConnected;
Bool useSpinLock;
spinlock_t qpRecvLock;
spinlock_t qpSendLock;
* Receiving buffer.
*/
- int curRecvBufs;
+ Atomic_Int curRecvBufs;
int recvBufsTarget;
int defaultRecvBufs;
int maxRecvBufs;
static int VPageChannelSendControl(VPageChannel *channel,
+ VPageChannelPacketType type,
char *message,
int len,
- VPageChannelPacketType type,
int numElems,
VPageChannelElem *elems);
/*
*-----------------------------------------------------------------------------
*
- * VPageChannelSetRecvBuffers --
+ * VPageChannelAddRecvBuffers --
*
- * Set the receiving buffers for the channel.
+ * Add receiving buffers for the channel. This will ask the client to
+ * to allocate the required elements and then pass those to the peer.
+ * If "byControl" is TRUE, then the DGRAM control channel will be used,
+ * and multiple packets will be sent if necessary.
*
* Results:
- * VMCI_SUCCESS if set, negative error code otherwise.
+ * The number of buffers actually sent to the peer.
*
* Side effects:
* None.
*/
static int
-VPageChannelSetRecvBuffers(VPageChannel *channel, // IN
+VPageChannelAddRecvBuffers(VPageChannel *channel, // IN
int numElems, // IN
Bool byControl) // IN
{
- int retval;
- int allocNum;
- size_t size = sizeof(VPageChannelPacket) +
- numElems * sizeof(VPageChannelElem);
+ int n;
+ int sent;
+ size_t size;
VPageChannelElem *elems;
VPageChannelPacket *packet;
ASSERT(channel);
- packet = (VPageChannelPacket *)VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
- if (packet == NULL) {
- VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
- "(size=%"FMTSZ"u).\n",
- channel,
- size));
- return VMCI_ERROR_NO_MEM;
- }
+ sent = 0;
+ size = 0;
+ elems = NULL;
+ packet = NULL;
- packet->type = VPCPacket_SetRecvBuffer;
- packet->msgLen = 0;
- packet->numElems = numElems;
+ n = min_t(int, VMCI_PACKET_DGRAM_MAX_ELEMS, numElems);
+ while (n > 0) {
+ int retval;
+ int allocNum;
- elems = VPAGECHANNEL_PACKET_ELEMS(packet);
- allocNum = channel->elemAllocFn(channel->allocClientData, elems, numElems);
- if (allocNum != numElems) {
- VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) "
- "(expected=%d) (actual=%d).\n",
- channel,
- numElems,
- allocNum));
- retval = VMCI_ERROR_NO_MEM;
- goto error;
- }
+ /*
+ * First packet is always big enough to cover any remaining elements,
+ * so just allocate it once.
+ */
- if (byControl || !channel->qpConnected) {
- retval = VPageChannelSendControl(channel, NULL, 0,
- VPCPacket_SetRecvBuffer,
- numElems, elems);
- } else {
- retval = VPageChannel_SendPacket(channel, packet);
- }
- if (retval < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) "
- "(err=%d).\n",
- channel,
- retval));
- goto error;
- }
+ if (NULL == packet) {
+ size = sizeof(VPageChannelPacket) + (n * sizeof(VPageChannelElem));
+ packet = (VPageChannelPacket *)
+ VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
+ if (packet == NULL) {
+ VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
+ "(size=%"FMTSZ"u).\n",
+ channel,
+ size));
+ goto exit;
+ }
+
+ packet->type = VPCPacket_SetRecvBuffer;
+ packet->msgLen = 0;
+ elems = VPAGECHANNEL_PACKET_ELEMS(packet);
+ }
- channel->curRecvBufs += numElems;
+ allocNum = channel->elemAllocFn(channel->allocClientData, elems, n);
+ if (0 == allocNum) {
+ /*
+ * If the client failed to allocate any elements at all then just
+ * bail out and return whatever number we managed to send so far
+ * (if any).
+ */
- VMCI_FreeKernelMem(packet, size);
+ VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) "
+ "(expected=%d).\n",
+ channel,
+ n));
+ goto exit;
+ }
- return VMCI_SUCCESS;
+ /*
+ * We wanted "n" elements, but we might only have "allocNum" because
+ * that's all the client could allocate. Pass down whatever we got.
+ */
- error:
- if (packet != NULL) {
- if (allocNum) {
+ packet->numElems = allocNum;
+
+ if (byControl || VPCState_Connected != channel->state) {
+ retval = VPageChannelSendControl(channel, VPCPacket_SetRecvBuffer,
+ NULL, 0, allocNum, elems);
+ } else {
+ retval = VPageChannel_SendPacket(channel, packet);
+ /*
+ * XXX, what if this is a non-blocking queuepair and we fail to
+ * send because it's full and we can't wait? Is it even worth it
+ * to loop?
+ */
+ }
+ if (retval < VMCI_SUCCESS) {
+ /*
+ * Failure to send is fatal. Release the client's elements and
+ * bail out.
+ */
+
+ VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) "
+ "(err=%d).\n",
+ channel,
+ retval));
channel->elemFreeFn(channel->freeClientData, elems, allocNum);
+ goto exit;
}
- VMCI_FreeKernelMem(packet, size);
+
+ Atomic_Add32(&channel->curRecvBufs, allocNum);
+
+ sent += allocNum;
+ numElems -= allocNum;
+ n = min_t(int, VMCI_PACKET_DGRAM_MAX_ELEMS, numElems);
}
- return retval;
+exit:
+ if (NULL != packet) {
+ VMCI_FreeKernelMem(packet, size);
+ }
+ return sent;
}
VPageChannelRecvPacket(VPageChannel *channel, // IN
VPageChannelPacket *packet) // IN
{
+ int curRecvBufs;
int recvBufsTarget;
ASSERT(channel);
if (packet->type != VPCPacket_Data &&
packet->type != VPCPacket_Completion_Notify &&
packet->type != VPCPacket_RequestBuffer &&
- packet->type != VPCPacket_HyperConnect) {
+ packet->type != VPCPacket_HyperConnect &&
+ packet->type != VPCPacket_HyperDisconnect) {
VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) "
"(type=%d).\n",
channel,
(LGPFX"Requested more buffers (channel=%p) "
"(cur=%d) (target=%d) (max=%d).\n",
channel,
- channel->curRecvBufs,
+ Atomic_Read32(&channel->curRecvBufs),
channel->recvBufsTarget,
channel->maxRecvBufs));
case VPCPacket_Data:
channel->recvCB(channel->clientRecvData, packet);
- channel->curRecvBufs -= packet->numElems;
+ Atomic_Sub32(&channel->curRecvBufs, packet->numElems);
+ ASSERT(Atomic_Read32(&channel->curRecvBufs) > 0);
break;
case VPCPacket_Completion_Notify:
channel->recvCB(channel->clientRecvData, packet);
break;
+ case VPCPacket_HyperDisconnect:
+ VMCI_DEBUG_LOG(10,
+ (LGPFX"Hypervisor requested disconnection "
+ "(channel=%p) (numElems=%d).\n",
+ channel,
+ packet->numElems));
+ if (packet->numElems > 0) {
+ channel->elemFreeFn(channel->freeClientData,
+ VPAGECHANNEL_PACKET_ELEMS(packet),
+ packet->numElems);
+ }
+ (void)VPageChannelSendControl(channel, VPCPacket_GuestDisconnect,
+ NULL, 0, 0, NULL);
+ if (channel->state < VPCState_Disconnecting) {
+ channel->state = VPCState_Disconnecting;
+ }
+ return VMCI_SUCCESS;
+
default:
ASSERT_NOT_IMPLEMENTED(FALSE);
break;
* in the hope that we won't hit this again.
*/
- if (channel->curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
- int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD -
- channel->curRecvBufs;
+ curRecvBufs = Atomic_Read32(&channel->curRecvBufs);
+ if (curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
+ int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD - curRecvBufs;
- if (VPageChannelSetRecvBuffers(channel, numElems, FALSE) ==
- VMCI_SUCCESS) {
- channel->recvBufsTarget = recvBufsTarget;
- }
+ (void)VPageChannelAddRecvBuffers(channel, numElems, FALSE);
+ channel->recvBufsTarget = recvBufsTarget;
}
return VMCI_SUCCESS;
ASSERT(channel);
- if (!channel->qpConnected) {
+ if (VPCState_Connected != channel->state) {
VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
channel));
return;
ASSERT(channel);
+ channel->state = VPCState_Connecting;
+
memset(&message, 0, sizeof message);
message.dgHandle = channel->dgHandle;
message.qpHandle = channel->qpHandle;
channel->qpHandle.context,
channel->qpHandle.resource));
- return VPageChannelSendControl(channel,
- (char *)&message, sizeof message,
- VPCPacket_GuestConnect, 0, NULL);
+ return VPageChannelSendControl(channel, VPCPacket_GuestConnect,
+ (char *)&message, sizeof message, 0, NULL);
}
channel,
ePayload->handle.context,
ePayload->handle.resource));
- channel->qpConnected = TRUE;
+ channel->state = VPCState_Connected;
}
}
channel,
ePayload->handle.context,
ePayload->handle.resource));
- channel->qpConnected = FALSE;
+ channel->state = VPCState_Disconnected;
}
}
channel->qpair = NULL;
}
- channel->qpConnected = FALSE;
+ channel->state = VPCState_Disconnected;
}
*/
memset(pageChannel, 0, sizeof *pageChannel);
+ pageChannel->state = VPCState_Unconnected;
pageChannel->dgHandle = VMCI_INVALID_HANDLE;
pageChannel->attachSubId = VMCI_INVALID_ID;
pageChannel->detachSubId = VMCI_INVALID_ID;
pageChannel->qpair = NULL;
pageChannel->doorbellHandle = VMCI_INVALID_HANDLE;
pageChannel->peerDoorbellHandle = VMCI_INVALID_HANDLE;
- pageChannel->qpConnected = FALSE;
pageChannel->flags = channelFlags;
pageChannel->recvCB = recvCB;
pageChannel->clientRecvData = clientRecvData;
pageChannel->resourceId = resourceId;
pageChannel->peerDgHandle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID,
peerResourceId);
- pageChannel->curRecvBufs = 0;
+ Atomic_Write32(&pageChannel->curRecvBufs, 0);
pageChannel->recvBufsTarget = defaultRecvBuffers;
pageChannel->defaultRecvBufs = defaultRecvBuffers;
pageChannel->maxRecvBufs = maxRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
if (defaultRecvBuffers) {
int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
- retval = VPageChannelSetRecvBuffers(pageChannel, numElems, TRUE);
- if (retval < VMCI_SUCCESS) {
+ if (0 == VPageChannelAddRecvBuffers(pageChannel, numElems, TRUE)) {
+ /*
+ * AddRecvBuffers() returns the number of buffers actually added. If
+ * we failed to add any at all, then fail.
+ */
+
+ retval = VMCI_ERROR_NO_MEM;
goto error;
}
}
VMCIDatagram_DestroyHnd(channel->dgHandle);
}
+ channel->state = VPCState_Free;
VMCI_FreeKernelMem(channel, sizeof *channel);
VMCI_DEBUG_LOG(10,
static int
VPageChannelSendControl(VPageChannel *channel, // IN
+ VPageChannelPacketType type, // IN
char *message, // IN
int len, // IN
- VPageChannelPacketType type, // IN
int numElems, // IN
VPageChannelElem *elems) // IN
{
ASSERT(channel);
ASSERT(type == VPCPacket_Data ||
type == VPCPacket_GuestConnect ||
- type == VPCPacket_SetRecvBuffer);
+ type == VPCPacket_SetRecvBuffer ||
+ type == VPCPacket_GuestDisconnect);
dg = NULL;
retval = VPageChannelAllocDatagram(channel, len, numElems, &dg);
ASSERT(channel);
- if (!channel->qpConnected) {
+ if (VPCState_Connected != channel->state) {
VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
channel));
return VMCI_ERROR_DST_UNREACHABLE;
ASSERT(channel);
- if (!channel->qpConnected) {
+ if (VPCState_Connected != channel->state) {
VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
channel));
return VMCI_ERROR_DST_UNREACHABLE;
void
VPageChannel_PollRecvQ(VPageChannel *channel) // IN
{
- if (channel->qpConnected) {
+ if (VPCState_Connected != channel->state) {
VPageChannelDoDoorbellCallback(channel);
}
}
#ifndef _VMCI_VERSION_H_
#define _VMCI_VERSION_H_
-#define VMCI_DRIVER_VERSION 9.5.5.0
-#define VMCI_DRIVER_VERSION_COMMAS 9,5,5,0
-#define VMCI_DRIVER_VERSION_STRING "9.5.5.0"
+#define VMCI_DRIVER_VERSION 9.5.6.0
+#define VMCI_DRIVER_VERSION_COMMAS 9,5,6,0
+#define VMCI_DRIVER_VERSION_STRING "9.5.6.0"
#endif /* _VMCI_VERSION_H_ */
/*********************************************************
- * Copyright (C) 2011 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2012 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
#include "vmci_defs.h"
#include "vmci_call_defs.h"
-/* Max size of a single tx buffer. */
+/** \cond PRIVATE */
#define VPAGECHANNEL_MAX_TX_BUF_SIZE (1 << 14)
#define VPAGECHANNEL_MAX_PAGES_PER_TX_BUFFER \
(VPAGECHANNEL_MAX_TX_BUF_SIZE / PAGE_SIZE + 1)
+/** \endcond */
+
+/**
+ * \brief Get a pointer to the elements in a packet.
+ *
+ * Returns a pointer to the elements at the end of a page channel packet.
+ *
+ * \see VPageChannelElem
+ * \see VPageChannelPacket
+ */
#define VPAGECHANNEL_PACKET_ELEMS(packet) \
(VPageChannelElem *)((char *)(packet) + \
sizeof(VPageChannelPacket) + \
packet->msgLen)
+
+/**
+ * \brief Get a pointer to the message in a packet.
+ *
+ * Returns a pointer to the message embedded in a page channel packet.
+ *
+ * \see VPageChannelPacket
+ */
+
#define VPAGECHANNEL_PACKET_MESSAGE(packet) \
(char *)((char *)(packet) + sizeof(VPageChannelPacket))
-/*
- * Flags for channel creation.
- *
- * NOTIFY_ONLY means invoke the channel's receive callback directly when a
- * notification is received. If not specified, then when a notification is
- * received, packets are read from the queuepair and the callback invoked for
- * each one separately. Not applicable on VMKernel.
- *
- * DELAYED_CB means that all callbacks run in a delayed context, and the
- * caller is allowed to block. If not specified, then callbacks run in
- * interrupt context and the channel will not block. This can only be
- * specified on the guest side for now.
- *
- * SEND_WHILE_ATOMIC indicates that the client wishes to call Send() from
- * an atomic context and that the channel should not block. If the channel
- * is not allowed to block, then the channel's pages are permanently mapped
- * and pinned. Note that this will limit the total size of the channel to
+/**
+ * \brief Notify client directly, and do not read packets.
+ *
+ * This flag indicates that the channel should invoke the client's receive
+ * callback directly when any packets are available. If not specified, then
+ * when a notification is received, packets are read from the channel and the
+ * callback invoked for each one separately.
+ *
+ * \note Not applicable to VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
+ */
+
+#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY 0x1
+
+/**
+ * \brief Invoke client's receive callback in delayed context.
+ *
+ * This flag indicates that all callbacks run in a delayed context, and the
+ * caller and callback are allowed to block. If not specified, then callbacks
+ * run in interrupt context and the channel will not block, and the caller
+ * is not allowed to block.
+ *
+ * \note Not applicable to VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
+ */
+
+#define VPAGECHANNEL_FLAGS_RECV_DELAYED 0x2
+
+/**
+ * \brief Send from an atomic context.
+ *
+ * This flag indicates that the client wishes to call Send() from an atomic
+ * context and that the channel should not block. If the channel is not
+ * allowed to block, then the channel's pages are permanently mapped and
+ * pinned. Note that this will limit the total size of the channel to
* VMCI_MAX_PINNED_QP_MEMORY.
+ *
+ * \note Not applicable to VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
*/
-#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY 0x1
-#define VPAGECHANNEL_FLAGS_RECV_DELAYED 0x2
#define VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC 0x4
+/**
+ * \brief An element describing a data range.
+ *
+ * Describes a data range, starting at a base address and for a given
+ * length, i.e., an element of a scatter-gather list. Indicates physical
+ * address for the guest and machine address for hypervisor. Can be passed
+ * via packets or buffers.
+ *
+ * \note Structure is packed.
+ *
+ * \see VPageChannelPacket
+ * \see VPageChanelBuffer
+ */
typedef
#include "vmware_pack_begin.h"
struct VPageChannelElem {
union {
- uint64 pa; // For guest
- uint64 ma; // For hypervisor
+ /** \brief Physical address for guest. */
+ uint64 pa;
+
+ /** \brief Machine address for hypervisor. */
+ uint64 ma;
};
+
+ /** \brief Length of range. */
uint32 le;
}
#include "vmware_pack_end.h"
VPageChannelElem;
+/**
+ * \brief Page channel page types.
+ *
+ * The various types of page channel packets.
+ *
+ * \see VPageChannelPacket
+ */
typedef enum {
+ /** \brief Data packet. */
VPCPacket_Data = 1,
- VPCPacket_Completion_Notify, // Hypervisor to guest only.
- VPCPacket_GuestConnect, // Connect to hypervisor. Internal use only.
- VPCPacket_HyperConnect, // Complete connection handshake. Internal.
- VPCPacket_RequestBuffer, // Request buffers. Internal use only.
- VPCPacket_SetRecvBuffer, // Set buffers. Internal use only.
+
+ /** \brief Completion notification, from hypervisor to guest. */
+ VPCPacket_Completion_Notify,
+
+ /** \cond PRIVATE */
+ /** \brief Connect to hypervisor, internal. */
+ VPCPacket_GuestConnect,
+
+ /** \brief Complete connection handshake, internal. */
+ VPCPacket_HyperConnect,
+
+ /** \brief Request buffers, internal. */
+ VPCPacket_RequestBuffer,
+
+ /** \brief Set buffers, internal. */
+ VPCPacket_SetRecvBuffer,
+
+ /** \brief Hypervisor channel disconnect, internal. */
+ VPCPacket_HyperDisconnect,
+
+ /** \brief Guest channel ACK hypervisor disconnect, internal. */
+ VPCPacket_GuestDisconnect,
+ /** \endcond */
} VPageChannelPacketType;
+/**
+ * \brief Page channel packet structure.
+ *
+ * A packet structure for passing control/data between guest and hypervisor.
+ * Can optionally contain a message and also a number of elements.
+ *
+ * \note Structure is packed.
+ *
+ * \see VPageChannelPacketType
+ */
typedef
#include "vmware_pack_begin.h"
struct VPageChannelPacket {
+ /** \brief Type of packet. */
VPageChannelPacketType type;
+
+ /** \brief Length of optional message. */
uint32 msgLen;
+
+ /** \brief Number of optional elements in packet. */
uint32 numElems;
- /*
- * Followed by msgLen of message and numElems of VPageChannelElem.
- */
+
+ /** \brief Followed by msgLen of message and numElems VPageChannelElem. */
}
#include "vmware_pack_end.h"
VPageChannelPacket;
+/**
+ * \brief Page channel buffer structure.
+ *
+ * A buffer of elements (a scatter-gather list).
+ *
+ * \note Structure is packed.
+ *
+ * \see VPageChannelElem
+ */
+
typedef
#include "vmware_pack_begin.h"
struct VPageChannelBuffer {
+ /** \brief Number of elements. */
uint32 numElems;
+
+ /** \brief First element. */
VPageChannelElem elems[1];
- /*
- * Followed by numElems - 1 of VPageChannelElem.
- */
+
+ /** \brief Followed by numElems - 1 of VPageChannelElem. */
}
#include "vmware_pack_end.h"
VPageChannelBuffer;
+/** \cond PRIVATE */
typedef
#include "vmware_pack_begin.h"
struct VPageChannelGuestConnectMessage {
+
+ /** \brief Guest channel's datagram handle for control channel. */
VMCIHandle dgHandle;
+
+ /** \brief Guest channel's queuepair handle. */
VMCIHandle qpHandle;
+
+ /** \brief Size of producer queue in queuepair in bytes. */
uint64 produceQSize;
+
+ /** \brief Size of consumer queue in queuepair in bytes. */
uint64 consumeQSize;
+
+ /** \brief Guest channel's doorbell handle. */
VMCIHandle doorbellHandle;
}
#include "vmware_pack_end.h"
typedef
#include "vmware_pack_begin.h"
struct VPageChannelHyperConnectMessage {
+ /** \brief Hypervisor's doorbell handle. */
VMCIHandle doorbellHandle;
}
#include "vmware_pack_end.h"
VPageChannelHyperConnectMessage;
+/** \endcond PRIVATE */
+
+/** \cond PRIVATE */
+typedef enum VPageChannelState {
+ VPCState_Free = 0,
+ VPCState_Unconnected,
+ VPCState_Connecting,
+ VPCState_Connected,
+ VPCState_Disconnecting,
+ VPCState_Disconnected,
+} VPageChannelState;
+/** \endcond PRIVATE */
+
+/**
+ * \brief Opaque page channel type.
+ */
struct VPageChannel;
typedef struct VPageChannel VPageChannel;
+/**
+ * \brief Client receive callback type.
+ *
+ * Type of receive callback, invoked when there are data packets in the
+ * channel. The client provides a callback with this type to
+ * VPageChannel_CreateInVM(). If VPAGECHANNEL_FLAGS_NOTIFY_ONLY is specified
+ * in the channel creation flags, then \c packet is \c NULL; otherwise,
+ * \c packet points to a channel packet.
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannelPacket
+ */
+
typedef void (*VPageChannelRecvCB)(void *clientData,
VPageChannelPacket *packet);
#if !defined(VMKERNEL)
+/**
+ * \brief Client element allocation callback type.
+ *
+ * Type of element allocation callback, invoked when the channel needs
+ * elements. The client provides a callback of this type to
+ * VPageChannel_CreateInVM().
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannelElem
+ * \see VPageChannelFreeElemFn
+ */
+
typedef int (*VPageChannelAllocElemFn)(void *clientData,
VPageChannelElem *elems,
int numElems);
+/**
+ * \brief Client element release callback type.
+ *
+ * Type of element release callback, invoked when the channel releases
+ * elements. The client provides a callback of this type to
+ * VPageChannel_CreateInVM().
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannelElem
+ * \see VPageChannelAllocElemFn
+ */
+
typedef void (*VPageChannelFreeElemFn)(void *clientData,
VPageChannelElem *elems,
int numElems);
+/*
+ ************************************************************************
+ * VPageChannel_CreateInVM */ /**
+ *
+ * \brief Create guest page channel.
+ *
+ * Creates a page channel in the guest. The channel should be released
+ * with VPageChannel_Destroy().
+ *
+ * \note Only applicable in the guest.
+ *
+ * \see VPageChannel_CreateInVMK()
+ * \see VPageChannel_Destroy()
+ *
+ * \param[out] channel Pointer to a newly constructed page
+ * channel if successful.
+ * \param[in] resourceId Resource ID on which the channel should
+ * register its control channel.
+ * \param[in] peerResourceId Resource ID of peer's control channel.
+ * \param[in] produceQSize Size of producer queue in queuepair in
+ * bytes.
+ * \param[in] consumeQSize Size of consumer queue in queuepair in
+ * bytes.
+ * \param[in] flags Channel flags.
+ * \param[in] recvCB Client's receive callback.
+ * \param[in] clientRecvData Client data for client's receive
+ * callback.
+ * \param[in] elemAlloc Element allocation callback for
+ * allocating page ranges (scatter-gather
+ * elements).
+ * \param[in] allocClientData Client data for element allocation
+ * callback.
+ * \param[in] elemFree Element release callback for elements.
+ * \param[in] freeClientData Client data for element release
+ * callback.
+ * \param[in] defRecvBufs Default number of elements sent to
+ * hypervisor channel.
+ * \param[in] maxRecvBufs Maximum number of elements that can be
+ * sent to the hypervisor channel.
+ *
+ * \retval VMCI_SUCCESS Creation succeeded, \c *channel contains
+ * a pointer to a valid channel.
+ * \retval other Failure.
+ *
+ ************************************************************************
+ */
+
int VPageChannel_CreateInVM(VPageChannel **channel,
VMCIId resourceId,
VMCIId peerResourceId,
void *allocClientData,
VPageChannelFreeElemFn elemFree,
void *freeClientData,
- int defaultRecvBuffers,
- int maxRecvBuffers);
+ int defRecvBufs,
+ int maxRecvBufs);
#else // VMKERNEL
+/*
+ ************************************************************************
+ * VPageChannel_CreateInVMK */ /**
+ *
+ * \brief Create a page channel in VMKernel.
+ *
+ * Creates a page channel. The channel should be released with
+ * VPageChannel_Destroy().
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannel_Destroy()
+ *
+ * \param[out] channel Pointer to a newly constructed page
+ * channel if successful.
+ * \param[in] resourceId Resource ID on which to register
+ * control channel.
+ * \param[in] recvCB Client's receive callback.
+ * \param[in] clientRecvData Client data for receive callback.
+ *
+ * \retval VMCI_SUCCESS Creation succeeded, \c *channel
+ * contains a pointer to a valid channel.
+ * \retval other Failure.
+ *
+ ***********************************************************************
+ */
+
int VPageChannel_CreateInVMK(VPageChannel **channel,
VMCIId resourceId,
VPageChannelRecvCB recvCB,
void *clientRecvData);
+/*
+ ************************************************************************
+ * VPageChannel_ReserveBuffers */ /**
+ *
+ * \brief Reserve guest elements.
+ *
+ * Reserve sufficient guest elements to cover the given length. The
+ * buffers can then be posted to the guest. This allocates both the
+ * buffer and the elements within the buffer.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_ReleaseBuffers()
+ *
+ * \param[in] channel Page channel.
+ * \param[in] dataLen Length to reserve in bytes.
+ * \param[out] buffer Pointer to a buffer containing elements to cover
+ * the given length if successful.
+ *
+ * \retval VMCI_SUCCESS Reservation succeeded, \c *buffer contains
+ * a pointer to a valid buffer.
+ * \retval other Failure.
+ *
+ ************************************************************************
+ */
+
int VPageChannel_ReserveBuffers(VPageChannel *channel,
size_t dataLen,
VPageChannelBuffer **buffer);
+
+/*
+ ************************************************************************
+ * VPageChannel_ReleaseBuffers */ /**
+ *
+ * \brief Release guest elements.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_ReserveBuffers()
+ *
+ * Release guest elements previous reserved with
+ * VPageChannel_ReserveBuffers(). If the buffers were sent to the guest,
+ * then only the buffer itself should be released, i.e.,
+ * \c returnToFreePool should be \c FALSE; the guest will release the
+ * buffers on completion. Otherwise, if for some reason they are not
+ * sent after reserving them, then \c returnToFreePool should be set to
+ * \c TRUE.
+ *
+ * \param[in] channel Page channel.
+ * \param[in] buffer Buffer to be released.
+ * \param[in] returnToFreePool If \c TRUE, then release the elements
+ * of the buffer along with the buffer
+ * itself. If \c FALSE, then release only
+ * the buffer pointer itself.
+ *
+ ************************************************************************
+ */
+
void VPageChannel_ReleaseBuffers(VPageChannel *channel,
VPageChannelBuffer *buffer,
Bool returnToFreePool);
/*
- * This function is called when the client is finished using the
- * scatter-gather list of a packet. This will generate a notification to the
- * guest to pass the ownership of buffers back to the guest. This can also be
- * used to read back the data from hypervisor and send it the to guest.
+ ************************************************************************
+ * VPageChannel_CompletionNotify */ /**
+ *
+ * \brief Notify channel of completion.
+ *
+ * This function is called when the client is finished using the elements
+ * (scatter-gather list) of a packet. This will generated a notification
+ * to the guest to pass ownership of the buffers back to the guest. This
+ * can also be used to read back the data from the hypervisor and send
+ * it to the guest.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_ReserveBuffers
+ *
+ * \param[in] channel Channel on which I/O is complete.
+ * \param[in] message Optional message to send to guest.
+ * \param[in] len Length of optional message.
+ * \param[in] buffer Buffer used for I/O.
+ *
+ ************************************************************************
*/
int VPageChannel_CompletionNotify(VPageChannel *channel,
int len,
VPageChannelBuffer *buffer);
+/*
+ ************************************************************************
+ * VPageChannel_MapToMa */ /**
+ *
+ * \brief Map guest PA in an element to a list of MAs.
+ *
+ * Map a guest physical address to a list of hypervisor machine
+ * addresses.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \param[in] channel Channel on which to map.
+ * \param[in] paElem Guest's physical address.
+ * \param[out] maElems Hypervisor machine addresses.
+ * \param[in] numElems Max number of hypervisor elements.
+ *
+ * \retval elems Number of mapped elements.
+ *
+ ************************************************************************
+ */
+
int VPageChannel_MapToMa(VPageChannel *channel,
VPageChannelElem paElem,
VPageChannelElem *maElems,
uint32 numElems);
+
+/*
+ ************************************************************************
+ * VPageChannel_UnmapMa */ /**
+ *
+ * \brief Unmap MA for a buffer.
+ *
+ * Unmap hypervisor machine addresses referring to a guest physical
+ * addresses.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_MapToMa
+ *
+ * \param[in] channel Channel for which to unmap.
+ * \param[in] buffer Buffer containing elements to unmap.
+ * \param[in] numElems Number of elements to unmap.
+ *
+ * \retval 0 Unmap successful.
+ * \retval -1 World not found for channel.
+ *
+ ************************************************************************
+ */
+
int VPageChannel_UnmapMa(VPageChannel *channel,
VPageChannelBuffer *buffer,
int numElems);
#endif // VMKERNEL
/*
- * Common functions.
+ ************************************************************************
+ * VPageChannel_Destroy */ /**
+ *
+ * \brief Destroy the given channel.
+ *
+ * Destroy the given channel. This will disconnect from the peer
+ * channel (if connected) and release all resources.
+ *
+ * \see VPageChannel_CreateInVMK
+ * \see VPageChannel_CreateInVM
+ *
+ * \param[in] channel The channel to be destroyed.
+ *
+ ************************************************************************
*/
void VPageChannel_Destroy(VPageChannel *channel);
+
+/*
+ ************************************************************************
+ * VPageChannel_Send */ /**
+ *
+ * \brief Send a packet to the channel's peer.
+ *
+ * Send a packet to the channel's peer. A message and a number of
+ * elements may optionally be sent. If the send is successful, the
+ * elements are owned by the peer and only the buffer itself should
+ * be released, but not the elements within. If the send fails, the
+ * client should release the buffer and the elements.
+ *
+ * \see VPageChannel_SendPacket
+ *
+ * \param[in] channel Channel on which to send.
+ * \param[in] type Type of packet to send.
+ * \param[in] message Optional message to send.
+ * \param[in] len Length of optional message.
+ * \param[in] buffer Buffer (of elements) to send.
+ *
+ * \retval VMCI_SUCCESS Packet successfully sent, buffer elements
+ * owned by peer.
+ * \retval other Failure to send, client should release
+ * elements.
+ *
+ ************************************************************************
+ */
+
int VPageChannel_Send(VPageChannel *channel,
VPageChannelPacketType type,
char *message,
int len,
VPageChannelBuffer *buffer);
+
+/*
+ ************************************************************************
+ * VPageChannel_SendPacket */ /**
+ *
+ * \brief Send the given packet to the channel's peer.
+ *
+ * Send a client-constructed packet to the channel's peer. If the
+ * send is successful, any elements in the packet are owned by the
+ * peer. Otherwise, the client retains ownership.
+ *
+ * \see VPageChannel_Send
+ *
+ * \param[in] channel Channel on which to send.
+ * \param[in] packet Packet to be sent.
+ *
+ * \retval VMCI_SUCCESS Packet successfully sent, buffer elements
+ * owned by peer.
+ * \retval other Failure to send, client should release
+ * elements.
+ *
+ ************************************************************************
+ */
+
int VPageChannel_SendPacket(VPageChannel *channel,
VPageChannelPacket *packet);
-void VPageChannel_PollRecvQ(VPageChannel *channel);
+/*
+ ************************************************************************
+ * VPageChannel_PollRecvQ */ /**
+ *
+ * \brief Poll the channel's receive queue for packets.
+ *
+ * Poll the channel's receive queue for packets from the peer. If any
+ * packets are available, the channel's receive callback will be invoked.
+ *
+ * \param[in] channel Channel to poll.
+ *
+ ************************************************************************
+ */
+
+void VPageChannel_PollRecvQ(VPageChannel *channel);
/*
- *-----------------------------------------------------------------------------
+ ************************************************************************
+ * VPageChannel_BufferLen */ /**
*
- * VPageChannelPacket_BufferLen --
+ * \brief Determine the length of a packet.
*
- * Calculate the length of the given packet.
+ * Determine the length of the given packet in bytes.
*
- * Results:
- * The length of the given packet in bytes.
+ * \param[in] packet Packet for which length is to be determined.
*
- * Side effects:
- * None.
+ * \retval bytes Size of the packet in bytes.
*
- *-----------------------------------------------------------------------------
+ ************************************************************************
*/
static INLINE size_t
return len;
}
-
+/** \cond PRIVATE */
#if defined(linux) && !defined(VMKERNEL)
#include "compat_pci.h"
#define vmci_pci_map_page(_pg, _off, _sz, _dir) \
#define vmci_pci_unmap_page(_dma, _sz, _dir) \
pci_unmap_page(NULL, (_dma), (_sz), (_dir))
#endif // linux && !VMKERNEL
+/** \endcond PRIVATE */
#endif // _VMCI_PACKET_H_
ToolsDaemonTcloReceiveVixCommand(RpcInData *data) // IN
{
VixError err = VIX_OK;
+ uint32 additionalError;
char *requestName = NULL;
VixCommandRequestHeader *requestMsg = NULL;
size_t maxResultBufferSize;
/*
* All Foundry tools commands return results that start with a foundry error
* and a guest-OS-specific error.
+ *
+ * NOTE: We have always been returning an additional 32 bit error (errno,
+ * or GetLastError() for Windows) along with the 64 bit VixError. The VMX
+ * side has been dropping the higher order 32 bits of VixError (by copying
+ * it onto a 32 bit error). They do save the additional error but as far
+ * as we can tell, it was not getting used by foundry. So at this place,
+ * for certain guest commands that have extra error information tucked into
+ * the higher order 32 bits of the VixError, we use that extra error as the
+ * additional error to be sent back to VMX.
*/
+ additionalError = VixTools_GetAdditionalError(requestMsg->opCode, err);
Str_Sprintf(tcloBuffer,
sizeof tcloBuffer,
"%"FMT64"d %d ",
err,
- Err_Errno());
+ additionalError);
destPtr = tcloBuffer + strlen(tcloBuffer);
/*
#include "impersonate.h"
#include "vixOpenSource.h"
#include "vixToolsInt.h"
+#include "vmware/tools/plugin.h"
#ifdef _WIN32
#include "registryWin32.h"
* No support for open-vm-tools.
*/
#if (defined(_WIN32) || defined(linux)) && !defined(OPEN_VM_TOOLS)
-// XXX Disabled until VGAuth API signature changes work through GoBuild
-#define SUPPORT_VGAUTH 0
+#define SUPPORT_VGAUTH 1
#else
#define SUPPORT_VGAUTH 0
#endif
#include "VGAuthIdProvider.h"
#define VMTOOLSD_APP_NAME "vmtoolsd"
+
+#define VIXTOOLS_CONFIG_USE_VGAUTH_NAME "useVGAuth"
+/*
+ * XXX Leave this off by default until the VGAuth service is being
+ * officially installed.
+ */
+#define USE_VGAUTH_DEFAULT FALSE
+
+static gboolean gSupportVGAuth = USE_VGAUTH_DEFAULT;
+static gboolean QueryVGAuthConfig(GKeyFile *confDictRef);
+
#endif
+
#define SECONDS_BETWEEN_POLL_TEST_FINISHED 1
/*
char const *obfuscatedNamePassword,
void **userToken);
+VixError GuestAuthSAMLAuthenticateAndImpersonate(
+ char const *obfuscatedNamePassword,
+ void **userToken);
+
void GuestAuthUnimpersonate();
#if SUPPORT_VGAUTH
void *clientData) // IN
{
VixError err = VIX_OK;
+#if SUPPORT_VGAUTH
+ ToolsAppCtx *ctx = (ToolsAppCtx *) clientData;
+#endif
/*
* Run unit tests on DEVEL builds.
*/
#endif
+#if SUPPORT_VGAUTH
+ gSupportVGAuth = QueryVGAuthConfig(ctx->config);
+#endif
+
#ifdef _WIN32
err = VixToolsInitializeWin32();
if (VIX_FAILED(err)) {
__FUNCTION__, vgErr);
break;
}
+ Debug("%s: translated VGAuth err "VGAUTHERR_FMT64X" to Vix err %"FMT64"d\n",
+ __FUNCTION__, vgErr, err);
+
return err;
}
}
break;
}
+ case VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN:
+ {
+ VixCommandSAMLToken *samlStruct =
+ (VixCommandSAMLToken *) credentialField;
+ credentialField += sizeof(*samlStruct);
+
+ err = VixToolsImpersonateUserImplEx(NULL,
+ credentialType,
+ credentialField,
+ userToken);
+ break;
+ }
case VIX_USER_CREDENTIAL_SSPI:
/*
* SSPI currently only supported in ticketed sessions
*/
if ((VIX_USER_CREDENTIAL_NAME_PASSWORD != credentialType)
&& (VIX_USER_CREDENTIAL_NAME_PASSWORD_OBFUSCATED != credentialType)
- && (VIX_USER_CREDENTIAL_TICKETED_SESSION != credentialType)) {
+ && (VIX_USER_CREDENTIAL_TICKETED_SESSION != credentialType)
+#if SUPPORT_VGAUTH
+ && (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN != credentialType)
+#endif
+ ) {
err = VIX_E_NOT_SUPPORTED;
goto abort;
}
+
/*
* Use the GuestAuth library to do name-password authentication
* and impersonation.
goto abort;
}
+ if (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType) {
+ if (GuestAuthEnabled()) {
+ err = GuestAuthSAMLAuthenticateAndImpersonate(obfuscatedNamePassword,
+ userToken);
+ } else {
+ err = VIX_E_NOT_SUPPORTED;
+ }
+ goto abort;
+ }
+
/* Get the authToken and impersonate */
if (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType) {
#ifdef _WIN32
si.subject.val.name = (char *) principalName;
si.comment = (char *) principalComment;
- vgErr = VGAuth_AddSubject(ctx, userName, req->addMapping, pemCert, &si);
+ vgErr = VGAuth_AddSubject(ctx, userName, req->addMapping, pemCert, &si,
+ 0, NULL);
if (VGAUTH_FAILED(vgErr)) {
err = VixToolsTranslateVGAuthError(vgErr);
}
}
if (VIX_GUEST_AUTH_PRINCIPAL_TYPE_NONE == req->principalType) {
- vgErr = VGAuth_RemoveCert(ctx, userName, pemCert);
+ vgErr = VGAuth_RemoveCert(ctx, userName, pemCert, 0, NULL);
} else {
subj.type = (req->principalType == VIX_GUEST_AUTH_PRINCIPAL_TYPE_NAMED) ?
VGAUTH_SUBJECT_NAMED : VGAUTH_SUBJECT_ANY;
subj.val.name = (char *) principalName;
- vgErr = VGAuth_RemoveSubject(ctx, userName, pemCert, &subj);
+ vgErr = VGAuth_RemoveSubject(ctx, userName, pemCert, &subj, 0, NULL);
}
if (VGAUTH_FAILED(vgErr)) {
err = VixToolsTranslateVGAuthError(vgErr);
goto abort;
}
- vgErr = VGAuth_QueryIdProviders(ctx, userName, &num, &idList);
+ vgErr = VGAuth_QueryIdProviders(ctx, userName, 0, NULL, &num, &idList);
if (VGAUTH_FAILED(vgErr)) {
err = VixToolsTranslateVGAuthError(vgErr);
goto abort;
goto abort;
}
- vgErr = VGAuth_QueryMappedIdentities(ctx, &num, &miList);
+ vgErr = VGAuth_QueryMappedIdentities(ctx, 0, NULL, &num, &miList);
if (VGAUTH_FAILED(vgErr)) {
err = VixToolsTranslateVGAuthError(vgErr);
goto abort;
{
VixError newError = origError;
- ASSERT(VIX_ERROR_CODE(origError) == origError);
-
switch (opCode) {
/*
* This should include all non-VI guest operations.
case VIX_COMMAND_LIST_FILESYSTEMS:
case VIX_COMMAND_WAIT_FOR_TOOLS:
case VIX_COMMAND_CAPTURE_SCREEN:
+ ASSERT(VIX_ERROR_CODE(origError) == origError);
switch (origError) {
case VIX_E_INVALID_LOGIN_CREDENTIALS:
newError = VIX_E_GUEST_USER_PERMISSIONS;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixTools_GetAdditionalError --
+ *
+ * Gets the vix extra/additional error if any.
+ *
+ * Some errors returned by tools may have extra error in
+ * the higher order 32 bits. We need to pass that back.
+ *
+ * Results:
+ * uint32
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+VixTools_GetAdditionalError(uint32 opCode, // IN
+ VixError error) // IN
+{
+ uint32 err;
+
+ switch (opCode) {
+ case VIX_COMMAND_CREATE_REGISTRY_KEY:
+ case VIX_COMMAND_LIST_REGISTRY_KEYS:
+ case VIX_COMMAND_DELETE_REGISTRY_KEY:
+ case VIX_COMMAND_SET_REGISTRY_VALUE:
+ case VIX_COMMAND_LIST_REGISTRY_VALUES:
+ case VIX_COMMAND_DELETE_REGISTRY_VALUE:
+ err = VIX_ERROR_EXTRA_ERROR(error);
+ break;
+ default:
+ err = Err_Errno();
+ }
+
+ return err;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
GuestAuthEnabled(void)
{
#if SUPPORT_VGAUTH
- return TRUE;
+ return gSupportVGAuth;
#else
return FALSE;
#endif
}
vgErr = VGAuth_ValidateUsernamePassword(ctx, username, password,
+ 0, NULL,
&newHandle);
if (VGAUTH_FAILED(vgErr)) {
err = VixToolsTranslateVGAuthError(vgErr);
goto done;
}
- vgErr = VGAuth_Impersonate(ctx, newHandle);
+ vgErr = VGAuth_Impersonate(ctx, newHandle, 0, NULL);
+ if (VGAUTH_FAILED(vgErr)) {
+ err = VixToolsTranslateVGAuthError(vgErr);
+ goto done;
+ }
+
+ *userToken = VGAUTH_GENERIC_USER_TOKEN;
+
+ err = VIX_OK;
+
+done:
+
+ if (newHandle) {
+ VGAuth_UserHandleFree(newHandle);
+ }
+
+ return err;
+#else
+ return VIX_E_NOT_SUPPORTED;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * GuestAuthSAMLAuthenticateAndImpersonate
+ *
+ * Do SAML bearer token authentication and impersonation using
+ * the GuestAuth library.
+ *
+ * Results:
+ * VIX_OK if successful. Other VixError code otherwise.
+ *
+ * Side effects:
+ * Current process impersonates.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VixError
+GuestAuthSAMLAuthenticateAndImpersonate(
+ char const *obfuscatedNamePassword, // IN
+ void **userToken) // OUT
+{
+#if SUPPORT_VGAUTH
+ VixError err;
+ char *token;
+ char *username;
+ VGAuthContext *ctx = NULL;
+ VGAuthError vgErr;
+ VGAuthUserHandle *newHandle = NULL;
+
+ Debug(">%s\n", __FUNCTION__);
+ err = VixMsg_DeObfuscateNamePassword(obfuscatedNamePassword,
+ &token,
+ &username);
+ if (err != VIX_OK) {
+ goto done;
+ }
+
+ err = VIX_E_INVALID_LOGIN_CREDENTIALS;
+
+ vgErr = TheVGAuthContext(&ctx);
+ if (VGAUTH_FAILED(vgErr)) {
+ err = VixToolsTranslateVGAuthError(vgErr);
+ goto done;
+ }
+
+ vgErr = VGAuth_ValidateSamlBearerToken(ctx,
+ token,
+ username,
+ 0,
+ NULL,
+ &newHandle);
+ if (VGAUTH_FAILED(vgErr)) {
+ err = VixToolsTranslateVGAuthError(vgErr);
+ goto done;
+ }
+
+ vgErr = VGAuth_Impersonate(ctx, newHandle, 0, NULL);
if (VGAUTH_FAILED(vgErr)) {
err = VixToolsTranslateVGAuthError(vgErr);
goto done;
VGAuth_UserHandleFree(newHandle);
}
+ Debug("<%s\n", __FUNCTION__);
+
return err;
#else
return VIX_E_NOT_SUPPORTED;
#if SUPPORT_VGAUTH
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueryVGAuthConfig
+ *
+ * Check the tools configuration to see if VGAuth should be used.
+ *
+ * Results:
+ * TRUE if vgauth should be used, FALSE if not.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+QueryVGAuthConfig(GKeyFile *confDictRef) // IN
+{
+ gboolean useVGAuth;
+ gboolean retVal = USE_VGAUTH_DEFAULT;
+ GError *gErr = NULL;
+
+ if (confDictRef != NULL) {
+ useVGAuth = g_key_file_get_boolean(confDictRef,
+ VIX_TOOLS_CONFIG_API_GROUPNAME,
+ VIXTOOLS_CONFIG_USE_VGAUTH_NAME,
+ &gErr);
+
+ /*
+ * g_key_file_get_boolean() will return FALSE and set an error
+ * if the value isn't in config, so use the default in that
+ * case.
+ */
+ if (!useVGAuth && (NULL != gErr)) {
+ g_error_free(gErr);
+ retVal = USE_VGAUTH_DEFAULT;
+ } else {
+ retVal = useVGAuth;
+ }
+ }
+
+ Debug("%s: vgauth usage is: %d\n", __FUNCTION__, retVal);
+
+ return retVal;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
static VGAuthContext *vgaCtx = NULL;
VGAuthError vgaCode = VGAUTH_E_OK;
+ /*
+ * XXX This needs to handle errors better -- if the service gets
+ * reset, the context will point to junk and anything using it will
+ * fail.
+ *
+ * Maybe add a no-op API here to poke it? Or make the underlying
+ * VGAuth code smarter.
+ */
if (vgaCtx == NULL) {
- vgaCode = VGAuth_Init(VMTOOLSD_APP_NAME, 0, NULL, 0, &vgaCtx);
+ vgaCode = VGAuth_Init(VMTOOLSD_APP_NAME, 0, NULL, &vgaCtx);
}
*ctx = vgaCtx;
size_t *resultLen,
Bool *deleteResultBufferResult);
+uint32 VixTools_GetAdditionalError(uint32 opCode,
+ VixError error);
Bool VixToolsImpersonateUserImpl(char const *credentialTypeStr,
int credentialType,