mirror of https://github.com/winsw/winsw
Allow prompting for credentials
parent
5efcc8aca5
commit
afe25d1d82
|
@ -207,13 +207,24 @@ namespace winsw
|
||||||
allowServiceLogonRight = true;
|
allowServiceLogonRight = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (descriptor.HasServiceAccount())
|
||||||
{
|
{
|
||||||
if (descriptor.HasServiceAccount())
|
username = descriptor.ServiceAccountUserName;
|
||||||
|
password = descriptor.ServiceAccountPassword;
|
||||||
|
allowServiceLogonRight = descriptor.AllowServiceAcountLogonRight;
|
||||||
|
|
||||||
|
if (username is null || password is null)
|
||||||
{
|
{
|
||||||
username = descriptor.ServiceAccountUserName;
|
switch (descriptor.ServiceAccountPrompt)
|
||||||
password = descriptor.ServiceAccountPassword;
|
{
|
||||||
allowServiceLogonRight = descriptor.AllowServiceAcountLogonRight;
|
case "dialog":
|
||||||
|
PropmtForCredentialsDialog();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "console":
|
||||||
|
PromptForCredentialsConsole();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +268,116 @@ namespace winsw
|
||||||
{
|
{
|
||||||
EventLog.CreateEventSource(eventLogSource, "Application");
|
EventLog.CreateEventSource(eventLogSource, "Application");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropmtForCredentialsDialog()
|
||||||
|
{
|
||||||
|
username ??= string.Empty;
|
||||||
|
password ??= string.Empty;
|
||||||
|
|
||||||
|
int inBufferSize = 0;
|
||||||
|
_ = CredentialApis.CredPackAuthenticationBuffer(
|
||||||
|
0,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ref inBufferSize);
|
||||||
|
|
||||||
|
IntPtr inBuffer = Marshal.AllocCoTaskMem(inBufferSize);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!CredentialApis.CredPackAuthenticationBuffer(
|
||||||
|
0,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
inBuffer,
|
||||||
|
ref inBufferSize))
|
||||||
|
{
|
||||||
|
Throw.Win32Exception("Failed to pack auth buffer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
CredentialApis.CREDUI_INFO info = new CredentialApis.CREDUI_INFO
|
||||||
|
{
|
||||||
|
Size = Marshal.SizeOf(typeof(CredentialApis.CREDUI_INFO)),
|
||||||
|
CaptionText = "Windows Service Wrapper", // TODO
|
||||||
|
MessageText = "service account credentials", // TODO
|
||||||
|
};
|
||||||
|
uint authPackage = 0;
|
||||||
|
bool save = false;
|
||||||
|
int error = CredentialApis.CredUIPromptForWindowsCredentials(
|
||||||
|
info,
|
||||||
|
0,
|
||||||
|
ref authPackage,
|
||||||
|
inBuffer,
|
||||||
|
inBufferSize,
|
||||||
|
out IntPtr outBuffer,
|
||||||
|
out uint outBufferSize,
|
||||||
|
ref save,
|
||||||
|
CredentialApis.CREDUIWIN_GENERIC);
|
||||||
|
|
||||||
|
if (error != Errors.ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
throw new Win32Exception(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int userNameLength = 0;
|
||||||
|
int passwordLength = 0;
|
||||||
|
_ = CredentialApis.CredUnPackAuthenticationBuffer(
|
||||||
|
0,
|
||||||
|
outBuffer,
|
||||||
|
outBufferSize,
|
||||||
|
null,
|
||||||
|
ref userNameLength,
|
||||||
|
default,
|
||||||
|
default,
|
||||||
|
null,
|
||||||
|
ref passwordLength);
|
||||||
|
|
||||||
|
username = userNameLength == 0 ? null : new string('\0', userNameLength - 1);
|
||||||
|
password = passwordLength == 0 ? null : new string('\0', passwordLength - 1);
|
||||||
|
|
||||||
|
if (!CredentialApis.CredUnPackAuthenticationBuffer(
|
||||||
|
0,
|
||||||
|
outBuffer,
|
||||||
|
outBufferSize,
|
||||||
|
username,
|
||||||
|
ref userNameLength,
|
||||||
|
default,
|
||||||
|
default,
|
||||||
|
password,
|
||||||
|
ref passwordLength))
|
||||||
|
{
|
||||||
|
Throw.Win32Exception("Failed to unpack auth buffer.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeCoTaskMem(outBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeCoTaskMem(inBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PromptForCredentialsConsole()
|
||||||
|
{
|
||||||
|
if (username is null)
|
||||||
|
{
|
||||||
|
Console.Write("Username: ");
|
||||||
|
username = Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password is null)
|
||||||
|
{
|
||||||
|
Console.Write("Password: ");
|
||||||
|
password = ReadPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Uninstall()
|
void Uninstall()
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace winsw.Native
|
||||||
|
{
|
||||||
|
internal static class CredentialApis
|
||||||
|
{
|
||||||
|
internal const uint CREDUIWIN_GENERIC = 0x00000001;
|
||||||
|
|
||||||
|
[DllImport(Libraries.CredUI, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CredPackAuthenticationBufferW")]
|
||||||
|
internal static extern bool CredPackAuthenticationBuffer(
|
||||||
|
uint flags,
|
||||||
|
string userName,
|
||||||
|
string password,
|
||||||
|
IntPtr packedCredentials,
|
||||||
|
ref int packedCredentialsSize);
|
||||||
|
|
||||||
|
[DllImport(Libraries.CredUI, SetLastError = false, CharSet = CharSet.Unicode, EntryPoint = "CredUIPromptForWindowsCredentialsW")]
|
||||||
|
internal static extern int CredUIPromptForWindowsCredentials(
|
||||||
|
in CREDUI_INFO uiInfo,
|
||||||
|
uint authError,
|
||||||
|
ref uint authPackage,
|
||||||
|
IntPtr inAuthBuffer,
|
||||||
|
int inAuthBufferSize,
|
||||||
|
out IntPtr outAuthBuffer,
|
||||||
|
out uint outAuthBufferSize,
|
||||||
|
ref bool save,
|
||||||
|
uint flags);
|
||||||
|
|
||||||
|
[DllImport(Libraries.CredUI, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CredUnPackAuthenticationBufferW")]
|
||||||
|
internal static extern bool CredUnPackAuthenticationBuffer(
|
||||||
|
uint flags,
|
||||||
|
IntPtr authBuffer,
|
||||||
|
uint authBufferSize,
|
||||||
|
string? userName,
|
||||||
|
ref int maxUserName,
|
||||||
|
string? domainName,
|
||||||
|
IntPtr maxDomainName,
|
||||||
|
string? password,
|
||||||
|
ref int maxPassword);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
internal struct CREDUI_INFO
|
||||||
|
{
|
||||||
|
internal int Size;
|
||||||
|
internal IntPtr ParentWindow;
|
||||||
|
internal string MessageText;
|
||||||
|
internal string CaptionText;
|
||||||
|
internal IntPtr BannerBitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
{
|
{
|
||||||
internal static class Errors
|
internal static class Errors
|
||||||
{
|
{
|
||||||
|
internal const int ERROR_SUCCESS = 0;
|
||||||
internal const int ERROR_ACCESS_DENIED = 5;
|
internal const int ERROR_ACCESS_DENIED = 5;
|
||||||
internal const int ERROR_INVALID_HANDLE = 6;
|
internal const int ERROR_INVALID_HANDLE = 6;
|
||||||
internal const int ERROR_INVALID_PARAMETER = 7;
|
internal const int ERROR_INVALID_PARAMETER = 7;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
internal static class Libraries
|
internal static class Libraries
|
||||||
{
|
{
|
||||||
internal const string Advapi32 = "advapi32.dll";
|
internal const string Advapi32 = "advapi32.dll";
|
||||||
|
internal const string CredUI = "credui.dll";
|
||||||
internal const string Kernel32 = "kernel32.dll";
|
internal const string Kernel32 = "kernel32.dll";
|
||||||
internal const string NtDll = "ntdll.dll";
|
internal const string NtDll = "ntdll.dll";
|
||||||
}
|
}
|
||||||
|
|
|
@ -643,6 +643,8 @@ namespace winsw
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? ServiceAccountPrompt => GetServiceAccountPart("prompt")?.ToLowerInvariant();
|
||||||
|
|
||||||
protected string? AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
|
protected string? AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
|
||||||
|
|
||||||
public string? ServiceAccountPassword => GetServiceAccountPart("password");
|
public string? ServiceAccountPassword => GetServiceAccountPart("password");
|
||||||
|
@ -651,7 +653,7 @@ namespace winsw
|
||||||
|
|
||||||
public bool HasServiceAccount()
|
public bool HasServiceAccount()
|
||||||
{
|
{
|
||||||
return !string.IsNullOrEmpty(ServiceAccountUserName);
|
return this.dom.SelectSingleNode("//serviceaccount") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AllowServiceAcountLogonRight
|
public bool AllowServiceAcountLogonRight
|
||||||
|
|
Loading…
Reference in New Issue