aspnetcore/src/Microsoft.AspNet.Security.W.../NativeInterop/SafeFreeContextBuffer.cs

166 lines
5.9 KiB
C#

// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
// -----------------------------------------------------------------------
// <copyright file="SafeFreeContextBuffer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace Microsoft.AspNet.Security.Windows
{
[SuppressUnmanagedCodeSecurity]
internal sealed class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeFreeContextBuffer()
: base(true)
{
}
// This must be ONLY called from this file and in the context of a CER
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal unsafe void Set(IntPtr value)
{
this.handle = value;
}
internal static int EnumeratePackages(out int pkgnum, out SafeFreeContextBuffer pkgArray)
{
int res = -1;
res = UnsafeNclNativeMethods.SafeNetHandles.EnumerateSecurityPackagesW(out pkgnum, out pkgArray);
if (res != 0 && pkgArray != null)
{
pkgArray.SetHandleAsInvalid();
}
return res;
}
internal static SafeFreeContextBuffer CreateEmptyHandle()
{
return new SafeFreeContextBuffer();
}
// After PINvoke call the method will fix the refHandle.handle with the returned value.
// The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned.
//
// This method switches between three non-interruptible helper methods. (This method can't be both non-interruptible and
// reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.)
public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle)
{
int status = (int)SecurityStatus.InvalidHandle;
bool b = false;
// We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit
// one of the following methods. So run within a CER non-interruptible block.
RuntimeHelpers.PrepareConstrainedRegions();
try
{
phContext.DangerousAddRef(ref b);
}
catch (Exception e)
{
if (b)
{
phContext.DangerousRelease();
b = false;
}
if (!(e is ObjectDisposedException))
{
throw;
}
}
finally
{
if (b)
{
status = UnsafeNclNativeMethods.SafeNetHandles.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer);
phContext.DangerousRelease();
}
if (status == 0 && refHandle != null)
{
if (refHandle is SafeFreeContextBuffer)
{
((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer);
}
else
{
((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer);
}
}
if (status != 0 && refHandle != null)
{
refHandle.SetHandleAsInvalid();
}
}
return status;
}
public static int SetContextAttributes(SafeDeleteContext phContext, ContextAttribute contextAttribute, byte[] buffer)
{
int status = (int)SecurityStatus.InvalidHandle;
bool b = false;
// We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing
// to jit one of the following methods. So run within a CER non-interruptible block.
RuntimeHelpers.PrepareConstrainedRegions();
try
{
phContext.DangerousAddRef(ref b);
}
catch (Exception e)
{
if (b)
{
phContext.DangerousRelease();
b = false;
}
if (!(e is ObjectDisposedException))
{
throw;
}
}
finally
{
if (b)
{
status = UnsafeNclNativeMethods.SafeNetHandles.SetContextAttributesW(
ref phContext._handle, contextAttribute, buffer, buffer.Length);
phContext.DangerousRelease();
}
}
return status;
}
protected override bool ReleaseHandle()
{
return UnsafeNclNativeMethods.SafeNetHandles.FreeContextBuffer(handle) == 0;
}
}
}