Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/libraries/System.Diagnostics.Process/tests/Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using Xunit;
using System.Security.AccessControl;

namespace System.Diagnostics.Tests
{
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()
{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -496,8 +499,9 @@ public void TestUserCredentialsPropertiesOnWindows()
}
finally
{
IEnumerable<uint> collection = new uint[] { 0 /* NERR_Success */, 2221 /* NERR_UserNotFound */ };
Assert.Contains<uint>(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();
Expand All @@ -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<string> GetNamesOfUserProfiles()
{
List<string> userNames = new List<string>();
Expand Down