3

C# .NET 3.5 を使用するように書き換えている古い Win32 C++ DCOM サーバーがあります。クライアント アプリケーションは、リモートの Windows XP マシン上にあり、C++ で記述されています。これらのクライアントは変更しないでおく必要があるため、新しい .NET オブジェクトにインターフェイスを実装する必要があります。

これは完了しており、インターフェイスの実装に関しては正常に機能しており、古いクライアントから新しい .NET オブジェクトへのすべての呼び出しが正しく行われています。

しかし、DCOM クライアントから呼び出し元のユーザーの ID を取得するのに問題があります。DCOM 呼び出しを扇動したユーザーを特定するために、サーバー上に次のコードがあります...

[DllImport("ole32.dll")]
static extern int CoImpersonateClient();

[DllImport("ole32.dll")]
static extern int CoRevertToSelf();

private string CallingUser
{
    get
    {
        string sCallingUser = null;

        if (CoImpersonateClient() == 0)
        {
            WindowsPrincipal wp = System.Threading.Thread.CurrentPrincipal as WindowsPrincipal;

            if (wp != null)
            {
                WindowsIdentity wi = wp.Identity as WindowsIdentity;

                if (wi != null && !string.IsNullOrEmpty(wi.Name))
                    sCallingUser = wi.Name;
            }

            if (CoRevertToSelf() != 0)
                ReportWin32Error("CoRevertToSelf");
        }
        else
            ReportWin32Error("CoImpersonateClient");

        return sCallingUser;
    }
}

private static void ReportWin32Error(string sFailingCall)
{
    Win32Exception ex = new Win32Exception();
    Logger.Write("Call to " + sFailingCall + " FAILED: " + ex.Message);
}

プロパティを取得するとCallingUser、最初の数回は正しい値が返され、正しいユーザー名が識別されますが、3 人または 4 人の異なるユーザーが正常に呼び出しを行うと (状況はさまざまであるため、より具体的には言えません)、他のユーザーは、以前に電話をかけたユーザーとして識別されているようです。

私が気付いたのは、最初の数人のユーザーが独自のスレッドで処理される DCOM 呼び出し (つまり、特定のクライアントからのすべての呼び出しが単一の一意のスレッドによって処理される) であり、その後、後続のユーザーが同じスレッドによって処理されることです。の呼び出し後、CoImpersonateClient()そのCurrentPrincipalスレッドの最初のユーザーと一致します。

説明する:

ユーザー Tom は、スレッド 1 によって処理される DCOM 呼び出しを行います ( CurrentPrincipalTom を正しく識別します) 。

ユーザー Dick は、スレッド 2 によって処理される DCOM 呼び出しを行います ( CurrentPrincipalDick を正しく識別します) 。

ユーザー Harry は、スレッド 3 によって処理される DCOM 呼び出しを行います ( CurrentPrincipalHarry を正しく識別します) 。

ユーザー Bob は、スレッド 3 によって処理される DCOM 呼び出しを行います (CurrentPrincipal誤って彼を Harry と識別します)。

この図でわかるように、クライアント Harry と Bob からの呼び出しはスレッド 3 で処理され、サーバーは呼び出し元のクライアントを Harry として識別しています。

私が間違っていることはありますか?このように偽装を使用する際の注意事項や制限はありますか? 私がやろうとしていることを確実に達成できる、より良い方法または別の方法はありますか?

すべての助けをいただければ幸いです。

4

1 に答える 1

1

OK、それで私は別のアプローチを取り、最後にうまくいくと思われる方法を考え出しました(8人の異なるリモートユーザーに対してテストされました)。

私はClientBlanketsを支持して偽装ルートを捨てました...

[DllImport("ole32.dll")]
static extern int CoQueryClientBlanket(out IntPtr pAuthnSvc, out IntPtr pAuthzSvc,
    [MarshalAs(UnmanagedType.LPWStr)] out StringBuilder pServerPrincName, out IntPtr
    pAuthnLevel, out IntPtr pImpLevel, out IntPtr pPrivs, out IntPtr pCapabilities);

public static string CallingUser
{
    get
    {
        IntPtr pAthnSvc = new IntPtr();
        IntPtr pAthzSvc = new IntPtr();
        StringBuilder pServerPrincName = new StringBuilder();
        IntPtr pAuthnLevel = new IntPtr();
        IntPtr pImpLevel = new IntPtr();
        IntPtr pPrivs = new IntPtr();
        IntPtr pCaps = new IntPtr(4);
        string sCallingUser = string.Empty;

        try
        {
            CoQueryClientBlanket(out pAthnSvc,
                out pAthzSvc,
                out pServerPrincName,
                out pAuthnLevel,
                out pImpLevel,
                out pPrivs,
                out pCaps);
        }
        catch (Exception ex)
        {
            Logger.Write(ex.Message);
        }
        finally
        {
            sCallingUser = System.Runtime.InteropServices.Marshal.PtrToStringAuto(pPrivs);
        }

        return sCallingUser;
    }
}

CoCreateClientBlanket を使用すると、望ましい結果が得られるようで、メッセージの処理に使用されるスレッドに関係なく、呼び出し元のユーザーの ID を毎回確実に取得できます。

于 2010-04-22T09:05:09.903 に答える