2009-02-24 9 views
8

Ho un app WinForms client-server in esecuzione su una rete Novell che produce il seguente errore durante la connessione al solitario di Windows 2003 Server sulla rete:Puoi spiegare perché DirectoryInfo.GetFiles produce questa IOException?

TYPE: System.IO.IOException 
MSG: Logon failure: unknown user name or bad password. 

SOURCE: mscorlib 
SITE: WinIOError 

    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at System.IO.Directory.InternalGetFileDirectoryNames(String path, 
    String userPathOriginal, String searchPattern, Boolean includeFiles, 
    Boolean includeDirs, SearchOption searchOption) 
    at System.IO.DirectoryInfo.GetFiles(String searchPattern, 
    SearchOption searchOption) 
    at System.IO.DirectoryInfo.GetFiles(String searchPattern) 
    at Ceoimage.Basecamp.DocumentServers.ClientAccessServer.SendQueuedFiles(
    Int32 queueId, Int32 userId, IDocQueueFile[] queueFiles) 
    at Ceoimage.Basecamp.ScanDocuments.DataModule.CommitDocumentToQueue(
    QueuedDocumentModelWithCollections doc, IDocQueueFile[] files) 

amministratore di rete del cliente gestisce la connessione di Windows Server manualmente sincronizzazione del nome utente e della password della workstation con un utente locale sul server. La cosa strana dell'errore è che l'utente può scrivere sul server sia prima che dopo l'errore, il tutto senza accedere esplicitamente.

Puoi spiegare perché si verifica l'errore e offrire una soluzione?

+0

Potrebbe non esserci trust implicito tra Novell e il gruppo di lavoro o dominio Windows. –

+0

Questa "fiducia implicita" è qualcosa che può essere configurato? – flipdoubt

+0

Puoi pubblicare il segmento di codice che si collega al server? – AviD

risposta

38

Ho lo stesso problema quando si tenta di accedere al file system di un server Windows in un dominio diverso. Il problema è che l'account utente su cui è in esecuzione il programma non ha accesso al server remoto. Windows esegue un lavoro aggiuntivo dietro le quinte per renderlo senza problemi quando si utilizza Esplora risorse, perché suppone che le credenziali remote corrispondano alle credenziali locali.

Se si associa un'unità localmente al server remoto, quindi si utilizza l'unità mappata localmente nel codice, non si dovrebbe avere il problema. Se non è possibile tracciare un azionamento, ma è possibile difficile codificare le credenziali da utilizzare per il server remoto, quindi è possibile utilizzare questo codice:

using System; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 
using System.Security.Principal; 

namespace Company.Security 
{ 
    public class ImpersonateUser : IDisposable 
    { 
     [DllImport("advapi32.dll", SetLastError=true)] 
     private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); 

     [DllImport("kernel32", SetLastError = true)] 
     private static extern bool CloseHandle(IntPtr hObject); 

     private IntPtr userHandle = IntPtr.Zero; 
     private WindowsImpersonationContext impersonationContext; 

     public ImpersonateUser(string user, string domain, string password) 
     { 
      if (! string.IsNullOrEmpty(user)) 
      { 
       // Call LogonUser to get a token for the user 
       bool loggedOn = LogonUser(user, domain, password, 
        9 /*(int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS*/, 
        3 /*(int)LogonProvider.LOGON32_PROVIDER_WINNT50*/, 
        out userHandle); 
       if (!loggedOn) 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 

       // Begin impersonating the user 
       impersonationContext = WindowsIdentity.Impersonate(userHandle); 
      } 
     } 

     public void Dispose() 
     { 
      if (userHandle != IntPtr.Zero) 
       CloseHandle(userHandle); 
      if (impersonationContext != null) 
       impersonationContext.Undo(); 
     } 
    } 
} 

Poi si può accedere al server remoto in questo modo:

using (new ImpersonateUser("UserID", "Domain", "Password")) 
{ 
    // Any IO code within this block will be able to access the remote server. 
} 
+0

Ho un metodo simile per la rappresentazione di un utente, ma sembra funzionare solo quando l'utente è un amministratore locale. Lo trovi così? – flipdoubt

+0

Quale utente deve essere un amministratore locale? Per accedere alla condivisione, potrebbe essere necessario che l'utente remoto sia un amministratore. – David

+0

Sto dicendo che è necessario avere un qualche tipo di autorizzazione "può impersonare un utente" sulla macchina locale, che la maggior parte degli utenti standard non ha. – flipdoubt

1

Penso che dovresti provare a riprodurre il problema e poi utilizzare un monitor a pacchetto per vedere il traffico di rete e osservare la differenza tra la situazione di errore e la situazione di successo.

Quindi scrivere un'applicazione che utilizza le API raw da Windows (P/Invokes) per riprodurre la situazione di errore e cercare di individuare i parametri che causano l'errore. Se sei in grado di risolvere il problema piuttosto che cercare di ottenere i componenti per fare ciò che vuoi.

altre direzioni si poteva guardare (dopo è possibile riprodurre il problema in modo stabile):

  • Usa Process Monitor per registrare tutte le chiamate alle API e vedere dove l'errore proviene.
  • provarlo su un ambiente pulito VM/macchina e provare a riprodurre lì
  • disattivare il programma antivirus
  • Aggiornare il client Novell
1

IMHO, sembra essere una sorta di effetto collaterale di rinfrescante un token di autenticazione scaduto (o qualcosa di simile).

Il mio caso, come utente di Active Directory che ha accesso a Internet tramite un proxy (squid), sto navigando senza problemi finché non ottengo (a intervalli casuali) un errore sulla mancanza di credenziali, che viene risolto da un aggiornamento della pagina nel browser, quindi tutto funziona bene fino al prossimo errore.

2

Per gli sviluppatori VB.Net (come me), ecco il VB.Versione netto:

Imports System 
Imports System.ComponentModel 
Imports System.Runtime.InteropServices 
Imports System.Security.Principal 

Namespace Company.Security 
    Public Class ImpersonateUser 
     Implements IDisposable 

     <DllImport("advapi32.dll", SetLastError:=True)> _ 
     Private Shared Function LogonUser(ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, ByRef phToken As IntPtr) As Integer 
     End Function 

     <DllImport("kernel32", SetLastError:=True)> _ 
     Private Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean 
     End Function 

     Private userHandle As IntPtr = IntPtr.Zero 
     Private impersonationContext As WindowsImpersonationContext 

     Public Sub New(ByVal user As String, ByVal domain As String, ByVal password As String) 
      If Not String.IsNullOrEmpty(user) Then 
       Dim loggedOn As Integer = LogonUser(user, domain, password, 9, 3, userHandle) 
       If Not loggedOn = 1 Then 
        Throw New Win32Exception(Marshal.GetLastWin32Error()) 
       End If 
       impersonationContext = WindowsIdentity.Impersonate(userHandle) 
      End If 
     End Sub 

     Public Sub Dispose() Implements System.IDisposable.Dispose 
      If userHandle <> IntPtr.Zero Then 
       CloseHandle(userHandle) 
      End If 
      If impersonationContext IsNot Nothing Then 
       impersonationContext.Undo() 
      End If 
     End Sub 

    End Class 
End Namespace 

e usarlo come:

using New ImpersonateUser("UserID", "Domain", "Password") 
    ' ... your code here 
End Using 
Problemi correlati