2009-02-24 5 views
8

У меня есть приложение WinForms клиент-сервер, работающий в сети Novell, которая производит следующее сообщение об ошибке при подключении к одинокому Windows 2003 Server в сети:Можете ли вы объяснить, почему DirectoryInfo.GetFiles создает это 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) 

сеть администрировать клиента управляет соединение Windows Server с помощью вручную синхронизация имени пользователя и пароля рабочей станции с локальным пользователем на сервере. Нечетная вещь об ошибке заключается в том, что пользователь может писать на сервер как до, так и после ошибки, без явного входа в систему.

Можете ли вы объяснить причину возникновения ошибки и предложить решение?

+0

Между Novell и рабочей группой или доменом Windows не может быть скрытого доверия. –

+0

Является ли это «неявным доверием» что-то, что можно настроить? – flipdoubt

+0

Можете ли вы разместить сегмент кода, который подключается к серверу? – AviD

ответ

38

У меня такая же проблема при попытке доступа к файловой системе сервера Windows в другом домене. Проблема в том, что учетная запись пользователя, в которой работает программа, не имеет доступа к удаленному серверу. Windows делает дополнительную работу за кулисами, чтобы она выглядела бесшовной при использовании проводника Windows, поскольку она предполагает, что ваши удаленные учетные данные будут соответствовать вашим локальным учетным данным.

Если вы сопоставляете диск локально с удаленным сервером, а затем используйте локально подключенный диск в своем коде, у вас не должно быть проблем. Если вы не можете отобразить диск, но вы можете жестко кодировать учетные данные, используемые для удаленного сервера, то вы можете использовать этот код:

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

Затем вы можете получить доступ к удаленному серверу, делая это:

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

У меня есть аналогичный метод для олицетворения пользователя, но он работает только тогда, когда пользователь является локальным администратором. Вы находите, что это так? – flipdoubt

+0

Какой пользователь должен быть локальным администратором? Для доступа к ресурсу вашему удаленному пользователю может понадобиться администратор. – David

+0

Я говорю, что вам нужно иметь какое-то разрешение «может выдавать себя за пользователя» на локальном компьютере, которого нет у большинства стандартных пользователей. – flipdoubt

1

Я думаю, вы должны попытаться воспроизвести проблему, а не использовать пакетный монитор для просмотра сетевого трафика и посмотреть на разницу между ситуацией сбоя и ситуацией с успехом.

Затем напишите приложение, которое использует необработанные api из окон (P/Invokes), чтобы воспроизвести вашу ситуацию сбоя и попытаться найти, какие параметры вызывают ошибку. Если вы в состоянии решить проблему, а не просто найти, как заставить компоненты делать то, что вы хотите.

Другие направления вы можете посмотреть на (после того, как вы можете стабильно воспроизвести проблему):

  • Использование Process Monitor для регистрации всех вызовов API, и увидеть, где ошибка приходит.
  • Попробуйте его на чистую VM/Machine и попытаться воспроизвести его там
  • Отключением антивирусного сканера
  • Update новеллы клиент
1

ИМХИ, это, кажется, какое-то побочный эффект освежения токен аутентификации с истекшим сроком действия (или что-то в этом роде).

Я, в качестве пользователя Active Directory, имеющего доступ в Интернет через прокси (squid), просматриваю без проблем, пока не получаю (в случайных промежутках) ошибку об отсутствии учетных данных, которая решается обновлением страницы в браузере, тогда все работает нормально до следующей ошибки.

2

Для разработчиков VB.Net (например, я) здесь используется VB.Чистая версия:

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 

И использовать это нравится:

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

Существует пример Microsoft доступен по этому адресу: https://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx

Но это сказать, в своем примере: «В Windows Vista и позже этот образец должен быть запущен как администратор ».

Так что это решение хорошо, только если пользователь, запускающий код, является администратором на большинстве платформ.

 Смежные вопросы

  • Нет связанных вопросов^_^