1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
//------------------------------------------------------------------------------
// <copyright file="ImpersonationContext.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web {
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Util;
internal class ImpersonationContext : IDisposable {
private HandleRef _savedToken;
private bool _reverted;
private bool _impersonating;
// arg-less ctor creates dummy context
internal ImpersonationContext() {
}
// ctor that takes a token impersonates that token
internal ImpersonationContext(IntPtr token) {
ImpersonateToken(new HandleRef(this, token));
}
// IDisposable pattern
~ImpersonationContext() {
Dispose(false);
}
void IDisposable.Dispose() {
Undo();
}
private void Dispose(bool disposing) {
if (_savedToken.Handle != IntPtr.Zero) {
try {} finally {
UnsafeNativeMethods.CloseHandle(_savedToken.Handle);
_savedToken = new HandleRef(this, IntPtr.Zero);
}
}
}
// impersonate a given token
protected void ImpersonateToken(HandleRef token) {
try {
// first revert
_savedToken = new HandleRef(this, GetCurrentToken());
if (_savedToken.Handle != IntPtr.Zero) {
if (UnsafeNativeMethods.RevertToSelf() != 0) {
_reverted = true;
}
}
// impersonate token if not zero
if (token.Handle != IntPtr.Zero) {
if (UnsafeNativeMethods.SetThreadToken(IntPtr.Zero, token.Handle) == 0) {
throw new HttpException(SR.GetString(SR.Cannot_impersonate));
}
_impersonating = true;
}
}
catch {
RestoreImpersonation();
throw;
}
}
// restore impersonation to the original state
private void RestoreImpersonation() {
// first revert before reimpersonating
if (_impersonating) {
UnsafeNativeMethods.RevertToSelf();
_impersonating = false;
}
// second reimpersonate the orignal saved identity (if exists)
if (_savedToken.Handle != IntPtr.Zero) {
if (_reverted) {
if (UnsafeNativeMethods.SetThreadToken(IntPtr.Zero, _savedToken.Handle) == 0) {
throw new HttpException(SR.GetString(SR.Cannot_impersonate));
}
}
_reverted = false;
}
}
// 'public' version of Dispose
internal void Undo() {
RestoreImpersonation();
// free unmanaged resources
Dispose(true);
System.GC.SuppressFinalize(this);
}
// helper to get the currently impersonated token
private static IntPtr GetCurrentToken() {
IntPtr token = IntPtr.Zero;
if (UnsafeNativeMethods.OpenThreadToken(
UnsafeNativeMethods.GetCurrentThread(),
UnsafeNativeMethods.TOKEN_READ | UnsafeNativeMethods.TOKEN_IMPERSONATE,
true,
ref token) == 0) {
// if the last error is ERROR_NO_TOKEN it is ok, otherwise throw
if (Marshal.GetLastWin32Error() != UnsafeNativeMethods.ERROR_NO_TOKEN) {
throw new HttpException(SR.GetString(SR.Cannot_impersonate));
}
}
return token;
}
// helper to check if there is a current token
internal static bool CurrentThreadTokenExists {
get {
bool impersonating = false;
try {} finally {
IntPtr token = GetCurrentToken();
if (token != IntPtr.Zero) {
impersonating = true;
UnsafeNativeMethods.CloseHandle(token);
}
}
return impersonating;
}
}
}
internal sealed class ProcessImpersonationContext : ImpersonationContext {
internal ProcessImpersonationContext() {
ImpersonateToken(new HandleRef(this, IntPtr.Zero));
}
}
internal sealed class ApplicationImpersonationContext : ImpersonationContext {
internal ApplicationImpersonationContext() {
ImpersonateToken(new HandleRef(this, HostingEnvironment.ApplicationIdentityToken));
}
}
internal sealed class ClientImpersonationContext : ImpersonationContext {
internal ClientImpersonationContext(HttpContext context) {
Start(context, true);
}
internal ClientImpersonationContext(HttpContext context, bool throwOnError) {
Start(context, throwOnError);
}
private void Start(HttpContext context, bool throwOnError) {
IntPtr token = IntPtr.Zero;
try {
if (context != null) {
token = context.ImpersonationToken;
}
else {
// by default use app identity
token = HostingEnvironment.ApplicationIdentityToken;
}
}
catch {
if (throwOnError) {
throw;
}
}
// only impersonate if there is a token
// this is to optimize for the default case of impersonation="false"
// and no UNC identity, when requests run under process identity
if (token != IntPtr.Zero) {
ImpersonateToken(new HandleRef(this, token));
}
}
}
}
|