문제

네트워크의 Lone Windows 2003 서버에 연결할 때 다음 오류를 생성하는 Novell 네트워크에서 실행되는 WinForms 클라이언트 서버 앱이 있습니다.

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 서버 연결을 관리합니다. 오류에 대한 이상한 점은 사용자가 명시 적으로 로그온하지 않고 오류 전후에 서버에 쓸 수 있다는 것입니다.

오류가 발생하는 이유를 설명하고 해결책을 제공 할 수 있습니까?

도움이 되었습니까?

해결책

다른 도메인에서 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.
}

다른 팁

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

문제를 재현하고 패킷 모니터를 사용하여 네트워크 트래픽을보고 실패 상황과 성공 상황의 차이점을 살펴 보는 것보다 문제를 재현해야한다고 생각합니다.

그런 다음 Windows의 RAW API를 사용하는 응용 프로그램을 작성하여 실패 상황을 재현하고 오류가 발생하는 매개 변수를 찾으십시오. 문제를 해결할 수 있다면 구성 요소가 원하는 작업을 수행하는 방법을 찾는 문제 일뿐입니다.

볼 수있는 다른 방향 (문제를 안정적으로 재현 한 후) :

  • 사용 프로세스 모니터 모든 API 호출을 기록하고 오류의 출처를 확인하십시오.
  • 깨끗한 vm/machine에서 시도하고 거기에서 재현하십시오.
  • 바이러스 스캐너를 비활성화합니다
  • Novell 클라이언트를 업데이트하십시오

IMHO, 만료 된 인증 토큰 (또는 그와 비슷한)을 새로 고치는 것은 일종의 부작용 인 것 같습니다.

저의 사례는 프록시 (오징어)를 통해 인터넷에 액세스 할 수있는 Active Directory 사용자로서 (임의의 간격으로) 자격 증명 부족에 대한 오류가 발생할 때까지 브라우저의 페이지 새로 고침으로 해결됩니다. 그런 다음 다음 오류가 발생할 때까지 모든 것이 잘 작동합니다.

이 주소에는 마이크로 소프트 예제가 있습니다. https://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx

그러나 그 예에서 "Windows Vista와 나중에이 샘플은 관리자로 실행되어야합니다."

따라서이 솔루션은 코드를 실행하는 사용자가 대부분의 플랫폼에서 관리자 인 경우에만 좋습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top