2009-05-26 6 views
0

Après avoir lutté avec cela pendant une semaine, je n'ai pas vraiment compris pourquoi il échoue constamment dans mon code, mais pas dans d'autres exemples. Mon code, qui lors de la compilation, ne se connectera pas à un utilisateur dont je connais les informations de connexion correctes. Lorsqu'il échoue est la ligne suivante:Échec avec LogonUser dans MC++

wi = gcnew WindowsIdentity(token); 

Il échoue ici parce que le jeton est égal à zéro, ce qui signifie qu'il n'a jamais été mis à un jeton d'utilisateur. Voici mon code complet:

#ifndef UNCAPI_H 
#define UNCAPI_H 

#include <windows.h> 

#pragma once 
using namespace System; 
using namespace System::Runtime::InteropServices; 
using namespace System::Security::Principal; 
using namespace System::Security::Permissions; 

namespace UNCAPI 
{ 
public ref class UNCAccess 
{ 
public: 
    //bool Logon(String ^_srUsername, String ^_srDomain, String ^_srPassword); 
    [PermissionSetAttribute(SecurityAction::Demand, Name = "FullTrust")] 
    bool Logon(String ^_srUsername, String ^_srDomain, String ^_srPassword) 
    { 
     bool bSuccess = false; 
     token = IntPtr(0); 
     bSuccess = LogonUser(_srUsername, _srDomain, _srPassword, 8, 0, &tokenHandle); 

     if(bSuccess) 
     { 
      wi = gcnew WindowsIdentity(token); 
      wic = wi->Impersonate();     
     } 

     return bSuccess; 
    } 

    void UNCAccess::Logoff() 
    { 
     if (wic != nullptr) 
     { 
      wic->Undo(); 
     } 

     CloseHandle((int*)token.ToPointer());   
    } 
private: 
    [DllImport("advapi32.dll", SetLastError=true)]//[DllImport("advapi32.DLL", EntryPoint="LogonUserW", SetLastError=true, CharSet=CharSet::Unicode, ExactSpelling=true, CallingConvention=CallingConvention::StdCall)] 
    bool static LogonUser(String ^lpszUsername, String ^lpszDomain, String ^lpszPassword, int dwLogonType, int dwLogonProvider, IntPtr *phToken); 

    [DllImport("KERNEL32.DLL", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet::Unicode, ExactSpelling=true, CallingConvention=CallingConvention::StdCall)] 
    bool static CloseHandle(int *handle); 
    IntPtr token; 
    WindowsIdentity ^wi; 
    WindowsImpersonationContext ^wic; 
};// End of Class UNCAccess 
}// End of Name Space 

#endif UNCAPI_H 

Maintenant, en utilisant cet exemple légèrement modifié de Microsoft, je suis en mesure d'obtenir un login et un jeton:

#using <mscorlib.dll> 
#using <System.dll> 
using namespace System; 
using namespace System::Runtime::InteropServices; 
using namespace System::Security::Principal; 
using namespace System::Security::Permissions; 

[assembly:SecurityPermissionAttribute(SecurityAction::RequestMinimum, UnmanagedCode=true)] 
[assembly:PermissionSetAttribute(SecurityAction::RequestMinimum, Name = "FullTrust")]; 


[DllImport("advapi32.dll", SetLastError=true)] 
bool LogonUser(String^ lpszUsername, String^ lpszDomain, String^ lpszPassword, int dwLogonType, int dwLogonProvider, IntPtr* phToken); 

[DllImport("kernel32.dll", CharSet=System::Runtime::InteropServices::CharSet::Auto)] 
int FormatMessage(int dwFlags, IntPtr* lpSource, int dwMessageId, int dwLanguageId, String^ lpBuffer, int nSize, IntPtr *Arguments); 

[DllImport("kernel32.dll", CharSet=CharSet::Auto)] 
bool CloseHandle(IntPtr handle); 

[DllImport("advapi32.dll", CharSet=CharSet::Auto, SetLastError=true)] 
bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, IntPtr* DuplicateTokenHandle); 


// GetErrorMessage formats and returns an error message 
// corresponding to the input errorCode. 
String^ GetErrorMessage(int errorCode) 
{ 
    int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; 
    int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; 
    int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; 

    //int errorCode = 0x5; //ERROR_ACCESS_DENIED 
    //throw new System.ComponentModel.Win32Exception(errorCode); 

    int messageSize = 255; 
    String^ lpMsgBuf = ""; 
    int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; 

    IntPtr ptrlpSource = IntPtr::Zero; 
    IntPtr prtArguments = IntPtr::Zero; 

    int retVal = FormatMessage(dwFlags, &ptrlpSource, errorCode, 0, lpMsgBuf, messageSize, &prtArguments); 
    if (0 == retVal) 
    { 
     throw gcnew Exception(String::Format("Failed to format message for error code {0}. ", errorCode)); 
    } 

    return lpMsgBuf; 
} 

// Test harness. 
// If you incorporate this code into a DLL, be sure to demand FullTrust. 
[PermissionSetAttribute(SecurityAction::Demand, Name = "FullTrust")] 
int main() 
{  
    IntPtr tokenHandle = IntPtr(0); 
    IntPtr dupeTokenHandle = IntPtr(0); 
    try 
    { 
     String^ userName; 
     String^ domainName; 

     // Get the user token for the specified user, domain, and password using the 
     // unmanaged LogonUser method. 
     // The local machine name can be used for the domain name to impersonate a user on this machine. 
     Console::Write("Enter the name of the domain on which to log on: "); 
     domainName = Console::ReadLine(); 

     Console::Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName); 
     userName = Console::ReadLine(); 

     Console::Write("Enter the password for {0}: ", userName); 

     const int LOGON32_PROVIDER_DEFAULT = 0; 
     //This parameter causes LogonUser to create a primary token. 
     const int LOGON32_LOGON_INTERACTIVE = 2; 
     const int SecurityImpersonation = 2; 

     tokenHandle = IntPtr::Zero; 
     dupeTokenHandle = IntPtr::Zero; 

     // Call LogonUser to obtain a handle to an access token. 
     bool returnValue = LogonUser(userName, domainName, Console::ReadLine(), 
     LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, 
     &tokenHandle); 

     Console::WriteLine("LogonUser called."); 

     if (false == returnValue) 
     { 
      int ret = Marshal::GetLastWin32Error(); 
      Console::WriteLine("LogonUser failed with error code : {0}", ret); 
      Console::WriteLine("\nError: [{0}] {1}\n", ret, GetErrorMessage(ret)); 
      int errorCode = 0x5; //ERROR_ACCESS_DENIED 
      throw gcnew System::ComponentModel::Win32Exception(errorCode); 
     } 

     Console::WriteLine("Did LogonUser Succeed? {0}", (returnValue?"Yes":"No")); 
     Console::WriteLine("Value of Windows NT token: {0}", tokenHandle); 

     // Check the identity. 
     Console::WriteLine("Before impersonation: {0}", WindowsIdentity::GetCurrent()->Name); 

     bool retVal = DuplicateToken(tokenHandle, SecurityImpersonation, &dupeTokenHandle); 
     if (false == retVal) 
     { 
      CloseHandle(tokenHandle); 
      Console::WriteLine("Exception thrown in trying to duplicate token.");   
      return -1; 
     } 

     // The token that is passed to the following constructor must 
     // be a primary token in order to use it for impersonation. 
     WindowsIdentity^ newId = gcnew WindowsIdentity(dupeTokenHandle); 
     WindowsImpersonationContext^ impersonatedUser = newId->Impersonate(); 

     // Check the identity. 
     Console::WriteLine("After impersonation: {0}", WindowsIdentity::GetCurrent()->Name); 

     // Stop impersonating the user. 
     impersonatedUser->Undo(); 

     // Check the identity. 
     Console::WriteLine("After Undo: {0}", WindowsIdentity::GetCurrent()->Name); 

     // Free the tokens. 
     if (tokenHandle != IntPtr::Zero) 
      CloseHandle(tokenHandle); 
     if (dupeTokenHandle != IntPtr::Zero) 
      CloseHandle(dupeTokenHandle); 
    } 
    catch(Exception^ ex) 
    { 
     Console::WriteLine("Exception occurred. {0}", ex->Message); 
    } 

Console::ReadLine(); 
}// end of function 

Pourquoi le code de Microsoft réussir, où le mien échoue?

Répondre

1

"Pourquoi le code de Microsoft devrait-il réussir, là où le mien échoue?"

Parce que votre code fait autre chose :-)

Dans cette ligne:

bool returnValue = LogonUser(userName, domainName, Console::ReadLine(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, 
    &tokenHandle); 

Notez que 'tokenHandle' est passée par référence, mais dans votre version:

bSuccess = LogonUser(_srUsername, _srDomain, _srPassword, 8, 0, (IntPtr*)token.ToPointer()); 

vous avez et non en passant 'token' par référence, donc votre référence locale ne sera pas mise à jour, ce qui explique pourquoi il est encore zéro lorsque vous le transmettez à e WindowsIdentity.

+0

C'est ce que j'avais pensé avant aussi, ce qui explique pourquoi c'est ainsi dans mon code actuel, mais malheureusement, cela échoue également. J'ai changé le code ci-dessus afin qu'il reflète ce changement. –

+0

Je ne vois pas comment votre code édité fonctionnerait non plus - vous passez maintenant tokenHandle par ref, mais vous ne l'utilisez pas ailleurs! –

0

Je pense que la réponse est dans l'article MSDN décrivant la fonction LogonUser:


Le type de connexion LOGON32_LOGON_NETWORK est le plus rapide, mais il a les limites suivantes:

La fonction retourne un jeton d'emprunt d'identité, pas un jeton principal. Vous ne pouvez pas utiliser ce jeton directement dans la fonction CreateProcessAsUser. Toutefois, vous pouvez appeler la fonction DuplicateTokenEx pour convertir le jeton en jeton principal, puis l'utiliser dans CreateProcessAsUser.