2009-02-24 21 views
8

Tengo una aplicación Windows Forms cliente-servidor que se ejecuta en una red Novell que produce el siguiente error al conectar con el solitario de Windows 2003 Server en la red:¿Puede explicar por qué DirectoryInfo.GetFiles produce esta 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) 

administrador de red del cliente gestiona la conexión de Windows Server manualmente sincronizar el nombre de usuario y la contraseña de la estación de trabajo con un usuario local en el servidor. Lo extraño del error es que el usuario puede escribir en el servidor antes y después del error, todo sin iniciar sesión explícitamente.

¿Puede explicar por qué ocurre el error y ofrecer una solución?

+0

Puede que no haya confianza implícita entre Novell y el grupo de trabajo o el dominio de Windows. –

+0

¿Es esta "confianza implícita" algo que se puede configurar? – flipdoubt

+0

¿Se puede publicar el segmento de código que se conecta al servidor? – AviD

Respuesta

38

Tengo este mismo problema al intentar acceder al sistema de archivos de un servidor de Windows en un dominio diferente. El problema es que la cuenta de usuario con la que se ejecuta el programa no tiene acceso al servidor remoto. Windows hace un trabajo extra entre bastidores para que se vea perfecto cuando usa Windows Explorer porque adivina que sus credenciales remotas coincidirán con sus credenciales locales.

Si asigna una unidad localmente al servidor remoto, y luego usa la unidad localmente asignada en su código, no debería tener el problema. Si no se puede asignar una unidad, pero que puede codificar las credenciales a utilizar para el servidor remoto, a continuación, puede utilizar este código:

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(); 
     } 
    } 
} 

A continuación, se puede acceder al servidor remoto al hacer esto:

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

Tengo un método similar para suplantar a un usuario, pero parece funcionar solo cuando el usuario es un administrador local. ¿Encuentras que este es el caso? – flipdoubt

+0

¿Qué usuario necesita ser un administrador local? Es posible que su usuario remoto necesite ser un administrador para acceder al recurso compartido. – David

+0

Estoy diciendo que necesita tener algún tipo de permiso de "poder suplantar al usuario" en la máquina local, lo que la mayoría de los usuarios estándar no tienen. – flipdoubt

1

Creo que debería intentar reproducir el problema, y ​​usar un monitor de paquetes para ver el tráfico de la red y observar la diferencia entre la situación de falla y la situación de éxito.

Luego, escriba una aplicación que use las API sin formato de Windows (P/Invocaciones) para reproducir su situación de falla e intente encontrar los parámetros que causan el error. Si puede resolver el problema, solo tiene que averiguar cómo conseguir que los componentes hagan lo que desea.

Otras direcciones usted podría mirar a (después se puede reproducir de forma estable el problema):

  • Uso Process Monitor para registrar todas las llamadas a la API y ver donde entra en juego el error.
  • probarlo en un lugar limpio VM/máquina y tratar de reproducirlo no
  • Desactivar el antivirus
  • actualizar el cliente Novell
1

en mi humilde opinión, que parece ser algún tipo de efecto secundario de la refrescante un token de autenticación caducado (o algo así).

I mi caso, como usuario de Active Directory que tiene acceso a Internet a través de un proxy (calamar), estoy navegando sin problemas hasta que recibo (a intervalos aleatorios) un error sobre falta de credenciales, que se resuelve mediante una actualización de página en el navegador, todo funciona bien hasta el próximo error.

2

Para los desarrolladores de VB.Net (como yo) aquí está el VB.Versión neto:

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 

y utilizarlo como:

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