Мы реализовали сборку Windows на C#. Эта программа прослушивает сокет для входящих соединений и запускает дочерние процессы (неуправляемый код c), которые затем должны использовать этот сокет. Дочерние процессы запускаются командной строкой, которая включает дескриптор сокета в качестве аргумента. Весь механизм отлично работает с .Net 4.8 Framework, но не работает с .Net 6. Это фрагмент кода, который мы используем:
GetUserNameAndDomain(user, out var userName, out var domain);
var process = new Process{StartInfo = new ProcessStartInfo(command, arguments){UseShellExecute = false}};
WrapperImpersonationContext wrapperImpersonationContext = new WrapperImpersonationContext(domain, userName, password.ToUnsecureString(), false, false);
using (wrapperImpersonationContext) {
Action impersonationAction = () =>
{
process.Start();
};
wrapperImpersonationContext.Enter(impersonationAction);
}
где материал олицетворения в основном делает что-то вроде
public WrapperImpersonationContext(string domain, string username, string password, bool automaticallyEnter = true, bool logonAsService = false) {
mDomain = domain;
mUsername = username;
mPassword = password;
mLogonType = logonAsService ? LOGON32_LOGON_SERVICE : LOGON32_LOGON_INTERACTIVE;
if (automaticallyEnter)
Enter();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public void Enter(Action impersonationAction = null) {
//if (IsInContext)
// return;
mToken = new IntPtr(0);
try {
LogFactory.WriteVerbose("Logon to user '{0}' in domain '{1}'", mUsername, mDomain);
mToken = IntPtr.Zero;
bool logonSuccessfull = LogonUser(mUsername, mDomain, mPassword, mLogonType, LOGON32_PROVIDER_DEFAULT, ref mToken);
if (logonSuccessfull == false) {
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error);
}
WindowsIdentity identity = new WindowsIdentity(mToken);
WindowsIdentity.RunImpersonated(new Microsoft.Win32.SafeHandles.SafeAccessTokenHandle(mToken), impersonationAction);
LogFactory.WriteVerbose("Impersonation was successfully");
} catch (Exception exception) {
LogFactory.WriteWarning(exception);
throw;
}
}
Мы использовали Sysinternals Process Explorer для просмотра дескрипторов родительского и дочернего процессов. Используя .Net 4.8, мы ясно увидели, что дескриптор сокета, переданный в командной строке, доступен в списке дескрипторов дочерних процессов. Однако при использовании .Net 6 переданный дескриптор не является. В .Net 6 наследуется меньше дескрипторов по сравнению с .Net 4.8.
Почему .Net 6 ведет себя по-другому в этой области? Все исследования/чтения, которые мы сделали, показали, что «дескриптор наследования» должен оставаться таким же в .Net 6.
Мы использовали GetHandleInformation(), чтобы узнать, что сокет, к которому мы хотим получить доступ в дочернем процессе, не был помечен как «наследуемый» в .NET 6 (тогда как это было при использовании .Net 4.8). Теперь мы используем SetHandleInformation(), чтобы установить флаг в 1 и вуаля — теперь мы можем передать дескриптор.