Pergunta

Eu tenho um aplicativo WinForms cliente-servidor em execução em uma rede Novell, que produz o seguinte erro ao se conectar ao solitário Windows 2003 Server na rede:

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 rede do cliente gerencia a conexão Windows Server sincronizando manualmente o nome de usuário e senha estação de trabalho com um usuário local no servidor. A coisa estranha sobre o erro é que o usuário pode escrever para o servidor antes e após o erro, tudo sem efetuar explicitamente.

Você pode explicar por que ocorre o erro e oferecer uma solução?

Foi útil?

Solução

Eu tenho esse mesmo problema ao tentar acessar o sistema de um servidor de arquivos do Windows em um domínio diferente. O problema é que a conta de usuário que o programa está sendo executado não tem acesso ao servidor remoto. Windows faz trabalho extra nos bastidores para torná-la perfeita quando você usa Windows Explorer, porque supõe que suas credenciais remotos irá corresponder a suas credenciais locais.

Se você mapear uma unidade local para o servidor remoto, em seguida, utilizar a unidade mapeada localmente no seu código, você não deve ter o problema. Se você não pode mapear uma unidade, mas você pode codificar as credenciais a utilizar para o servidor remoto, então você pode usar 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();
        }
    }
}

Em seguida, você pode acessar o servidor remoto, fazendo isso:

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

Outras dicas

Para os fomentador de VB.Net (como eu) Aqui está a versão 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

E usá-lo como:

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

Eu acho que você deve tentar reproduzir o problema, e que o uso de um monitor de pacotes para ver o tráfego de rede e olhar para a diferença entre a situação de falha ea situação sucesso.

Em seguida, escrever uma aplicação que utiliza a API crua do das janelas (P / Invoca) para reproduzir a sua situação de falha e tentar encontrar os parâmetros que causa o erro ocorra. Se o seu capaz de resolver o problema do que é apenas a questão de encontrar como obter os componentes para fazer a coisa que você quer.

Outros direções que você poderia olhar (depois você pode reproduzir de forma estável o problema):

  • Process Monitor para registrar todas as chamadas de API e ver onde o erro vem.
  • Experimente-o em um ambiente limpo VM / máquina e tentar reproduzi-lo lá
  • Desativar o antivírus
  • Atualização do Novell Client

IMHO, parece ser algum tipo de efeito colateral de refrescar um token de autenticação expirou (ou algo parecido).

I meu caso, como um usuário do Active Directory ter acesso à Internet através de um proxy (squid), estou navegando sem problemas até eu chegar (em intervalos aleatórios) um erro sobre a falta de credenciais, que é resolvido por uma atualização de página em o navegador, então tudo está funcionando bem até o próximo erro.

Há um exemplo Microsoft disponível neste endereço: https://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext (v = vs.110) .aspx

Mas isso não dizem no seu exemplo: "No Windows Vista e mais tarde este exemplo deve ser executado como um administrador"

Portanto, esta solução é boa somente se o usuário executar o código é admin na maioria das plataformas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top