OSDN Git Service

na-get-lib,使う必要がない気もするが権限降格のコードを追加。現時点のAppliStationでは呼ばれない。
authorttp <ttp@users.sourceforge.jp>
Sun, 1 Feb 2009 08:21:42 +0000 (08:21 +0000)
committerttp <ttp@users.sourceforge.jp>
Sun, 1 Feb 2009 08:21:42 +0000 (08:21 +0000)
git-svn-id: http://localhost/svn/AppliStation/trunk@1014 34ed2c89-c49f-4a4b-abdb-c318350108cf

na-get-lib/NaGet.InteropServices/CreateProcessCaller.cs

index 382f6ae..696e686 100644 (file)
@@ -82,6 +82,49 @@ namespace NaGet.InteropServices
                [return: MarshalAs(UnmanagedType.Bool)]\r
                static extern bool GetExitCodeProcess(IntPtr hProcess, out int lpExitCode);\r
                \r
+               #region 権限降格関連\r
+               \r
+               [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true)]\r
+               [return: MarshalAs(UnmanagedType.Bool)]\r
+               static extern bool CreateProcessWithTokenW(\r
+            IntPtr hToken,\r
+            uint dwLogonFlags,\r
+            string lpApplicationName, string lpCommandLine,\r
+            uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,\r
+            [In] ref STARTUPINFO lpStartupInfo,\r
+            out PROCESS_INFORMATION lpProcessInfo);\r
+\r
+               // For Windows Mobile, replace user32.dll with coredll.dll\r
+               [DllImport("user32.dll", SetLastError = true)]\r
+               static extern IntPtr FindWindow(string lpClassName, string lpWindowName);\r
+               \r
+               [DllImport("user32.dll", SetLastError=true)]\r
+               static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);\r
+                               \r
+               [DllImport("advapi32.dll", SetLastError=true)]\r
+               [return: MarshalAs(UnmanagedType.Bool)]\r
+               static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);\r
+               \r
+               [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]\r
+               extern static bool DuplicateTokenEx(\r
+                       IntPtr hExistingToken,\r
+                       uint dwDesiredAccess,\r
+                       /* ref SECURITY_ATTRIBUTES lpTokenAttributes, */\r
+                       IntPtr lpTokenAttributes,\r
+                       /* SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, */\r
+                       uint ImpersonationLevel,\r
+                       /* TOKEN_TYPE TokenType, */\r
+                       uint TokenType,\r
+                       out IntPtr phNewToken );\r
+               \r
+               [DllImport("kernel32.dll")]\r
+               static extern IntPtr GetEnvironmentStrings();\r
+\r
+               [DllImport("kernel32.dll")]\r
+               static extern bool FreeEnvironmentStrings(IntPtr lpszEnvironmentBlock);\r
+               \r
+               #endregion\r
+               \r
                #endregion\r
                \r
                STARTUPINFO si;\r
@@ -93,6 +136,11 @@ namespace NaGet.InteropServices
                /// <param name="procInfo">プロセス起動情報。\r
                /// なお、<code>procInfo.UseShellExecute</code>は必ずfalseでなければならない</param>\r
                public CreateProcessCaller(ProcessStartInfo procInfo)\r
+                       : this(procInfo, false)\r
+               {\r
+               }\r
+               \r
+               public CreateProcessCaller(ProcessStartInfo procInfo, bool runAsNormalUser)\r
                {\r
                        if (procInfo.UseShellExecute) {\r
                                throw new ArgumentException("UseShellExecute must be false");\r
@@ -105,14 +153,82 @@ namespace NaGet.InteropServices
                        if (procInfo.CreateNoWindow) dwCreationFlags |= 0x08000000; // CREATE_NO_WINDOW\r
                        string lpCurrentDirectory = (System.IO.Directory.Exists(procInfo.WorkingDirectory))? procInfo.WorkingDirectory : null;\r
                        \r
-                       bool retValue = CreateProcess(lpFileName, procInfo.Arguments,\r
+                       bool retValue;\r
+                       if (runAsNormalUser && NaGet.Utils.IsAdministrators()) {\r
+                               retValue = _CreateProcessAsNormalUser(lpFileName, procInfo.Arguments,\r
                                                      IntPtr.Zero, IntPtr.Zero,\r
                                                      false, dwCreationFlags,\r
                                                      IntPtr.Zero, lpCurrentDirectory, ref si, out pi);\r
+                       } else {\r
+                               retValue = CreateProcess(lpFileName, procInfo.Arguments,\r
+                                                     IntPtr.Zero, IntPtr.Zero,\r
+                                                     false, dwCreationFlags,\r
+                                                     IntPtr.Zero, lpCurrentDirectory, ref si, out pi);\r
+                       }\r
+                       \r
                        if (! retValue) {\r
                                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());\r
                        }\r
-                       CloseHandle(pi.hThread);\r
+                       if (pi.hThread != IntPtr.Zero) {\r
+                               CloseHandle(pi.hThread);\r
+                       }\r
+               }\r
+               \r
+               private bool _CreateProcessAsNormalUser(string lpApplicationName,\r
+                       string lpCommandLine,\r
+                       /* ref SECURITY_ATTRIBUTES lpProcessAttributes, */\r
+                       IntPtr lpProcessAttributes,\r
+                       /* ref SECURITY_ATTRIBUTES lpThreadAttributes, */\r
+                       IntPtr lpThreadAttributes,\r
+                       bool bInheritHandles,\r
+                       uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,\r
+                       [In] ref STARTUPINFO lpStartupInfo,\r
+                       out PROCESS_INFORMATION lpProcessInformation)\r
+               {\r
+                       /*\r
+                        * cf. nsWindowsRestart.cpp#LaunchAsNormalUser\r
+                        * 動作チェックせず\r
+                        */\r
+                       \r
+                       \r
+                       lpProcessInformation = new PROCESS_INFORMATION(); /* fake */\r
+                       try {\r
+                               IntPtr hwndShell = FindWindow("Progman", null);\r
+                               uint dwProcessId;\r
+                               GetWindowThreadProcessId(hwndShell, out dwProcessId);\r
+                               Process procShell = Process.GetProcessById((int) dwProcessId);\r
+                               if (procShell == null) {\r
+                                       return false;\r
+                               }\r
+                               \r
+                               IntPtr hTokenHandle, hNewToken;\r
+                               // bool ok = OpenProcessToken(hProcessShell, MAXIMUM_ALLOWED, out hTokenHandle);\r
+                               bool ok = OpenProcessToken(procShell.Handle, 0x02000000, out hTokenHandle);\r
+                               if (!ok) return false;\r
+                               // ok = DuplicateTokenEx(hTokenShell, MAXIMUM_ALLOWED, null, SecurityDelegation, TokenPrimary, out hNewToken);\r
+                               ok = DuplicateTokenEx(hTokenHandle, 0x02000000, IntPtr.Zero, 3, 1, out hNewToken);\r
+                               CloseHandle(hTokenHandle);\r
+                               if (!ok) return false;\r
+\r
+                               IntPtr myenv = GetEnvironmentStrings();\r
+                               ok = CreateProcessWithTokenW(hNewToken,\r
+                                                            0, // profile is already loaded\r
+                                                            lpApplicationName,\r
+                                                            lpCommandLine,\r
+                                                            dwCreationFlags,\r
+                                                            myenv,\r
+                                                            lpCurrentDirectory,\r
+                                                            ref lpStartupInfo,\r
+                                                            out lpProcessInformation);\r
+                               if (myenv != IntPtr.Zero) {\r
+                                       FreeEnvironmentStrings(myenv);\r
+                               }\r
+                               CloseHandle(hNewToken);\r
+                               \r
+                               return ok;\r
+                       } catch {\r
+                               return false;\r
+                       }\r
                }\r
                \r
                /// <summary>\r
@@ -153,7 +269,9 @@ namespace NaGet.InteropServices
                /// </summary>\r
                public void Dispose()\r
                {\r
-                       CloseHandle(pi.hProcess);\r
+                       if (pi.hProcess != IntPtr.Zero) {\r
+                               CloseHandle(pi.hProcess);\r
+                       }\r
                }\r
                \r
        }\r