Générer un processus qui s’exécute dans le contexte de l’utilisateur emprunté dans Microsoft ASP.NET

Cet article explique comment générer un processus qui s’exécute dans le contexte de l’utilisateur dont l’identité est empruntée.

              Version d’origine du produit : ASP.NET
Numéro de la base de connaissances d’origine : 889251

Introduction

Cet article pas à pas explique comment générer un processus qui s’exécute dans le contexte de l’utilisateur emprunté dans ASP.NET pages. Pour générer un processus qui s’exécute dans le contexte de l’utilisateur emprunté, vous ne pouvez pas utiliser la System.Diagnostics.Process.Start méthode . En effet, dans ASP.NET, l’emprunt d’identité est effectué au niveau du thread et non au niveau du processus. Par conséquent, tout processus que vous générez à partir de ASP.NET s’exécute dans le contexte du processus de travail ASP.NET et non dans le contexte emprunté.

Description de la technique

Pour contourner ce problème, vous devez effectuer des appels d’appel de plateforme (P/Invoke) aux API Win32 suivantes :

  • La CreateProcessAsUser fonction crée un processus sous l’identité du jeton de sécurité spécifié dans l’un des paramètres. Toutefois, l’appel à la CreateProcessAsUser fonction nécessite un jeton principal. Par conséquent, vous devez convertir le jeton emprunté en jeton principal.

  • La DuplicateTokenEx fonction convertit un jeton emprunté en jeton principal. L’appel à la CreateProcessAsUser fonction utilise ce jeton principal.

Remarque

Pour que l’appel à la CreateProcessAsUser fonction fonctionne, les droits d’utilisateur de sécurité suivants doivent être attribués à l’utilisateur qui a emprunté l’identité :

  • Sur un ordinateur exécutant Windows, attribuez le droit d’utilisateur Remplacer un jeton de niveau processus et le droit d’utilisateur Augmenter les quotas à l’utilisateur qui a emprunté l’identité.
  • Sur un ordinateur exécutant Windows Server ou Windows XP, attribuez le droit d’utilisateur Remplacer un jeton de niveau processus à l’utilisateur qui a emprunté l’identité.

Étapes de génération d’un processus

Microsoft fournit des exemples de programmation à titre d’illustration uniquement, sans garantie expresse ou implicite. Cela inclut, sans y être limité, les garanties implicites de commercialisation et d’adaptation à un but en particulier. Cet article considère que vous connaissez le langage de programmation présenté et les outils utilisés pour créer et déboguer des procédures. Les techniciens du Support technique Microsoft peuvent vous expliquer les fonctionnalités d’une procédure particulière, mais ils ne peuvent pas modifier les exemples en vue de vous fournir des fonctionnalités supplémentaires ou de créer des procédures répondant à vos besoins spécifiques. Pour générer un processus qui s’exécute dans le contexte de l’utilisateur emprunté, procédez comme suit :

  1. Dans Visual Studio .NET, créez une application web Visual C# ASP.NET, puis nommez l’application Q889251.

  2. Ouvrez le fichier WebForm1.aspx en mode code.

  3. Dans le fichier WebForm1.aspx , ajoutez les instructions suivantes au bloc de code using.

    using System.Runtime.InteropServices;
    using System.Security.Principal;
    
  4. Recherchez la ligne de code qui ressemble à la ligne de code suivante.

    public class WebForm1 : System.Web.UI.Page
    
  5. Après la ligne de code identifiée à l’étape 4, ajoutez le code suivant.

    [StructLayout(LayoutKind.Sequential)]
    public struct STARTUPINFO
    {
        public int cb;
        public String lpReserved;
        public String lpDesktop;
        public String lpTitle;
        public uint dwX;
        public uint dwY;
        public uint dwXSize;
        public uint dwYSize;
        public uint dwXCountChars;
        public uint dwYCountChars;
        public uint dwFillAttribute;
        public uint dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public uint dwProcessId;
        public uint dwThreadId;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int Length;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }
    [DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
    public extern static bool CloseHandle(IntPtr handle);
    [DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
    public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
    [DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
    public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
    
  6. Dans Explorateur de solutions, cliquez avec le bouton droit sur WebForm1.aspx, puis cliquez sur Ouvrir. Le formulaire Web s’ouvre en mode Création.

  7. Dans le menu Affichage , cliquez sur Source HTML.

  8. Remplacez tout le code existant dans la fenêtre Source HTML par le code suivant.

    <%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="Q889251.WebForm1" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
    <HTML>
       <HEAD>
          <title>WebForm1</title>
          <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
          <meta name="CODE_LANGUAGE" Content="C#">
          <meta name="vs_defaultClientScript" content="JavaScript">
          <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
       </HEAD>
       <body>
          <form id="Form1" method="post" runat="server">
             <P>&nbsp;</P>
             <P>
                Enter Path of process to be run (with relevant parameters)
                <asp:TextBox id="TextBox1" runat="server"></asp:TextBox>
             </P>
             <P>
                <asp:Button id="Button1" runat="server" Text="CreateProcess"></asp:Button>
             </P>
             <P>
                <asp:Label id="Label1" runat="server">Status:</asp:Label>
             </P>
             <P>
                <asp:Label id="Label2" runat="server">Impersonated Identity:</asp:Label>
             </P>
          </form>
       </body>
    </HTML>
    
  9. Dans le menu Affichage , cliquez sur Création.

  10. Double-cliquez sur CréerProcess. La Button1_Click méthode est insérée dans le code et le code apparaît dans le volet de contenu.

  11. Remplacez la méthode existante Button1_Click par le code suivant.

    private void Button1_Click(object sender, System.EventArgs e)
    {
        IntPtr Token = new IntPtr(0);
        IntPtr DupedToken = new IntPtr(0);
        bool ret;
        Label2.Text+=WindowsIdentity.GetCurrent().Name.ToString();
        SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
        sa.bInheritHandle = false;
        sa.Length = Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = (IntPtr)0;
        Token = WindowsIdentity.GetCurrent().Token;
        const uint GENERIC_ALL = 0x10000000;
        const int SecurityImpersonation = 2;
        const int TokenType = 1;
        ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
        if (ret == false)
        {
            Label1.Text +="DuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
        }
        else
        {
            Label1.Text+= "DuplicateTokenEx SUCCESS";
            STARTUPINFO si = new STARTUPINFO();
            si.cb = Marshal.SizeOf(si);
            si.lpDesktop = "";
            string commandLinePath;
            commandLinePath = TextBox1.Text;
            PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
            ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, "c:\\", ref si, out pi);
            if (ret == false)
            {
                Label1.Text +="CreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
            }
            else
            {
                Label1.Text +="CreateProcessAsUser SUCCESS. The child PID is" + pi.dwProcessId;
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
            }
            ret = CloseHandle(DupedToken);
            if (ret == false)
            {
                Label1.Text+=Marshal.GetLastWin32Error();
            }
            else
            {
                Label1.Text+="CloseHandle SUCCESS";
            }
        }
    }
    
  12. Dans le menu Générer, cliquez sur Générer la solution.

  13. Dans le menu Déboguer , cliquez sur Démarrer.

  14. Dans la page WebForm1 , tapez le chemin d’un processus que vous souhaitez démarrer. Par exemple, tapez SystemDriver \Windows\Notepad.exe.

  15. Cliquez sur CréerProcess.

References