Re: Создание процесса в SQL CLR
От: SokolTry  
Дата: 11.02.09 18:00
Если кому интересно, то дело вот в чем

If you call the Start(ProcessStartInfo) method with the ProcessStartInfo.UserName and
ProcessStartInfo.Password properties set, the unmanaged CreateProcessWithLogonW function
is called, which starts the process in a new window even if the CreateNoWindow property
value is true or the WindowStyle property value is Hidden.

Попытка создать окно под SYSTEM и вызывает “System.ComponentModel.Win32Exception: Access is denied”.

Решить получилось так:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Security.Principal;
using System.Text;

namespace HFUDF
    /// <summary>
    /// UserSpecificProcess extends the standard Process object to /// create new processes under a different user than the calling parent process.
    /// Also, the standard output of the child process redirected back to the parent process.
    /// This is class is designed to operate inside an ASP.NET web application.
    /// The assumption is that the calling thread is operating with an impersonated security token.
    /// The this class will change the imperonated security token to a primary token, /// and call CreateProcessAsUser.
    /// A System.Diagnostics.Process object will be returned with appropriate properties set.
    /// To use this function, the following security priviliges need to be set for the ASPNET account /// using the local security policy MMC snap-in. CreateProcessAsUser requirement.
    /// "Replace a process level token"/SE_ASSIGNPRIMARYTOKEN_NAME/SeAssignPrimaryTokenPrivilege
    /// "Adjust memory quotas for a process"/SE_INCREASE_QUOTA_NAME/SeIncreaseQuotaPrivilege
    /// This class was designed for .NET 1.1 for operating systems W2k an higher.
    /// Any other features or platform support can be implemented by using the .NET reflector and /// investigating the Process class.
    /// </summary>
    public class UserSpecificProcess : Process
        public class CreateProcessStartupInfo
            public int cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public int dwX;
            public int dwY;
            public int dwXSize;
            public int dwYSize;
            public int dwXCountChars;
            public int dwYCountChars;
            public int dwFillAttribute;
            public int dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
            public CreateProcessStartupInfo()
                this.cb = Marshal.SizeOf(typeof(CreateProcessStartupInfo));
                this.lpReserved = null;
                this.lpDesktop = null;
                this.lpTitle = null;
                this.dwX = 0;
                this.dwY = 0;
                this.dwXSize = 0;
                this.dwYSize = 0;
                this.dwXCountChars = 0;
                this.dwYCountChars = 0;
                this.dwFillAttribute = 0;
                this.dwFlags = 0;
                this.wShowWindow = 0;
                this.cbReserved2 = 0;
                this.lpReserved2 = IntPtr.Zero;
                this.hStdInput = IntPtr.Zero;
                this.hStdOutput = IntPtr.Zero;
                this.hStdError = IntPtr.Zero;

        public class CreateProcessProcessInformation
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
            public CreateProcessProcessInformation()
                this.hProcess = IntPtr.Zero;
                this.hThread = IntPtr.Zero;
                this.dwProcessId = 0;
                this.dwThreadId = 0;

        public class SecurityAttributes
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
            public SecurityAttributes()
                this.nLength = Marshal.SizeOf(typeof(SecurityAttributes));

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern bool CloseHandle(HandleRef handle);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool
        CreateProcess([MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName, StringBuilder lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, CreateProcessStartupInfo lpStartupInfo, CreateProcessProcessInformation lpProcessInformation);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CreateProcessAsUserW(IntPtr token, [MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName, [MarshalAs(UnmanagedType.LPTStr)] string lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, CreateProcessStartupInfo lpStartupInfo, CreateProcessProcessInformation lpProcessInformation);

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern IntPtr GetStdHandle(int whichHandle);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, SecurityAttributes lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, HandleRef hTemplateFile);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CreateNamedPipe(string name, int openMode, int pipeMode, int maxInstances, int outBufSize, int inBufSize, int timeout, SecurityAttributes lpPipeAttributes);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetConsoleOutputCP();

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool DuplicateTokenEx(HandleRef hToken, int access, SecurityAttributes tokenAttributes, int impersonationLevel, int tokenType, ref IntPtr hNewToken);

        // WinNT.h ACCESS TYPES
        const int GENERIC_ALL = 0x10000000;

        const int SECURITY_IMPERSONATION = 2;

        // WinNT.h TOKEN TYPE
        const int TOKEN_PRIMARY = 1;

        // WinBase.h
        const int STD_INPUT_HANDLE = -10;
        const int STD_ERROR_HANDLE = -12;

        // WinBase.h STARTUPINFO
        const int STARTF_USESTDHANDLES = 0x100;

        // Microsoft.Win23.NativeMethods
        static IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
        public static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);

        /// <summary>
        /// Starts the process with the security token of the calling thread.
        /// If the security token has a token type of TokenImpersonation,
        /// the token will be duplicated to a primary token before calling
        /// CreateProcessAsUser.
        /// </summary>
        /// <param name="process">The process to start.</param>
        public void StartAsUser()

        /// <summary>
        /// Starts the process with the given security token.
        /// If the security token has a token type of TokenImpersonation,
        /// the token will be duplicated to a primary token before calling
        /// CreateProcessAsUser.
        /// </summary>
        /// <param name="process"></param>
        public void StartAsUser(IntPtr userToken)
            if (StartInfo.UseShellExecute)
                throw new InvalidOperationException("can't call this with shell execute");

            // just assume that the securityToken is of TokenImpersonation and create a primary.
            IntPtr primayUserToken = CreatePrimaryToken(userToken);

            CreateProcessStartupInfo startupInfo = new CreateProcessStartupInfo();
            CreateProcessProcessInformation processInformation = new CreateProcessProcessInformation();

            IntPtr stdinHandle;
            IntPtr stdoutReadHandle;
            IntPtr stdoutWriteHandle = IntPtr.Zero;
            IntPtr stderrHandle;
                stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
                MyCreatePipe(out stdoutReadHandle, out stdoutWriteHandle, false);
                stderrHandle = GetStdHandle(STD_ERROR_HANDLE);

                //assign handles to startup info
                startupInfo.dwFlags = STARTF_USESTDHANDLES;
                startupInfo.hStdInput = stdinHandle;
                startupInfo.hStdOutput = stdoutWriteHandle;
                startupInfo.hStdError = stderrHandle;

                string commandLine = GetCommandLine();
                int creationFlags = 0;
                IntPtr environment = IntPtr.Zero;
                string workingDirectory = GetWorkingDirectory();

                // create the process or fail trying.
                if (!CreateProcessAsUserW(
                    throw new Win32Exception();
                // close thread handle
                if (processInformation.hThread != INVALID_HANDLE_VALUE)
                    CloseHandle(new HandleRef(this, processInformation.hThread));

                // close client stdout handle
                CloseHandle(new HandleRef(this, stdoutWriteHandle));

        /// <summary>
        /// Creates a primayToken out of an existing token.
        /// </summary>
        /// <param name="userToken"></param>
        private IntPtr CreatePrimaryToken(IntPtr userToken)
            SecurityAttributes securityAttributes = new SecurityAttributes();
            IntPtr primaryUserToken = IntPtr.Zero;
            if (!DuplicateTokenEx(new HandleRef(this, userToken), GENERIC_ALL, securityAttributes, SECURITY_IMPERSONATION, TOKEN_PRIMARY, ref
                throw new Win32Exception();
            return primaryUserToken;

        /// <summary>
        /// Gets the appropriate commandLine from the process.
        /// </summary>
        /// <param name="process"></param>
        /// <returns></returns>
        private string GetCommandLine()
            StringBuilder builder1 = new StringBuilder();
            string text1 = StartInfo.FileName.Trim();
            string text2 = StartInfo.Arguments;
            bool flag1 = text1.StartsWith("\"") && text1.EndsWith("\"");
            if (!flag1)
            if (!flag1)
            if ((text2 != null) && (text2.Length > 0))
                builder1.Append(" ");
            return builder1.ToString();

        /// <summary>
        /// Gets the working directory or returns null if an empty string was found.
        /// </summary>
        /// <returns></returns>
        private string GetWorkingDirectory()
            return (StartInfo.WorkingDirectory != string.Empty) ?
            StartInfo.WorkingDirectory : null;

        /// <summary>
        /// A clone of Process.CreatePipe. This is only implemented because reflection with
        /// out parameters are a pain.
        /// Note: This is only finished for w2k and higher machines.
        /// </summary>
        /// <param name="parentHandle"></param>
        /// <param name="childHandle"></param>
        /// <param name="parentInputs">Specifies whether the parent will be performing the writes.</param>
        public static void MyCreatePipe(out IntPtr parentHandle, out IntPtr childHandle, bool parentInputs)
            string pipename = @"\\.\pipe\Global\" + Guid.NewGuid().ToString();

            SecurityAttributes attributes2 = new SecurityAttributes();
            attributes2.bInheritHandle = false;

            parentHandle = CreateNamedPipe(pipename, 0x40000003, 0, 0xff, 0x1000, 0x1000, 0, attributes2);
            if (parentHandle == INVALID_HANDLE_VALUE)
                throw new Win32Exception();

            SecurityAttributes attributes3 = new SecurityAttributes();
            attributes3.bInheritHandle = true;
            int num1 = 0x40000000;
            if (parentInputs)
                num1 = -2147483648;
            childHandle = CreateFile(pipename, num1, 3, attributes3, 3, 0x40000080, NullHandleRef);
            if (childHandle == INVALID_HANDLE_VALUE)
                throw new Win32Exception();

и вызвать
    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;
    IntPtr tokenHandle = new IntPtr(0);
    bool returnValue = UserSpecificProcess.LogonUser(login, "", password,
        ref tokenHandle);

    UserSpecificProcess proc = new UserSpecificProcess();
    proc.StartInfo.WorkingDirectory = @"C:\";
    proc.StartInfo.FileName = @"C:\HFUDFClient.exe";
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.CreateNoWindow = true;
Подождите ...
Пока на собственное сообщение не было ответов, его можно удалить.