16

WinFormsクライアントサーバーアプリをNovellネットワークで実行しているため、ネットワーク上の唯一のWindows2003サーバーに接続すると次のエラーが発生します。

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)

顧客のネットワーク管理者は、ワークステーションのユーザー名とパスワードをサーバー上のローカルユーザーと手動で同期することにより、WindowsServer接続を管理します。エラーの奇妙な点は、ユーザーがエラーの前後の両方で、明示的にログオンしなくてもサーバーに書き込むことができることです。

エラーが発生する理由を説明し、解決策を提供できますか?

4

5 に答える 5

49

別のドメインの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.
}
于 2009-02-26T21:00:44.330 に答える
3

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
于 2011-04-06T07:49:24.833 に答える
1

問題を再現してみて、パケット モニターを使用してネットワーク トラフィックを確認し、失敗の状況と成功の状況の違いを確認する必要があると思います。

次に、Windows (P/Invokes) から生の API を使用して障害状況を再現するアプリケーションを作成し、どのパラメーターがエラーを発生させるかを見つけようとします。問題を解決できる場合は、コンポーネントに目的の機能を実行させる方法を見つけるだけです。

あなたが見ることができる他の方向(問題を安定して再現できるようになった後):

  • Process Monitorを使用してすべての API 呼び出しをログに記録し、エラーの原因を確認します。
  • クリーンな VM/マシンで試して、そこで再現してみてください
  • ウイルス スキャナーを無効にする
  • Novell クライアントを更新する
于 2009-03-05T08:58:27.393 に答える
1

IMHO、期限切れの認証トークン(またはそのようなもの)を更新することの何らかの副作用のようです。

私の場合、プロキシ (squid) 経由でインターネットにアクセスできる Active Directory ユーザーとして、(ランダムな間隔で) 資格情報の不足に関するエラーが発生するまで問題なくブラウジングしていますが、これはブラウザーでページを更新することによって解決されます。その後、次のエラーまですべてが正常に機能しています。

于 2009-03-05T09:19:52.677 に答える