2009-05-26 10 views
0

Nachdem ich eine Woche lang damit zu kämpfen hatte, bin ich nicht wirklich darauf gekommen, warum es ständig in meinem Code versagt, aber nicht in anderen Beispielen. Mein Code, der während der Kompilierung nicht an einem Benutzer angemeldet wird, von dem ich weiß, dass er die richtigen Anmeldeinformationen hat. Wo es nicht die folgende Zeile:Fehler mit LogonUser in MC++

wi = gcnew WindowsIdentity(token); 

Es schlägt fehl, weil hier die Token Null ist, was bedeutet, dass es nie zu einem Benutzertoken gesetzt wurde. Hier ist meine vollständige Code:

#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 

nun mit diesen leicht modifizierten Beispiel von Microsoft konnte ich einen Benutzernamen und ein Token bekommen:

#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 

Warum sollte Microsoft den Code erfolgreich zu sein, wo mein fehlschlägt?

Antwort

1

"Warum sollte Microsofts Code erfolgreich sein, wo meiner scheitert?"

Da Ihr Code tut etwas anderes :-)

In dieser Zeile:

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

zur Kenntnis, dass 'tokenHandle' als Referenz übergeben wird, aber in Ihrer Version:

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

Sie sind nicht übergeben 'Token' als Referenz, so dass Ihre lokale Referenz nicht aktualisiert wird, weshalb es immer noch Null ist, wenn Sie es an th weitergeben e WindowsIdentität.

+0

Das habe ich auch vorher gedacht, weshalb es in meinem jetzigen Code so ist, aber das scheitert leider auch. Ich habe den obigen Code so geändert, dass er diese Änderung widerspiegelt. –

+0

Ich sehe nicht, wie Ihr bearbeiteter Code auch funktionieren würde - Sie übergeben tokenHandle jetzt mit ref, aber Sie verwenden es nirgendwo anders! –

0

Ich denke, dass die Antwort in MSDN-Artikel ist die Logonuser Funktion beschreiben:


Die LOGON32_LOGON_NETWORK Anmeldetyp ist am schnellsten, aber es hat die folgenden Einschränkungen:

Die Funktion gibt einen Identitätstoken zurückgibt, kein primäres Token. Sie können dieses Token nicht direkt in der CreateProcessAsUser-Funktion verwenden. Sie können jedoch die DuplicateTokenEx-Funktion aufrufen, um das Token in ein primäres Token zu konvertieren und es dann in CreateProcessAsUser zu verwenden.


Verwandte Themen