Hi Everyone,
Recently in our environment, we moved from the thinkclient 5.5 Vsphere software to the Webclient 6.5 Software on our ESX host. During that time our integration is broken under Vsphere 5.5 Powercli (Based on .NET 2.0 Framework). Now it seems in 6.5 it's now called Vmware Powercli and one of the components inside is actually the VSphere PowerCli component which is what I want. I did the upgrade and it impacted the project on recompile giving a bunch of undefined errors for Vmware.Vim.virtualmachine. After that, I discovered I needed to move to .Net 4.5 but it seems the Passthrough Token SSPI authentication is no longer functioning as normal. Everything else seems to work like a charm. My code is below for the SSPI authentication. This code was tested and verified to work with 5.5
[code]
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Imports VMware.Vim
Imports System.Xml.Serialization
Imports System.Xml
Imports System.Runtime.Serialization
Module SSPIClient
End Module
Public Class SspiClients
Private ReadOnly _sspiHelper As SspiHelper
Private ReadOnly _sspiPackageType As SspiPackageType
Private _clientToken As Byte()
Private _continueProcessing As Boolean
Public Sub New(ByVal principalName As String, ByVal sspiPackageType As SspiPackageType)
_sspiHelper = New SspiHelper(principalName)
_sspiPackageType = sspiPackageType
_sspiHelper.InitializeClient(_clientToken, Nothing, _continueProcessing, _sspiPackageType)
End Sub
Public ReadOnly Property Token() As Byte()
Get
Return _clientToken
End Get
End Property
Public Sub Initialize(ByVal serverToken As Byte())
_sspiHelper.InitializeClient(_clientToken, serverToken, _continueProcessing, _sspiPackageType)
End Sub
End Class
Public Enum SspiPackageType
Kerberos
NTLM
Negotiate
End Enum
Friend NotInheritable Class FaultConverter
Private Sub New()
End Sub
Public Shared Function CreateMethodFault(ByVal exception As Exception) As MethodFault
Dim fault As MethodFault = Nothing
If exception Is Nothing Then
Return Nothing
End If
Dim soapException As SoapException = If(TryCast(exception, SoapException), TryCast(exception.InnerException, SoapException))
If soapException IsNot Nothing Then
'fault = ConvertSoapException(soapException)
End If
Return fault
End Function
End Class
Public Class MethodFaultUnused
Public Sub New()
End Sub
<XmlElement("dynamicProperty")> _
Public Property dynamicProperty() As DynamicProperty()
Get
Return m_dynamicProperty
End Get
Set(ByVal value As DynamicProperty())
m_dynamicProperty = value
End Set
End Property
Private m_dynamicProperty As DynamicProperty()
Public Property dynamicType() As String
Get
Return m_dynamicType
End Get
Set(ByVal value As String)
m_dynamicType = value
End Set
End Property
Private m_dynamicType As String
Public Property faultCause() As LocalizedMethodFault
Get
Return m_faultCause
End Get
Set(ByVal value As LocalizedMethodFault)
m_faultCause = value
End Set
End Property
Private m_faultCause As LocalizedMethodFault
<XmlElement("faultMessage")> _
Public Property faultMessage() As LocalizableMessage()
Get
Return m_faultMessage
End Get
Set(ByVal value As LocalizableMessage())
m_faultMessage = value
End Set
End Property
Private m_faultMessage As LocalizableMessage()
End Class
Friend Class SspiHelper
Private Const MAX_TOKEN_SIZE As Integer = 12288
Public Const STANDARD_CONTEXT_ATTRIBUTES As Integer = NativeContants.ISC_REQ_CONFIDENTIALITY Or NativeContants.ISC_REQ_REPLAY_DETECT Or NativeContants.ISC_REQ_SEQUENCE_DETECT Or NativeContants.ISC_REQ_CONNECTION
Public Const TOKEN_QUERY As Integer = &H8
Private ReadOnly _sAccountName As String
Private _bGotClientCredentials As Boolean
Private _bGotServerContext As Boolean
Private _bGotServerCredentials As Boolean
Private _hClientContext As New SECURITY_HANDLE(0)
Private _hInboundCred As New SECURITY_HANDLE(0)
Private _hOutboundCred As New SECURITY_HANDLE(0)
Private _hServerContext As New SECURITY_HANDLE(0)
Public Sub New()
Dim windowsIdentity__1 As WindowsIdentity = WindowsIdentity.GetCurrent()
If windowsIdentity__1 IsNot Nothing Then
_sAccountName = windowsIdentity__1.Name
End If
End Sub
Public Sub New(ByVal sRemotePrincipal As String)
_sAccountName = sRemotePrincipal
End Sub
Public Sub InitializeClient(ByRef clientToken As Byte(), ByVal serverToken As Byte(), ByRef bContinueProcessing As Boolean, Optional ByVal sspiPackageType__1 As SspiPackageType = SspiPackageType.Negotiate)
clientToken = Nothing
bContinueProcessing = True
Dim clientLifeTime = New SECURITY_INTEGER(0)
If Not _bGotClientCredentials Then
Dim result As Integer = NativeMethods.AcquireCredentialsHandle(_sAccountName, sspiPackageType__1.ToString(), NativeContants.SECPKG_CRED_OUTBOUND, IntPtr.Zero, IntPtr.Zero, 0, _
IntPtr.Zero, _hOutboundCred, clientLifeTime)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("Couldn't acquire client credentials", result)
End If
_bGotClientCredentials = True
End If
Dim ss As Integer
Dim clientTokenSecBufferDesc = New SecBufferDesc(MAX_TOKEN_SIZE)
Try
Dim contextAttributes As UInteger
If serverToken Is Nothing Then
' null string pszTargetName,
'int Reserved1,
'int TargetDataRep
'Always zero first time around...
'int Reserved2,
'pHandle CtxtHandle = SecHandle
'ref SecBufferDesc pOutput, //PSecBufferDesc
'ref int pfContextAttr,
'ref IntPtr ptsExpiry ); //PTimeStamp
ss = NativeMethods.InitializeSecurityContext(_hOutboundCred, IntPtr.Zero, _sAccountName, STANDARD_CONTEXT_ATTRIBUTES, 0, NativeContants.SECURITY_NATIVE_DREP, _
IntPtr.Zero, 0, _hClientContext, clientTokenSecBufferDesc, contextAttributes, clientLifeTime)
Else
Dim serverTokenSecBufferDesc = New SecBufferDesc(serverToken)
Try
' null string pszTargetName,
'int Reserved1,
'int TargetDataRep
'Always zero first time around...
'int Reserved2,
'pHandle CtxtHandle = SecHandle
'ref SecBufferDesc pOutput, //PSecBufferDesc
'ref int pfContextAttr,
'ref IntPtr ptsExpiry ); //PTimeStamp
ss = NativeMethods.InitializeSecurityContext(_hOutboundCred, _hClientContext, _sAccountName, STANDARD_CONTEXT_ATTRIBUTES, 0, NativeContants.SECURITY_NATIVE_DREP, _
serverTokenSecBufferDesc, 0, _hClientContext, clientTokenSecBufferDesc, contextAttributes, clientLifeTime)
Finally
serverTokenSecBufferDesc.Dispose()
End Try
End If
If ss <> NativeContants.SEC_E_OK AndAlso ss <> NativeContants.SEC_I_CONTINUE_NEEDED Then
Throw New SspiException("InitializeSecurityContext() failed!!!", ss)
End If
clientToken = clientTokenSecBufferDesc.GetSecBufferByteArray()
Finally
clientTokenSecBufferDesc.Dispose()
End Try
bContinueProcessing = ss <> NativeContants.SEC_E_OK
End Sub
Public Sub InitializeServer(ByVal clientToken As Byte(), ByRef serverToken As Byte(), ByRef bContinueProcessing As Boolean, Optional ByVal sspiPackageType__1 As SspiPackageType = SspiPackageType.Negotiate)
serverToken = Nothing
bContinueProcessing = True
Dim newLifeTime = New SECURITY_INTEGER(0)
If Not _bGotServerCredentials Then
Dim result As Integer = NativeMethods.AcquireCredentialsHandle(_sAccountName, sspiPackageType__1.ToString(), NativeContants.SECPKG_CRED_INBOUND, IntPtr.Zero, IntPtr.Zero, 0, _
IntPtr.Zero, _hInboundCred, newLifeTime)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("Couldn't acquire server credentials handle!!!", result)
End If
_bGotServerCredentials = True
End If
Dim serverTokenSecBufferDesc = New SecBufferDesc(MAX_TOKEN_SIZE)
Dim clientTokenSecBufferDesc = New SecBufferDesc(clientToken)
Try
Dim ss As Integer
Dim uNewContextAttr As UInteger
If Not _bGotServerContext Then
' [in] handle to the credentials
' [in/out] handle of partially formed context. Always NULL the first time through
' [in] pointer to the input buffers
' [in] required context attributes
' [in] data representation on the target
' [in/out] receives the new context handle
' [in/out] pointer to the output buffers
' [out] receives the context attributes
' [out] receives the life span of the security context
ss = NativeMethods.AcceptSecurityContext(_hInboundCred, IntPtr.Zero, clientTokenSecBufferDesc, STANDARD_CONTEXT_ATTRIBUTES, NativeContants.SECURITY_NATIVE_DREP, _hServerContext, _
serverTokenSecBufferDesc, uNewContextAttr, newLifeTime)
Else
' [in] handle to the credentials
' [in/out] handle of partially formed context. Always NULL the first time through
' [in] pointer to the input buffers
' [in] required context attributes
' [in] data representation on the target
' [in/out] receives the new context handle
' [in/out] pointer to the output buffers
' [out] receives the context attributes
' [out] receives the life span of the security context
ss = NativeMethods.AcceptSecurityContext(_hInboundCred, _hServerContext, clientTokenSecBufferDesc, STANDARD_CONTEXT_ATTRIBUTES, NativeContants.SECURITY_NATIVE_DREP, _hServerContext, _
serverTokenSecBufferDesc, uNewContextAttr, newLifeTime)
End If
If ss <> NativeContants.SEC_E_OK AndAlso ss <> NativeContants.SEC_I_CONTINUE_NEEDED Then
Throw New SspiException("AcceptSecurityContext() failed!!!", ss)
End If
If Not _bGotServerContext Then
_bGotServerContext = True
End If
serverToken = serverTokenSecBufferDesc.GetSecBufferByteArray()
bContinueProcessing = ss <> NativeContants.SEC_E_OK
Finally
clientTokenSecBufferDesc.Dispose()
serverTokenSecBufferDesc.Dispose()
End Try
End Sub
Public Sub EncryptMessage(ByVal message As Byte(), ByVal bUseClientContext As Boolean, ByRef encryptedBuffer As Byte())
encryptedBuffer = Nothing
Dim encryptionContext As SECURITY_HANDLE = _hServerContext
If bUseClientContext Then
encryptionContext = _hClientContext
End If
Dim contextSizes As SecPkgContext_Sizes
Dim result As Integer = NativeMethods.QueryContextAttributes(encryptionContext, NativeContants.SECPKG_ATTR_SIZES, contextSizes)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("QueryContextAttribute() failed!!!", result)
End If
Dim thisSecHelper = New MultipleSecBufferHelper(1) {}
thisSecHelper(0) = New MultipleSecBufferHelper(message, SecBufferType.SECBUFFER_DATA)
thisSecHelper(1) = New MultipleSecBufferHelper(New Byte(contextSizes.cbSecurityTrailer - 1) {}, SecBufferType.SECBUFFER_TOKEN)
Dim descBuffer = New SecBufferDesc(thisSecHelper)
Try
result = NativeMethods.EncryptMessage(encryptionContext, 0, descBuffer, 0)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("EncryptMessage() failed!!!", result)
End If
encryptedBuffer = descBuffer.GetSecBufferByteArray()
Finally
descBuffer.Dispose()
End Try
End Sub
Public Sub DecryptMessage(ByVal messageLength As Integer, ByVal encryptedBuffer As Byte(), ByVal bUseClientContext As Boolean, ByRef decryptedBuffer As Byte())
decryptedBuffer = Nothing
Dim decryptionContext As SECURITY_HANDLE = _hServerContext
If bUseClientContext Then
decryptionContext = _hClientContext
End If
Dim encryptedMessage = New Byte(messageLength - 1) {}
Array.Copy(encryptedBuffer, 0, encryptedMessage, 0, messageLength)
Dim securityTrailerLength As Integer = encryptedBuffer.Length - messageLength
Dim securityTrailer = New Byte(securityTrailerLength - 1) {}
Array.Copy(encryptedBuffer, messageLength, securityTrailer, 0, securityTrailerLength)
Dim thisSecHelper = New MultipleSecBufferHelper(1) {}
thisSecHelper(0) = New MultipleSecBufferHelper(encryptedMessage, SecBufferType.SECBUFFER_DATA)
thisSecHelper(1) = New MultipleSecBufferHelper(securityTrailer, SecBufferType.SECBUFFER_TOKEN)
Dim descBuffer = New SecBufferDesc(thisSecHelper)
Try
Dim encryptionQuality As UInteger
Dim result As Integer = NativeMethods.DecryptMessage(decryptionContext, descBuffer, 0, encryptionQuality)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("DecryptMessage() failed!!!", result)
End If
decryptedBuffer = New Byte(messageLength - 1) {}
Array.Copy(descBuffer.GetSecBufferByteArray(), 0, decryptedBuffer, 0, messageLength)
Finally
descBuffer.Dispose()
End Try
End Sub
Public Sub SignMessage(ByVal message As Byte(), ByVal bUseClientContext As Boolean, ByRef signedBuffer As Byte(), ByRef hServerContext As SECURITY_HANDLE)
signedBuffer = Nothing
Dim encryptionContext As SECURITY_HANDLE = _hServerContext
If bUseClientContext Then
encryptionContext = _hClientContext
End If
Dim contextSizes As SecPkgContext_Sizes
Dim result As Integer = NativeMethods.QueryContextAttributes(encryptionContext, NativeContants.SECPKG_ATTR_SIZES, contextSizes)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("QueryContextAttribute() failed!!!", result)
End If
Dim thisSecHelper = New MultipleSecBufferHelper(1) {}
thisSecHelper(0) = New MultipleSecBufferHelper(message, SecBufferType.SECBUFFER_DATA)
thisSecHelper(1) = New MultipleSecBufferHelper(New Byte(contextSizes.cbMaxSignature - 1) {}, SecBufferType.SECBUFFER_TOKEN)
Dim descBuffer = New SecBufferDesc(thisSecHelper)
Try
result = NativeMethods.MakeSignature(encryptionContext, 0, descBuffer, 0)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("MakeSignature() failed!!!", result)
End If
'SSPIHelper.SignAndVerify(ref _hClientContext,ref hServerContext,ref DescBuffer);
Dim encryptionQuality As UInteger
NativeMethods.VerifySignature(_hServerContext, descBuffer, 0, encryptionQuality)
signedBuffer = descBuffer.GetSecBufferByteArray()
Finally
descBuffer.Dispose()
End Try
End Sub
Public Sub VerifyMessage(ByVal messageLength As Integer, ByVal signedBuffer As Byte(), ByVal bUseClientContext As Boolean, ByRef verifiedBuffer As Byte())
verifiedBuffer = Nothing
Dim decryptionContext As SECURITY_HANDLE = _hServerContext
If bUseClientContext Then
decryptionContext = _hClientContext
End If
Dim signedMessage = New Byte(messageLength - 1) {}
Array.Copy(signedBuffer, 0, signedMessage, 0, messageLength)
Dim signatureLength As Integer = signedBuffer.Length - messageLength
Dim signature = New Byte(signatureLength - 1) {}
Array.Copy(signedBuffer, messageLength, signature, 0, signatureLength)
Dim thisSecHelper = New MultipleSecBufferHelper(1) {}
thisSecHelper(0) = New MultipleSecBufferHelper(signedMessage, SecBufferType.SECBUFFER_DATA)
thisSecHelper(1) = New MultipleSecBufferHelper(signature, SecBufferType.SECBUFFER_TOKEN)
Dim descBuffer = New SecBufferDesc(thisSecHelper)
Try
Dim encryptionQuality As UInteger
Dim result As Integer = NativeMethods.VerifySignature(decryptionContext, descBuffer, 0, encryptionQuality)
If result <> NativeContants.SEC_E_OK Then
Throw New SspiException("VerifySignature() failed!!!", result)
End If
verifiedBuffer = New Byte(messageLength - 1) {}
Array.Copy(descBuffer.GetSecBufferByteArray(), 0, verifiedBuffer, 0, messageLength)
Finally
descBuffer.Dispose()
End Try
End Sub
End Class
Public NotInheritable Class NativeContants
Private Sub New()
End Sub
Public Const ISC_REQ_CONFIDENTIALITY As Integer = &H10
Public Const ISC_REQ_CONNECTION As Integer = &H800
Public Const ISC_REQ_REPLAY_DETECT As Integer = &H4
Public Const ISC_REQ_SEQUENCE_DETECT As Integer = &H8
Public Const SEC_E_OK As Integer = 0
Public Const SEC_I_CONTINUE_NEEDED As Integer = &H90312
Public Const SECPKG_ATTR_SIZES As Integer = 0
Public Const SECPKG_CRED_INBOUND As Integer = 1
Public Const SECPKG_CRED_OUTBOUND As Integer = 2
Public Const SECURITY_NATIVE_DREP As Integer = &H10
End Class
Friend NotInheritable Class NativeMethods
Private Sub New()
End Sub
'SEC_CHAR*
'SEC_CHAR* //"Kerberos","NTLM","Negotiative"
'_LUID AuthenticationID,//pvLogonID, //PLUID
'PVOID
'SEC_GET_KEY_FN
'PVOID
'SecHandle //PCtxtHandle ref
<DllImport("secur32", CharSet:=CharSet.Unicode)> _
Friend Shared Function AcquireCredentialsHandle(ByVal pszPrincipal As String, ByVal pszPackage As String, ByVal fCredentialUse As Integer, ByVal pAuthenticationId As IntPtr, ByVal pAuthData As IntPtr, ByVal pGetKeyFn As Integer, _
ByVal pvGetKeyArgument As IntPtr, ByRef phCredential As SECURITY_HANDLE, ByRef ptsExpiry As SECURITY_INTEGER) As Integer
End Function
'PTimeStamp //TimeStamp ref
'PCredHandle
'PCtxtHandle
'PSecBufferDesc SecBufferDesc
'PCtxtHandle
'PSecBufferDesc SecBufferDesc
'managed ulong == 64 bits!!!
<DllImport("secur32", CharSet:=CharSet.Unicode, SetLastError:=True)> _
Friend Shared Function InitializeSecurityContext(ByRef phCredential As SECURITY_HANDLE, ByVal phContext As IntPtr, ByVal pszTargetName As String, ByVal fContextReq As Integer, ByVal reserved1 As Integer, ByVal targetDataRep As Integer, _
ByVal pInput As IntPtr, ByVal reserved2 As Integer, ByRef phNewContext As SECURITY_HANDLE, ByRef pOutput As SecBufferDesc, ByRef pfContextAttr As UInteger, ByRef ptsExpiry As SECURITY_INTEGER) As Integer
End Function
'PTimeStamp
'PCredHandle
'PCtxtHandle
'PSecBufferDesc SecBufferDesc
'PCtxtHandle
'PSecBufferDesc SecBufferDesc
'managed ulong == 64 bits!!!
<DllImport("secur32", CharSet:=CharSet.Unicode, SetLastError:=True)> _
Friend Shared Function InitializeSecurityContext(ByRef phCredential As SECURITY_HANDLE, ByRef phContext As SECURITY_HANDLE, ByVal pszTargetName As String, ByVal fContextReq As Integer, ByVal reserved1 As Integer, ByVal targetDataRep As Integer, _
ByRef secBufferDesc As SecBufferDesc, ByVal reserved2 As Integer, ByRef phNewContext As SECURITY_HANDLE, ByRef pOutput As SecBufferDesc, ByRef pfContextAttr As UInteger, ByRef ptsExpiry As SECURITY_INTEGER) As Integer
End Function
'PTimeStamp
'managed ulong == 64 bits!!!
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function AcceptSecurityContext(ByRef phCredential As SECURITY_HANDLE, ByVal phContext As IntPtr, ByRef pInput As SecBufferDesc, ByVal fContextReq As UInteger, ByVal targetDataRep As UInteger, ByRef phNewContext As SECURITY_HANDLE, _
ByRef pOutput As SecBufferDesc, ByRef pfContextAttr As UInteger, ByRef ptsTimeStamp As SECURITY_INTEGER) As Integer
End Function
'managed ulong == 64 bits!!!
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function AcceptSecurityContext(ByRef phCredential As SECURITY_HANDLE, ByRef phContext As SECURITY_HANDLE, ByRef pInput As SecBufferDesc, ByVal fContextReq As UInteger, ByVal targetDataRep As UInteger, ByRef phNewContext As SECURITY_HANDLE, _
ByRef pOutput As SecBufferDesc, ByRef pfContextAttr As UInteger, ByRef ptsTimeStamp As SECURITY_INTEGER) As Integer
End Function
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function ImpersonateSecurityContext(ByRef phContext As SECURITY_HANDLE) As Integer
End Function
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function QueryContextAttributes(ByRef phContext As SECURITY_HANDLE, ByVal ulAttribute As UInteger, ByRef pContextAttributes As SecPkgContext_Sizes) As Integer
End Function
'managed ulong == 64 bits!!!
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function EncryptMessage(ByRef phContext As SECURITY_HANDLE, ByVal fQop As UInteger, ByRef pMessage As SecBufferDesc, ByVal messageSeqNo As UInteger) As Integer
End Function
'managed ulong == 64 bits!!!
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function DecryptMessage(ByRef phContext As SECURITY_HANDLE, ByRef pMessage As SecBufferDesc, ByVal messageSeqNo As UInteger, ByRef pfQop As UInteger) As Integer
End Function
' Context to use
' Quality of Protection
' Message to sign
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function MakeSignature(ByRef phContext As SECURITY_HANDLE, ByVal fQop As UInteger, ByRef pMessage As SecBufferDesc, ByVal messageSeqNo As UInteger) As Integer
End Function
' Message Sequence Num.
' Context to use
' Message to sign
' Message Sequence Num.
<DllImport("secur32.Dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
Friend Shared Function VerifySignature(ByRef phContext As SECURITY_HANDLE, ByRef pMessage As SecBufferDesc, ByVal messageSeqNo As UInteger, ByRef pfQop As UInteger) As Integer
End Function
' Quality of Protection
End Class
#Region "NetResource Struct"
<StructLayout(LayoutKind.Sequential)> _
Public Structure NetResource
Public Scope As UInteger
Public Type As UInteger
Public DisplayType As UInteger
Public Usage As UInteger
Public LocalName As String
Public RemoteName As String
Public Comment As String
Public Provider As String
End Structure
#End Region
#Region "Enums"
Public Enum Scope
RESOURCE_CONNECTED = 1
RESOURCE_GLOBALNET
RESOURCE_REMEMBERED
RESOURCE_RECENT
RESOURCE_CONTEXT
End Enum
Public Enum Type As UInteger
RESOURCETYPE_ANY
RESOURCETYPE_DISK
RESOURCETYPE_PRINT
RESOURCETYPE_RESERVED = 8
RESOURCETYPE_UNKNOWN = 4294967295UI
End Enum
Public Enum DisplayType
RESOURCEDISPLAYTYPE_GENERIC
RESOURCEDISPLAYTYPE_DOMAIN
RESOURCEDISPLAYTYPE_SERVER
RESOURCEDISPLAYTYPE_SHARE
RESOURCEDISPLAYTYPE_FILE
RESOURCEDISPLAYTYPE_GROUP
RESOURCEDISPLAYTYPE_NETWORK
RESOURCEDISPLAYTYPE_ROOT
RESOURCEDISPLAYTYPE_SHAREADMIN
RESOURCEDISPLAYTYPE_DIRECTORY
RESOURCEDISPLAYTYPE_TREE
RESOURCEDISPLAYTYPE_NDSCONTAINER
End Enum
Public Enum Usage As UInteger
RESOURCEUSAGE_CONNECTABLE = 1
RESOURCEUSAGE_CONTAINER = 2
RESOURCEUSAGE_NOLOCALDEVICE = 4
RESOURCEUSAGE_SIBLING = 8
RESOURCEUSAGE_ATTACHED = 16
RESOURCEUSAGE_ALL = 31
RESOURCEUSAGE_RESERVED = 2147483648UI
End Enum
Public Enum ConnectionFlags As UInteger
CONNECT_UPDATE_PROFILE = 1
CONNECT_UPDATE_RECENT = 2
CONNECT_TEMPORARY = 4
CONNECT_INTERACTIVE = 8
CONNECT_PROMPT = 16
CONNECT_NEED_DRIVE = 32
CONNECT_REFCOUNT = 64
CONNECT_REDIRECT = 128
CONNECT_LOCALDRIVE = 256
CONNECT_CURRENT_MEDIA = 512
CONNECT_DEFERRED = 1024
CONNECT_COMMANDLINE = 2048
CONNECT_CMD_SAVECRED = 4096
CONNECT_CRED_RESET = 8192
CONNECT_RESERVED = 4278190080UI
End Enum
#End Region
#Region "for sspi helper"
Public Enum SecBufferType
SECBUFFER_VERSION = 0
SECBUFFER_EMPTY = 0
SECBUFFER_DATA = 1
SECBUFFER_TOKEN = 2
End Enum
<StructLayout(LayoutKind.Sequential)> _
Public Structure SecHandle
'=PCtxtHandle
Private ReadOnly dwLower As UInteger
Private ReadOnly dwUpper As UInteger
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure SecBuffer
Public cbBuffer As Integer
Public BufferType As Integer
Friend pvBuffer As IntPtr
Public Sub New(ByVal bufferSize As Integer)
cbBuffer = bufferSize
BufferType = CInt(SecBufferType.SECBUFFER_TOKEN)
pvBuffer = Marshal.AllocHGlobal(bufferSize)
End Sub
Public Sub New(ByVal secBufferBytes As Byte())
cbBuffer = secBufferBytes.Length
BufferType = CInt(SecBufferType.SECBUFFER_TOKEN)
pvBuffer = Marshal.AllocHGlobal(cbBuffer)
Marshal.Copy(secBufferBytes, 0, pvBuffer, cbBuffer)
End Sub
Public Sub New(ByVal secBufferBytes As Byte(), ByVal bufferType__1 As SecBufferType)
cbBuffer = secBufferBytes.Length
BufferType = CInt(bufferType__1)
pvBuffer = Marshal.AllocHGlobal(cbBuffer)
Marshal.Copy(secBufferBytes, 0, pvBuffer, cbBuffer)
End Sub
Public Sub Dispose()
If pvBuffer <> IntPtr.Zero Then
Marshal.FreeHGlobal(pvBuffer)
pvBuffer = IntPtr.Zero
End If
End Sub
End Structure
Public Structure MultipleSecBufferHelper
Public Buffer As Byte()
Public BufferType As SecBufferType
Public Sub New(ByVal buffer__1 As Byte(), ByVal bufferType__2 As SecBufferType)
If buffer__1 Is Nothing OrElse buffer__1.Length = 0 Then
Throw New ArgumentException("buffer cannot be null or 0 length")
End If
Buffer = buffer__1
BufferType = bufferType__2
End Sub
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure SecBufferDesc
Public ulVersion As Integer
Public cBuffers As Integer
Public pBuffers As IntPtr
'Point to SecBuffer
Public Sub New(ByVal bufferSize As Integer)
ulVersion = CInt(SecBufferType.SECBUFFER_VERSION)
cBuffers = 1
Dim thisSecBuffer = New SecBuffer(bufferSize)
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(thisSecBuffer))
Marshal.StructureToPtr(thisSecBuffer, pBuffers, False)
End Sub
Public Sub New(ByVal secBufferBytes As Byte())
ulVersion = CInt(SecBufferType.SECBUFFER_VERSION)
cBuffers = 1
Dim thisSecBuffer = New SecBuffer(secBufferBytes)
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(thisSecBuffer))
Marshal.StructureToPtr(thisSecBuffer, pBuffers, False)
End Sub
Public Sub New(ByVal secBufferBytesArray As MultipleSecBufferHelper())
If secBufferBytesArray Is Nothing OrElse secBufferBytesArray.Length = 0 Then
Throw New ArgumentException("secBufferBytesArray cannot be null or 0 length")
End If
ulVersion = CInt(SecBufferType.SECBUFFER_VERSION)
cBuffers = secBufferBytesArray.Length
'Allocate memory for SecBuffer Array....
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(SecBuffer)) * cBuffers)
For index As Integer = 0 To secBufferBytesArray.Length - 1
'Super hack: Now allocate memory for the individual SecBuffers
'and just copy the bit values to the SecBuffer array!!!
Dim thisSecBuffer = New SecBuffer(secBufferBytesArray(index).Buffer, secBufferBytesArray(index).BufferType)
'We will write out bits in the following order:
'int cbBuffer;
'int BufferType;
'pvBuffer;
'Note that we won't be releasing the memory allocated by ThisSecBuffer until we
'are disposed...
Dim currentOffset As Integer = index * Marshal.SizeOf(GetType(SecBuffer))
Marshal.WriteInt32(pBuffers, currentOffset, thisSecBuffer.cbBuffer)
Marshal.WriteInt32(pBuffers, currentOffset + Marshal.SizeOf(thisSecBuffer.cbBuffer), thisSecBuffer.BufferType)
Marshal.WriteIntPtr(pBuffers, currentOffset + Marshal.SizeOf(thisSecBuffer.cbBuffer) + Marshal.SizeOf(thisSecBuffer.BufferType), thisSecBuffer.pvBuffer)
Next
End Sub
Public Sub Dispose()
If pBuffers <> IntPtr.Zero Then
If cBuffers = 1 Then
Dim thisSecBuffer = CType(Marshal.PtrToStructure(pBuffers, GetType(SecBuffer)), SecBuffer)
thisSecBuffer.Dispose()
Else
For index As Integer = 0 To cBuffers - 1
'The bits were written out the following order:
'int cbBuffer;
'int BufferType;
'pvBuffer;
'What we need to do here is to grab a hold of the pvBuffer allocate by the individual
'SecBuffer and release it...
Dim currentOffset As Integer = index * Marshal.SizeOf(GetType(SecBuffer))
Dim secBufferpvBuffer As IntPtr = Marshal.ReadIntPtr(pBuffers, currentOffset + Marshal.SizeOf(GetType(Integer)) + Marshal.SizeOf(GetType(Integer)))
Marshal.FreeHGlobal(secBufferpvBuffer)
Next
End If
Marshal.FreeHGlobal(pBuffers)
pBuffers = IntPtr.Zero
End If
End Sub
Public Function GetSecBufferByteArray() As Byte()
Dim buffer As Byte() = Nothing
If pBuffers = IntPtr.Zero Then
Throw New InvalidOperationException("Object has already been disposed!!!")
End If
If cBuffers = 1 Then
Dim thisSecBuffer = CType(Marshal.PtrToStructure(pBuffers, GetType(SecBuffer)), SecBuffer)
If thisSecBuffer.cbBuffer > 0 Then
buffer = New Byte(thisSecBuffer.cbBuffer - 1) {}
Marshal.Copy(thisSecBuffer.pvBuffer, buffer, 0, thisSecBuffer.cbBuffer)
End If
Else
Dim bytesToAllocate As Integer = 0
Dim Index As Integer
For Index = 0 To cBuffers - 1
'The bits were written out the following order:
'int cbBuffer;
'int BufferType;
'pvBuffer;
'What we need to do here calculate the total number of bytes we need to copy...
Dim currentOffset As Integer = Index * Marshal.SizeOf(GetType(SecBuffer))
bytesToAllocate += Marshal.ReadInt32(pBuffers, currentOffset)
Next
buffer = New Byte(bytesToAllocate - 1) {}
Index = 0
Dim BufferIndex As Integer = 0
While Index < cBuffers
'The bits were written out the following order:
'int cbBuffer;
'int BufferType;
'pvBuffer;
'Now iterate over the individual buffers and put them together into a
'byte array...
Dim currentOffset As Integer = Index * Marshal.SizeOf(GetType(SecBuffer))
Dim bytesToCopy As Integer = Marshal.ReadInt32(pBuffers, currentOffset)
Dim secBufferpvBuffer As IntPtr = Marshal.ReadIntPtr(pBuffers, currentOffset + Marshal.SizeOf(GetType(Integer)) + Marshal.SizeOf(GetType(Integer)))
Marshal.Copy(secBufferpvBuffer, buffer, BufferIndex, bytesToCopy)
BufferIndex += bytesToCopy
Index += 1
End While
End If
Return (buffer)
End Function
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure SECURITY_INTEGER
Public LowPart As UInteger
Public HighPart As Integer
Public Sub New(ByVal dummy As Integer)
LowPart = 0
HighPart = 0
End Sub
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure SECURITY_HANDLE
Public LowPart As UInteger
Public HighPart As UInteger
Public Sub New(ByVal dummy As Integer)
LowPart = 0
HighPart = 0
End Sub
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure SecPkgContext_Sizes
Public cbMaxToken As UInteger
Public cbMaxSignature As UInteger
Public cbBlockSize As UInteger
Public cbSecurityTrailer As UInteger
End Structure
#End Region
<Serializable()> _
Public Class SspiException
Inherits ApplicationException
Private ReadOnly _errorCode As Integer
Public Sub New(ByVal message As String, ByVal errorCode As Integer)
MyBase.New(String.Format("{0}. Error Code = '{1:X}'.", message, errorCode))
_errorCode = errorCode
End Sub
Public ReadOnly Property ErrorCode() As Integer
Get
Return _errorCode
End Get
End Property
End Class
<Serializable()> _
Public Class SoapException
Inherits SystemException
Public Shared ReadOnly ClientFaultCode As XmlQualifiedName
Public Shared ReadOnly DetailElementName As XmlQualifiedName
Public Shared ReadOnly MustUnderstandFaultCode As XmlQualifiedName
Public Shared ReadOnly ServerFaultCode As XmlQualifiedName
Public Shared ReadOnly VersionMismatchFaultCode As XmlQualifiedName
Public Sub New()
End Sub
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal innerException As Exception)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal subCode As SoapFaultSubCode)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal actor As String)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal actor As String, ByVal innerException As Exception)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal actor As String, ByVal detail As XmlNode)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal actor As String, ByVal detail As XmlNode, ByVal innerException As Exception)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal actor As String, ByVal role As String, ByVal detail As XmlNode, ByVal subCode As SoapFaultSubCode, _
ByVal innerException As Exception)
End Sub
Public Sub New(ByVal message As String, ByVal code As XmlQualifiedName, ByVal actor As String, ByVal role As String, ByVal lang As String, ByVal detail As XmlNode, _
ByVal subCode As SoapFaultSubCode, ByVal innerException As Exception)
End Sub
Public ReadOnly Property Actor() As String
Get
End Get
End Property
Public ReadOnly Property Code() As XmlQualifiedName
Get
End Get
End Property
Public ReadOnly Property Detail() As XmlNode
Get
End Get
End Property
<ComVisible(False)> _
Public ReadOnly Property Lang() As String
Get
End Get
End Property
<ComVisible(False)> _
Public ReadOnly Property Node() As String
Get
End Get
End Property
<ComVisible(False)> _
Public ReadOnly Property Role() As String
Get
End Get
End Property
<ComVisible(False)> _
Public ReadOnly Property SubCode() As SoapFaultSubCode
Get
End Get
End Property
Public Overrides Sub GetObjectData(info As SerializationInfo, context As StreamingContext)
End Sub
Public Shared Function IsClientFaultCode(ByVal code As XmlQualifiedName) As Boolean
End Function
Public Shared Function IsMustUnderstandFaultCode(ByVal code As XmlQualifiedName) As Boolean
End Function
Public Shared Function IsServerFaultCode(ByVal code As XmlQualifiedName) As Boolean
End Function
Public Shared Function IsVersionMismatchFaultCode(ByVal code As XmlQualifiedName) As Boolean
End Function
End Class
<Serializable()> _
Public Class SoapFaultSubCode
Public Sub New(ByVal code As XmlQualifiedName)
End Sub
Public Sub New(ByVal code As XmlQualifiedName, ByVal subCode As SoapFaultSubCode)
End Sub
Public ReadOnly Property Code() As XmlQualifiedName
Get
End Get
End Property
Public ReadOnly Property SubCode() As SoapFaultSubCode
Get
End Get
End Property
End Class
Public Class SSPIChallengeUnused
Inherits VimFault
Public Sub New()
End Sub
Public Property base64Token() As String
Get
Return m_base64Token
End Get
Set(ByVal value As String)
m_base64Token = value
End Set
End Property
Private m_base64Token As String
End Class[/code]
Public Function Login(ByVal Server As String, Optional username As String = Nothing, ByVal Optional password As String = Nothing) As Boolean
Try
If username Is Nothing And password Is Nothing Then
Dim SSPIClient As SspiClients = New SspiClients("", SspiPackageType.Negotiate)
Try
SessMgr = VirtualCenter.GetView(VirtualCenter.ServiceContent.SessionManager, Nothing) 'Create Session to attempt login
UserSess = SessMgr.LoginBySSPI(Convert.ToBase64String(SSPIClient.Token), "en")
Catch ex As VimException
Debug.WriteLine("Exception")
Dim MySSPIChallange As SSPIChallenge = ex.MethodFault
Try
SSPIClient.Initialize(Convert.FromBase64String(MySSPIChallange.Base64Token))
Try
UserSess = SessMgr.LoginBySSPI(Convert.ToBase64String(SSPIClient.Token), "en")
SessMgr = VirtualCenter.GetView(VirtualCenter.ServiceContent.SessionManager, Nothing) 'Refresh Session Information
Return True
Catch exab As VimException
'Debug.WriteLine("NTLM AUTH FAILED TRYING WITH CREDS") ' Not sure why this happens on other machines?
'Return LoadVirtualCenter(Server, GVSphereUsername, GVSpherePassword)
Catch exabc As Exception
Debug.WriteLine(exabc.Message)
Debug.WriteLine("exabc")
End Try
Return False
Catch e As Exception
MsgBox(e.Message)
Return False
End Try
End Try
Else
UserSess = VirtualCenter.Login(username, password)
SessMgr = VirtualCenter.GetView(VirtualCenter.ServiceContent.SessionManager, Nothing) 'Refresh Session Information
End If
Return True
Catch ex As Exception
MsgBox(ex.Message)
Return False
End Try
End Function
Hi,
The community you posted your question to deals with the SDK for the vSphere client. From what I understand your problem is specifically related to Power CLI and not to any specific Client or vSphere API so I would recommend that you post your question to the VMware PowerCLI community. In the mean time I'll ping the PowerCLI team to respond if possible to this thread too.
Thanks,
Tony
Hi,
It seems like you're using VMware.Vim library from PowerCLI in your VB.NET project which is not officially supported by VMware. VMware.Vim dll is supposed to be used internally by PowerCLI only. Having said that we'll still try to figure out what your issue is and to assist you in this.
First of all PowerCLI 6.5 is quite an old version. The latest version we have is PowerCLI 11.1 and you can find it here: VMware PowerCLI 11.1.0 - VMware {code} . It's built against vSphere 6.7, but it's also backwards compatible with vSphere 6.0 and 6.5.
Are you sure that after the migration SSPI is properly setup? What happens if you try to login using SSPI through the vSphere web client? Does that work as expected?
AtanasAtanasov, do you have any other ideas?
When vSphere was running on Windows it supported both NTLM and Kerberos authentication. I don't remember if 5.5 supported Windows installation or appliance only. On the other hand the vSphere appliance only supports Kerberos authentication. Thus with the transition to 6.5 it might be the case that NTLM is no longer supported by the server.
Looking at your code, it uses the SspiPackageType.Negotiate package which would try to negotiate the authentication type. In this case the server probably only supports Kerberos. If your Windows client only supports NTLM (e.g. it is not joined to a domain) it would fail. If it supports Kerberos, then the Kerberos authentication might fail itself.
For Kerberos to work, you need to specify the SPN of vCenter to the call to InitializeSecurityContext. You can try to specify SspiPackageType.Kerberos instead of Negotiate to force it and pass "host/vCenterHostName" to the targetName parameter of InitializeSecurityContext.
Also check that this SPN is registered with the domain: SetSpn -L vCenterHostName
In some environments users might need to register the SPN themselves (probably when the PSC is installed as a separate appliance).
Atanas,
Your right on the money. I am currently getting this when using powershell. I notice via Wireshark that it's doing TLS negotiation with 1.0 and the client closes this connection after a "Change Cipher Spec" packet is sent. The code was tested and verified working for over a year no changes on my end other than the 6.5 upgrade. My two PSC's do not SPN's assigned, is that required or is it just needed for the Vcenter machine?
Secure Sockets Layer
TLSv1 Record Layer: Handshake Protocol: Client Key Exchange
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 70
Handshake Protocol: Client Key Exchange
Handshake Type: Client Key Exchange (16)
Length: 66
EC Diffie-Hellman Client Params
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Content Type: Change Cipher Spec (20)
Version: TLS 1.0 (0x0301)
Length: 1
Change Cipher Spec Message
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 48
Handshake Protocol: Encrypted Handshake Message
response below sent then a Fin from my to the server is sent
Secure Sockets Layer
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
Content Type: Change Cipher Spec (20)
Version: TLS 1.0 (0x0301)
Length: 1
Change Cipher Spec Message
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 48
Handshake Protocol: Encrypted Handshake Message
PowerCLI C:\> Connect-VIServer -server vcenter.info.sys -Verbose
VERBOSE: Attempting to connect using SSPI
VERBOSE: Reversely resolved 'vcenter.info.sys' to 'vcenter.info.sys'
VERBOSE: SSPI Kerberos: Acquired credentials for user 'EISENHOWER\24556'
VERBOSE: SSPI Kerberos: InitializeSecurityContext failed for target 'host/vcenter.info.sys'. Error code: 0x80090342
VERBOSE: Connect using SSPI was unsuccessful
Connect-VIServer : 1/30/2019 9:56:53 AM Connect-VIServer Could not determine user name and/or password for server
vcenter.info.sys
At line:1 char:1
+ Connect-VIServer -server vcenter.info.sys -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Connect-VIServer], ViServerConnectionException
+ FullyQualifiedErrorId : ViCore_Login_CredentialNotFound,VMware.VimAutomation.ViCore.Cmdlets.Commands.ConnectVISe
rver
I am not sure about the SPN's. I think vCenter would tunnel the LoginBySSPI to the PSC, so this would probably require you to use the SPN of the PSC. PowerCLI uses the SPN of the vCenter (management) machine, so it requires that SPN to exist. So check if you have an SPN for the PSC or the vCenter and use the one that you have.
The error that you get - 0x80090342 - is a bit different though, I haven't seen it before and I don't think it is related to SPNs.
It is defined as:
# for hex 0x80090342 / decimal -2146892990 :
SEC_E_KDC_UNKNOWN_ETYPE winerror.h
# The encryption type requested is not supported by the KDC.
I am not sure what encryption is that but I doubt that this has anything to do with the SSL connection that is used for the communication with vCenter.
This https://support.microsoft.com/en-us/help/978055/fix-user-accounts-that-use-des-encryption-for-kerber... claims that in this case there are entries in the event log that give more info.
Others here - The encryption type requested is not supported by the KDC - Windows Server - Spiceworks - claim that restarting the KDC service resolved the issue.
It looks like something related to the Windows client OS where you run and the Windows server where KDC. Also I think this error is on the first call to InitializeSecurityContext - that is, vCenter has not been involved yet, only the Windows OS.
Also with some version of vCenter, the SSL (probably not related to Kerberos) protocol versions supported by the server dropped some of the earlier version. On some machines by default the .Net client might advertise version that does not match with the supported versions at the server. In that case you need to enabled some of those version in the ServicePointManager, e.g. in PowerShell:
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Ssl3 + `
[System.Net.SecurityProtocolType]::Tls12 + [System.Net.SecurityProtocolType]::Tls11 + [System.Net.SecurityProtocolType]::Tls;
Thus the client and server would be able to negotiate a suitable version.