diff --git a/src/libraries/System.Diagnostics.Process/tests/Interop.cs b/src/libraries/System.Diagnostics.Process/tests/Interop.cs index e7388724a38999..449db3f9c3c985 100644 --- a/src/libraries/System.Diagnostics.Process/tests/Interop.cs +++ b/src/libraries/System.Diagnostics.Process/tests/Interop.cs @@ -75,7 +75,7 @@ public struct SID_AND_ATTRIBUTES [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern uint NetUserAdd(string servername, uint level, ref USER_INFO_1 buf, out uint parm_err); - [DllImport("netapi32.dll")] + [DllImport("netapi32.dll", CharSet = CharSet.Unicode)] internal static extern uint NetUserDel(string servername, string username); [DllImport("advapi32.dll")] @@ -94,7 +94,7 @@ internal static void NetUserAdd(string username, string password) uint parm_err; uint result = NetUserAdd(null, 1, ref userInfo, out parm_err); - if (result != 0) // NERR_Success + if (result != ExitCodes.NERR_Success) { // most likely result == ERROR_ACCESS_DENIED // due to running without elevated privileges @@ -132,5 +132,11 @@ internal static bool ProcessTokenToSid(SafeProcessHandle token, out SecurityIden Marshal.FreeHGlobal(tu); } } + + internal static class ExitCodes + { + internal const uint NERR_Success = 0; + internal const uint NERR_UserNotFound = 2221; + } } } diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs index 38c626ec2a8190..1493c990dedc76 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs @@ -17,6 +17,7 @@ using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using Xunit; +using System.Security.AccessControl; namespace System.Diagnostics.Tests { @@ -24,6 +25,8 @@ public class ProcessStartInfoTests : ProcessTestBase { private const string ItemSeparator = "CAFF9451396B4EEF8A5155A15BDC2080"; // random string that shouldn't be in any env vars; used instead of newline to separate env var strings + private static bool IsNotWindowsNanoServerAndRemoteExecutorIsSupported => PlatformDetection.IsNotWindowsNanoServer && RemoteExecutor.IsSupported; + [Fact] public void TestEnvironmentProperty() { @@ -447,21 +450,18 @@ public void TestWorkingDirectoryPropertyInChildProcess() }, workingDirectory, new RemoteInvokeOptions { StartInfo = psi }).Dispose(); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/18978")] - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported)), PlatformSpecific(TestPlatforms.Windows), OuterLoop] // Uses P/Invokes, Requires admin privileges + [ConditionalFact(nameof(IsNotWindowsNanoServerAndRemoteExecutorIsSupported))] // Nano has no "netapi32.dll" + [PlatformSpecific(TestPlatforms.Windows)] + [OuterLoop("Requires admin privileges")] public void TestUserCredentialsPropertiesOnWindows() { // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Unit test dummy credentials.")] - string username = "test", password = "PassWord123!!"; - try - { - Interop.NetUserAdd(username, password); - } - catch (Exception exc) - { - Console.Error.WriteLine("TestUserCredentialsPropertiesOnWindows: NetUserAdd failed: {0}", exc.Message); - return; // test is irrelevant if we can't add a user - } + const string username = "testForDotnetRuntime", password = "PassWord123!!"; + + uint removalResult = Interop.NetUserDel(null, username); + Assert.True(removalResult == Interop.ExitCodes.NERR_Success || removalResult == Interop.ExitCodes.NERR_UserNotFound); + + Interop.NetUserAdd(username, password); bool hasStarted = false; SafeProcessHandle handle = null; @@ -471,6 +471,9 @@ public void TestUserCredentialsPropertiesOnWindows() { p = CreateProcessLong(); + // ensure the new user can access the .exe (otherwise you get Access is denied exception) + SetAccessControl(username, p.StartInfo.FileName, AccessControlType.Allow); + p.StartInfo.LoadUserProfile = true; p.StartInfo.UserName = username; p.StartInfo.PasswordInClearText = password; @@ -496,8 +499,9 @@ public void TestUserCredentialsPropertiesOnWindows() } finally { - IEnumerable collection = new uint[] { 0 /* NERR_Success */, 2221 /* NERR_UserNotFound */ }; - Assert.Contains(Interop.NetUserDel(null, username), collection); + SetAccessControl(username, p.StartInfo.FileName, AccessControlType.Deny); // revoke the access + + Assert.Equal(Interop.ExitCodes.NERR_Success, Interop.NetUserDel(null, username)); if (handle != null) handle.Dispose(); @@ -511,6 +515,14 @@ public void TestUserCredentialsPropertiesOnWindows() } } + private static void SetAccessControl(string userName, string filePath, AccessControlType accessControlType) + { + FileInfo fileInfo = new FileInfo(filePath); + FileSecurity accessControl = fileInfo.GetAccessControl(); + accessControl.AddAccessRule(new FileSystemAccessRule(userName, FileSystemRights.ReadAndExecute, accessControlType)); + fileInfo.SetAccessControl(accessControl); + } + private static List GetNamesOfUserProfiles() { List userNames = new List();