mirror of https://github.com/winsw/winsw
				
				
				
			Allow prompting for credentials
							parent
							
								
									5efcc8aca5
								
							
						
					
					
						commit
						afe25d1d82
					
				| 
						 | 
				
			
			@ -207,13 +207,24 @@ namespace winsw
 | 
			
		|||
                        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;
 | 
			
		||||
                        password = descriptor.ServiceAccountPassword;
 | 
			
		||||
                        allowServiceLogonRight = descriptor.AllowServiceAcountLogonRight;
 | 
			
		||||
                        switch (descriptor.ServiceAccountPrompt)
 | 
			
		||||
                        {
 | 
			
		||||
                            case "dialog":
 | 
			
		||||
                                PropmtForCredentialsDialog();
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            case "console":
 | 
			
		||||
                                PromptForCredentialsConsole();
 | 
			
		||||
                                break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -257,6 +268,116 @@ namespace winsw
 | 
			
		|||
                {
 | 
			
		||||
                    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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 const int ERROR_SUCCESS = 0;
 | 
			
		||||
        internal const int ERROR_ACCESS_DENIED = 5;
 | 
			
		||||
        internal const int ERROR_INVALID_HANDLE = 6;
 | 
			
		||||
        internal const int ERROR_INVALID_PARAMETER = 7;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@
 | 
			
		|||
    internal static class Libraries
 | 
			
		||||
    {
 | 
			
		||||
        internal const string Advapi32 = "advapi32.dll";
 | 
			
		||||
        internal const string CredUI = "credui.dll";
 | 
			
		||||
        internal const string Kernel32 = "kernel32.dll";
 | 
			
		||||
        internal const string NtDll = "ntdll.dll";
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -643,6 +643,8 @@ namespace winsw
 | 
			
		|||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string? ServiceAccountPrompt => GetServiceAccountPart("prompt")?.ToLowerInvariant();
 | 
			
		||||
 | 
			
		||||
        protected string? AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
 | 
			
		||||
 | 
			
		||||
        public string? ServiceAccountPassword => GetServiceAccountPart("password");
 | 
			
		||||
| 
						 | 
				
			
			@ -651,7 +653,7 @@ namespace winsw
 | 
			
		|||
 | 
			
		||||
        public bool HasServiceAccount()
 | 
			
		||||
        {
 | 
			
		||||
            return !string.IsNullOrEmpty(ServiceAccountUserName);
 | 
			
		||||
            return this.dom.SelectSingleNode("//serviceaccount") != null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool AllowServiceAcountLogonRight
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue