Skip to content

Commit 0690bd9

Browse files
committed
Added files script to provide methods for abstracting the need to manipulate ACLs when installing/uninstalling.
1 parent 52694a1 commit 0690bd9

11 files changed

+607
-53
lines changed

scripts/setup/acl-util.ps1

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
5+
Param (
6+
[parameter(Mandatory=$true , Position=0)]
7+
[ValidateSet("Enable-AclUtil")]
8+
[string]
9+
$Command
10+
)
11+
12+
$cs = '
13+
namespace Microsoft.IIS.Administration.Setup
14+
{
15+
using System;
16+
using System.ComponentModel;
17+
using System.Runtime.InteropServices;
18+
19+
public class AclUtil
20+
{
21+
public const string TAKE_OWNERSHIP_PRIVILEGE = "SeTakeOwnershipPrivilege";
22+
public const string RESTORE_PRIVILEGE = "SeRestorePrivilege";
23+
24+
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
25+
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
26+
internal const int TOKEN_QUERY = 0x00000008;
27+
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
28+
29+
private const string ADVAPI = "advapi32.dll";
30+
private const string KERNEL32 = "kernel32.dll";
31+
32+
[DllImport(ADVAPI, SetLastError = true)]
33+
private static extern bool AdjustTokenPrivileges(
34+
IntPtr hTokenHandle,
35+
bool fDisableAllPrivileges,
36+
ref TokPriv1Luid pNewState,
37+
int nBufferLength,
38+
IntPtr pPreviousState,
39+
IntPtr pnReturnLength);
40+
41+
[DllImport(KERNEL32, SetLastError = true)]
42+
private static extern bool CloseHandle(IntPtr hObject);
43+
44+
[DllImport(KERNEL32)]
45+
private static extern IntPtr GetCurrentProcess();
46+
47+
[DllImport(ADVAPI, SetLastError = true)]
48+
private static extern bool GetTokenInformation(
49+
IntPtr TokenHandle,
50+
TOKEN_INFORMATION_CLASS TokenInformationClass,
51+
IntPtr TokenInformation,
52+
uint TokenInformationLength,
53+
out uint ReturnLength);
54+
55+
[DllImport(ADVAPI, SetLastError = true, CharSet = CharSet.Unicode)]
56+
private static extern bool LookupPrivilegeValueW(
57+
string host,
58+
string name,
59+
ref long pluid);
60+
61+
[DllImport(ADVAPI, ExactSpelling = true, SetLastError = true)]
62+
private static extern bool OpenProcessToken(
63+
IntPtr hProcess,
64+
int TokenAccess,
65+
ref IntPtr phAccessToken);
66+
67+
[StructLayout(LayoutKind.Sequential, Pack = 1)]
68+
private struct TokPriv1Luid
69+
{
70+
public int Count;
71+
public long Luid;
72+
public int Attr;
73+
}
74+
75+
[StructLayout(LayoutKind.Sequential)]
76+
private class TOKEN_PRIVILEGES
77+
{
78+
public UInt32 PrivilegeCount;
79+
public LUID_AND_ATTRIBUTES[] Privileges;
80+
}
81+
82+
[StructLayout(LayoutKind.Sequential, Pack = 4)]
83+
private class LUID_AND_ATTRIBUTES
84+
{
85+
public long Luid;
86+
public UInt32 Attributes;
87+
}
88+
89+
private enum TOKEN_INFORMATION_CLASS
90+
{
91+
TokenUser = 1,
92+
TokenGroups,
93+
TokenPrivileges
94+
}
95+
96+
public static void SetPrivilege(string privilege, bool enabled)
97+
{
98+
IntPtr hAccessToken = IntPtr.Zero;
99+
int attribute = enabled ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_DISABLED;
100+
101+
try {
102+
IntPtr hProcess = GetCurrentProcess();
103+
104+
if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref hAccessToken)) {
105+
throw new Win32Exception(Marshal.GetLastWin32Error());
106+
}
107+
108+
TokPriv1Luid tp = new TokPriv1Luid();
109+
tp.Count = 1;
110+
tp.Luid = 0;
111+
tp.Attr = attribute;
112+
113+
if (!LookupPrivilegeValueW(null, privilege, ref tp.Luid)) {
114+
throw new Win32Exception(Marshal.GetLastWin32Error());
115+
}
116+
117+
if (!AdjustTokenPrivileges(hAccessToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero)) {
118+
throw new Win32Exception(Marshal.GetLastWin32Error());
119+
}
120+
}
121+
finally {
122+
if (hAccessToken != IntPtr.Zero) {
123+
CloseHandle(hAccessToken);
124+
hAccessToken = IntPtr.Zero;
125+
}
126+
}
127+
}
128+
129+
public static bool HasPrivilege(string privilege)
130+
{
131+
IntPtr hAccessToken = IntPtr.Zero;
132+
IntPtr pTokenInfo = IntPtr.Zero;
133+
134+
try {
135+
long luid = 0;
136+
137+
if (!LookupPrivilegeValueW(null, privilege, ref luid)) {
138+
throw new Win32Exception(Marshal.GetLastWin32Error());
139+
}
140+
141+
IntPtr hProcess = GetCurrentProcess();
142+
143+
if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref hAccessToken)) {
144+
throw new Win32Exception(Marshal.GetLastWin32Error());
145+
}
146+
147+
//
148+
// Query information size
149+
uint cb;
150+
if (!GetTokenInformation(hAccessToken, TOKEN_INFORMATION_CLASS.TokenPrivileges, pTokenInfo, 0, out cb)) {
151+
pTokenInfo = Marshal.AllocHGlobal((int)cb);
152+
153+
if (!GetTokenInformation(hAccessToken, TOKEN_INFORMATION_CLASS.TokenPrivileges, pTokenInfo, cb, out cb)) {
154+
throw new Win32Exception(Marshal.GetLastWin32Error());
155+
}
156+
}
157+
158+
TOKEN_PRIVILEGES privileges = MarshalTokenPrivileges(pTokenInfo);
159+
160+
foreach (LUID_AND_ATTRIBUTES priv in privileges.Privileges) {
161+
if (priv.Luid == luid) {
162+
return (priv.Attributes & SE_PRIVILEGE_ENABLED) > 0;
163+
}
164+
}
165+
166+
return false;
167+
}
168+
finally {
169+
if (hAccessToken != IntPtr.Zero) {
170+
CloseHandle(hAccessToken);
171+
hAccessToken = IntPtr.Zero;
172+
}
173+
174+
if (pTokenInfo != IntPtr.Zero) {
175+
Marshal.FreeHGlobal(pTokenInfo);
176+
pTokenInfo = IntPtr.Zero;
177+
}
178+
}
179+
}
180+
181+
182+
private static TOKEN_PRIVILEGES MarshalTokenPrivileges(IntPtr buffer)
183+
{
184+
LUID_AND_ATTRIBUTES[] privs = new LUID_AND_ATTRIBUTES[(uint)Marshal.ReadInt32(buffer)];
185+
186+
for (int i = 0; i < privs.Length; i++) {
187+
privs[i] = new LUID_AND_ATTRIBUTES();
188+
Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + sizeof(uint) + Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * i), privs[i]);
189+
}
190+
191+
TOKEN_PRIVILEGES privileges = new TOKEN_PRIVILEGES();
192+
privileges.PrivilegeCount = (uint)privs.Length;
193+
privileges.Privileges = privs;
194+
195+
return privileges;
196+
}
197+
}
198+
}
199+
'
200+
201+
function InitializeInterop() {
202+
try {
203+
[Microsoft.IIS.Administration.Setup.AclUtil] | Out-Null
204+
}
205+
catch {
206+
Add-Type $cs
207+
}
208+
}
209+
210+
switch ($Command)
211+
{
212+
"Enable-AclUtil"
213+
{
214+
InitializeInterop
215+
}
216+
default
217+
{
218+
throw "Unknown command"
219+
}
220+
}

scripts/setup/config.ps1

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,7 @@ function Get($_path) {
104104
# Path: The parent directory of the setup configuration.
105105
function Remove($_path) {
106106
if ($(Test-Path $_path)) {
107-
.\security.ps1 Add-SelfRights -Path $_path
108-
Remove-Item -Force $(Join-Path $_path $INSTALL_FILE)
107+
.\files.ps1 Remove-ItemForced -Path $(Join-Path $_path $INSTALL_FILE)
109108
}
110109
}
111110

@@ -128,10 +127,20 @@ function Write-Config($obj, $_path) {
128127
$xConfig.AppendChild($xElem) | Out-Null
129128
}
130129
$xml.AppendChild($xConfig) | Out-Null
131-
132-
$sw = New-Object System.IO.StreamWriter -ArgumentList (Join-Path $_path $INSTALL_FILE)
130+
131+
$ms = New-Object System.IO.MemoryStream
132+
$sw = New-Object System.IO.StreamWriter -ArgumentList $ms
133133
$xml.Save($sw) | Out-Null
134+
135+
$position = $ms.Seek(0, [System.IO.SeekOrigin]::Begin)
136+
$sr = New-Object System.IO.StreamReader -ArgumentList $ms
137+
$content = $sr.ReadToEnd()
138+
139+
$sr.Dispose()
134140
$sw.Dispose()
141+
$ms.Dispose()
142+
143+
.\files.ps1 Write-FileForced -Path $(Join-Path $_path $INSTALL_FILE) -Content $content
135144
}
136145

137146
# Sets the applicationHost.config file to host the Microsoft.IIS.Administration application given the specified settings.
@@ -171,9 +180,20 @@ function Write-AppHost($_appHostPath, $_applicationPath, $_port, $_version) {
171180
$site.application.SetAttribute("applicationPool", "$IISAdminPoolName")
172181
$site.application.virtualDirectory.SetAttribute("physicalPath", "$_applicationPath")
173182
$site.bindings.binding.SetAttribute("bindingInformation", "*:$($_port):")
174-
$sw = New-Object System.IO.StreamWriter -ArgumentList $_appHostPath
175-
$xml.Save($sw)
183+
184+
$ms = New-Object System.IO.MemoryStream
185+
$sw = New-Object System.IO.StreamWriter -ArgumentList $ms
186+
$xml.Save($sw) | Out-Null
187+
188+
$position = $ms.Seek(0, [System.IO.SeekOrigin]::Begin)
189+
$sr = New-Object System.IO.StreamReader -ArgumentList $ms
190+
$content = $sr.ReadToEnd()
191+
192+
$sr.Dispose()
176193
$sw.Dispose()
194+
$ms.Dispose()
195+
196+
.\files.ps1 Write-FileForced -Path $_appHostPath -Content $content
177197
}
178198

179199
# Gets the port that the IIS Administration site is configured to listen on in the applicationHost.config file.

0 commit comments

Comments
 (0)