Как преобразовать CirdHandle* в SafeHandle в C ++/CLI, чтобы устранить предупреждения CA2004 (и почему идентифицируемые C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Как преобразовать CirdHandle* в SafeHandle в C ++/CLI, чтобы устранить предупреждения CA2004 (и почему идентифицируемые

Сообщение Anonymous »

Я внедряю обертку C ++/CLI через Windows SSPI (интерфейс поставщика безопасности), управляя ручками учетных данных с использованием AccureCredentialShandle. Моя первоначальная реализация вручную выделяла Credshandle* и очистила ее через FreeCredentialShandle + Delete. Вот моя старая реализация:
старый код:

Код: Выделить всё

public __gc __abstract class Credential : public IDisposable
{
public:

// types
__value enum Package {Negotiate, Kerberos, NTLM};
__value enum CredentialType {Client, Server};

// constructor/destructor
Credential(Package package, CredentialType credentialType)
{
// we're not disposed yet
this->disposed = false;

// create a new credential handle
// note: we're allocating the CredHandle on the C++ heap.  This needs to be
// explicitly deleted upon Disposal
this->credentialHandle = __nogc new CredHandle;
this->credentialHandle->dwLower = 0; this->credentialHandle->dwUpper = 0;

// capture the package
this->securityPackage = package;

// determine package name for the call the AcquireCredentialsHandle
TCHAR *pszPackageName = NULL;
switch (package)
{
case Package::Negotiate:
pszPackageName = szNegotiatePackageName;
break;

case Package::Kerberos:
pszPackageName = szKerberosPackageName;
break;

case Package::NTLM:
pszPackageName = szNTLMPackageName;
break;
}

// determine credential use
ULONG fCredentialUse = 0;
switch (credentialType)
{
case CredentialType::Client:
fCredentialUse = SECPKG_CRED_OUTBOUND;
break;

case CredentialType::Server:
fCredentialUse = SECPKG_CRED_INBOUND;
break;
}

// acquire credentials handle
TimeStamp tsExpiry = { 0, 0 };

// suppressing Code Analysis warning, as we will not disturb this code going forward
#pragma warning(suppress: 6387)
SECURITY_STATUS sResult = AcquireCredentialsHandle(
NULL,                                           // [in] name of principal. NULL = principal of current security context
pszPackageName,                                 // [in] name of package
fCredentialUse,                                 // [in] flags indicating use.
NULL,                                           // [in] pointer to logon identifier.  NULL = we're not specifying the id of another logon session
NULL,                                           // [in] package-specific data.  NULL = default credentials for security package
NULL,                                           // [in] pointer to GetKey function.   NULL = we're not using a callback to retrieve the credentials
NULL,                                           // [in] value to pass to GetKey
this->credentialHandle,                         // [out] credential handle (this must be already allocated)
&tsExpiry                                       // [out] lifetime of the returned credentials
);

// check for errors
if (sResult != SEC_E_OK)
{
SSPIException *ex = new SSPIException(S"AcquireCredentialsHandle failed", sResult);
throw ex;
}
}

~Credential()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}

// Implement IDisposable*
// Do not make this method virtual.
// A derived class should not be able to call this method.
void Dispose()
{
Dispose(true);
// Take ourselves off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC::SuppressFinalize(this);
}

protected:

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects.  Only unmanaged resources can be disposed.
virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this->disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources

// (there are no managed resources here)
}

// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.

// clean up
SECURITY_STATUS sResult = FreeCredentialsHandle(
this->credentialHandle                          // [in] handle to free
);

// delete the memory allocated for the handle
delete this->credentialHandle;
this->credentialHandle = NULL;

// check for errors
if (sResult != SEC_E_OK)
{
// VA: In .NET 2.0 the unhandled exception causes the application to terminate.
//SSPIException *ex = new SSPIException(S"FreeCredentialsHandle failed", sResult);
//throw ex;
}
}
this->disposed = true;
}

public:

// properties
__property Package get_SecurityPackage()
{
if(this->disposed)
throw new ObjectDisposedException(this->GetType()->Name);

return this->securityPackage;
};

__property IntPtr get_CredentialHandle()
{
if(this->disposed)
throw new ObjectDisposedException(this->GetType()->Name);

return IntPtr(this->credentialHandle);
};

__property String *get_Name()
{
if(this->disposed)
throw new ObjectDisposedException(this->GetType()->Name);

String *name = NULL;

// get the name associated with this credential
SecPkgCredentials_Names secPkgCredentials_Names = { 0 };

try
{
SECURITY_STATUS sResult = QueryCredentialsAttributes(this->credentialHandle, SECPKG_CRED_ATTR_NAMES, &secPkgCredentials_Names);

// check for errors
if (sResult != SEC_E_OK)
{
SSPIException *ex = new SSPIException(S"QueryCredentialsAttributes failed", sResult);
throw ex;
}

// copy the name for the caller
name = secPkgCredentials_Names.sUserName;
}
__finally
{
// free the buffer
if (secPkgCredentials_Names.sUserName != NULL)
{
FreeContextBuffer(secPkgCredentials_Names.sUserName);
secPkgCredentials_Names.sUserName = NULL;
}
}

// return the name to the caller
return name;
};

private:

// member variables
CredHandle __nogc* credentialHandle;
Package securityPackage;
bool disposed;
};
новый код:
// SafeHandle for managing the CredHandle
ref class SafeCredHandle sealed : public SafeHandle
{
public:
SafeCredHandle()
: SafeHandle(IntPtr::Zero, true)
{
//handle = Marshal::AllocHGlobal(sizeof(::CredHandle));
//ZeroMemory((void*)handle, sizeof(::CredHandle));
}

SafeCredHandle(CredHandle* handle)
: SafeHandle(IntPtr::Zero, true)
{
if (handle != nullptr)
{
this->SetHandle(IntPtr(handle));
}
}

property ::CredHandle* NativeHandle
{
::CredHandle* get()
{
return reinterpret_cast(handle.ToPointer());
}
}

[SecurityCritical]
virtual property bool IsInvalid
{
bool get() override
{
return handle == IntPtr::Zero;
}
}

protected:
[SecurityCritical]
virtual bool ReleaseHandle() override
{
if (handle != IntPtr::Zero)
{
SECURITY_STATUS status = FreeCredentialsHandle(reinterpret_cast(handle.ToPointer()));
handle = IntPtr::Zero;
return (status == SEC_E_OK);
}
return true;
}
};

public ref class Credential
{
public:

// types
enum class Package { Negotiate, Kerberos, NTLM };
enum class CredentialType { Client, Server };

// constructor/destructor
Credential(Package package, CredentialType credentialType)
{
// we're not disposed yet
this->disposed = false;

// capture the package
this->securityPackage = package;

// determine package name for the call the AcquireCredentialsHandle
TCHAR* pszPackageName = nullptr;
switch (package)
{
case Package::Negotiate:
pszPackageName = szNegotiatePackageName;
break;

case Package::Kerberos:
pszPackageName = szKerberosPackageName;
break;

case Package::NTLM:
pszPackageName = szNTLMPackageName;
break;
}

// determine credential use
ULONG fCredentialUse = 0;
switch (credentialType)
{
case CredentialType::Client:
fCredentialUse = SECPKG_CRED_OUTBOUND;
break;

case CredentialType::Server:
fCredentialUse = SECPKG_CRED_INBOUND;
break;
}

CredHandle* rawHandle = new CredHandle();
// acquire credentials handle
TimeStamp tsExpiry = { 0, 0 };

// suppressing Code Analysis warning, as we will not disturb this code going forward
#pragma warning(suppress: 6387)
SECURITY_STATUS sResult = AcquireCredentialsHandle(
nullptr, // [in] name of principal. NULL = principal of current security context
pszPackageName, // [in] name of package
fCredentialUse, // [in] flags indicating use.
nullptr, // [in] pointer to logon identifier. NULL = we're not specifying the id of another logon session
nullptr, // [in] package-specific data. NULL = default credentials for security package
nullptr, // [in] pointer to GetKey function. NULL = we're not using a callback to retrieve the credentials
nullptr, // [in] value to pass to GetKey
rawHandle, // [out] credential handle (this must be already allocated)
&tsExpiry // [out] lifetime of the returned credentials
);

// check for errors
if (sResult != SEC_E_OK)
{
SSPIException^ ex = gcnew SSPIException("AcquireCredentialsHandle failed", sResult);
throw ex;
}

this->credentialHandle = gcnew SafeCredHandle(rawHandle);
}

//Destructor to free managed code
~Credential()
{
this->!Credential();
}

//Finalizer to free unmanaged code
!Credential()
{
if (!disposed)
{
if (credentialHandle != nullptr)
{
credentialHandle->Close();
credentialHandle = nullptr;
}

this->disposed = true;
}
}

public:

// properties
property Credential::Package SecurityPackage
{
Credential::Package get()
{
if (disposed || credentialHandle == nullptr || credentialHandle->IsInvalid)
throw gcnew ObjectDisposedException(this->GetType()->Name);

return securityPackage;
}
};

property IntPtr CredentialHandle
{
IntPtr get()
{
if (disposed || credentialHandle == nullptr || credentialHandle->IsInvalid)
throw gcnew ObjectDisposedException(this->GetType()->Name);

return IntPtr(credentialHandle->NativeHandle);
}
};

property String^ Name
{
String^ get()
{
if (disposed || credentialHandle == nullptr || credentialHandle->IsInvalid)
throw gcnew ObjectDisposedException(this->GetType()->Name);

String^ name = nullptr;

// get the name associated with this credential
SecPkgCredentials_Names secPkgCredentials_Names = { 0 };

try
{
SECURITY_STATUS sResult = QueryCredentialsAttributes(credentialHandle->NativeHandle, SECPKG_CRED_ATTR_NAMES, &secPkgCredentials_Names);

// check for errors
if (sResult != SEC_E_OK)
{
SSPIException^ ex = gcnew SSPIException("QueryCredentialsAttributes failed", sResult);
throw ex;
}

// copy the name for the caller
name = gcnew String(secPkgCredentials_Names.sUserName);
}
__finally
{
// free the buffer
if (secPkgCredentials_Names.sUserName != nullptr)
{
FreeContextBuffer(secPkgCredentials_Names.sUserName);
secPkgCredentials_Names.sUserName = nullptr;
}
}

// return the name to the caller
return name;
}
};

private:

// member variables
SafeCredHandle^ credentialHandle;
Credential::Package securityPackage;
bool disposed;
};

< /code>
предупреждения: < /strong> < /p>

-warning: CA2004: Microsoft.relability: 'safecredhandle.safecredhandle ()' содержит один или несколько вызовов Gc.sope ресурс). < /p>
< /blockquote>

-warning: ca2123: microsoft.security: добавьте следующий атрибут безопасности на 'safecredhandle.isinvalid.get ()', чтобы совпадать с Linkdemand на основе метода 'safe-andle.isinvalid.get ()', чтобы совпадать с Linkdemand на основе. 'SecurityCriticalAttribute'. ресурс). < /p>
< /blockquote>

-warning: ca2004: microsoft.relability: 'safecredhandle.nativehandle.get ()' содержит один или несколько призывов Gc.keepalive (объект), которые должны быть удалены (после конвертации в Safe-Handle, чтобы undan-andage kc.keepalive (объект). /> < /blockquote>

-warning: CA2004: Microsoft.Relability: 'credential.credential (credential.package, credential.credentialtype)' содержит один или несколько призывов Gc.keepalive (объект), которые должны быть удалены (после конвертации в Safe-haft while для инкаплекса undan-mansakealive). /> < /blockquote>

-warning: ca2004: microsoft.relability: 'credential.credentialHandle.get ()' содержит один или несколько вызовов в GC.keepalive (объект), которые должны быть удалены (после конвертации в Safehandle, чтобы инкалировать некверногенный ресурс). />
[местоположение, не хранящее в PDB]: Предупреждение: CA2004: Microsoft.Relability: 'credential.dispose ()' содержит один или несколько вызовов в GC.keepal /> -warning: CA2004: Microsoft.Relability: 'credential.name.get ()' содержит один или несколько вызовов Gc.keepalive (объект), которые следует удалить (после преобразования в SafeHandle для инкапсуляции неуправляемого ресурса). Microsoft.relability: 'credential.securitypackage.get ()' содержит один или несколько вызовов Gc.keepalive (объект), которые следует удалить (после конвертации в Safehandle, чтобы инкапсулировать неуправляемый ресурс).

проблемы после рефлексии:
​​
. Появляется:
, несмотря на переход на Safehandle, я все еще получаю те же предупреждения CA2004. Предупреждения предполагают, что вызовы Gc.keepalive должны быть удалены после конвертации в SafeHandle, но я не могу избавиться от них. Респунктор ~ Detrential () никогда не называется, даже когда я использую класс внутри блока или вручную Call Dispose (). Это приводит к тому, что неуправляемые ресурсы не очищаются правильно. Обновление? Как я могу правильно интегрировать его с моим классом? Любой пример кода или руководства будет очень оценен.


Подробнее здесь: https://stackoverflow.com/questions/795 ... 4-warnings
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»