Можете ли вы объяснить, почему DirectoryInfo.GetFiles создает это исключение IOException? - PullRequest
12 голосов
/ 24 февраля 2009

У меня есть клиент-серверное приложение WinForms, работающее в сети Novell, которое выдает следующую ошибку при подключении к одинокому Windows 2003 Server в сети:

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, вручную синхронизируя имя пользователя и пароль рабочей станции с локальным пользователем на сервере. Самое странное в этой ошибке - то, что пользователь может писать на сервер как до, так и после ошибки, и все это без явного входа в систему.

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

Ответы [ 5 ]

44 голосов
/ 27 февраля 2009

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

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

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.
}
2 голосов
/ 06 апреля 2011

Для разработчиков VB.Net (таких как я) вот версия VB.Net:

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
1 голос
/ 05 марта 2009

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

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

1 голос
/ 05 марта 2009

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

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

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

  • Используйте Process Monitor , чтобы регистрировать все вызовы API и видеть, откуда возникла ошибка.
  • Попробуй на чистой ВМ / Машине и попробуй воспроизвести там
  • Отключить антивирусный сканер
  • Обновление клиента novell
0 голосов
/ 27 февраля 2018

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

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

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

...