using System; using System.Collections; using System.ComponentModel; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Text; namespace ZeroLevel.Services.AsService { public class ServiceProcessInstaller : ComponentInstaller { private ServiceAccount serviceAccount = ServiceAccount.User; private bool haveLoginInfo; private string password; private string username; private static bool helpPrinted; /// Gets help text displayed for service installation options. /// Help text that provides a description of the steps for setting the user name and password in order to run the service under a particular account. /// /// /// public override string HelpText { get { if (ServiceProcessInstaller.helpPrinted) { return base.HelpText; } ServiceProcessInstaller.helpPrinted = true; return Res.GetString("HelpText") + "\r\n" + base.HelpText; } } /// Gets or sets the password associated with the user account under which the service application runs. /// The password associated with the account under which the service should run. The default is an empty string (""). The property is not public, and is never serialized. /// /// /// /// /// /// /// [Browsable(false)] public string Password { get { if (!this.haveLoginInfo) { this.GetLoginInfo(); } return this.password; } set { this.haveLoginInfo = false; this.password = value; } } /// Gets or sets the type of account under which to run this service application. /// A that defines the type of account under which the system runs this service. The default is User. /// /// /// /// /// /// /// [DefaultValue(ServiceAccount.User)] [ServiceProcessDescription("ServiceProcessInstallerAccount")] public ServiceAccount Account { get { if (!this.haveLoginInfo) { this.GetLoginInfo(); } return this.serviceAccount; } set { this.haveLoginInfo = false; this.serviceAccount = value; } } /// Gets or sets the user account under which the service application will run. /// The account under which the service should run. The default is an empty string (""). /// /// /// /// /// /// /// [TypeConverter("System.Diagnostics.Design.StringValueConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] [Browsable(false)] public string Username { get { if (!this.haveLoginInfo) { this.GetLoginInfo(); } return this.username; } set { this.haveLoginInfo = false; this.username = value; } } private static bool AccountHasRight(IntPtr policyHandle, byte[] accountSid, string rightName) { IntPtr intPtr = (IntPtr)0; int num = 0; int num2 = NativeMethods.LsaEnumerateAccountRights(policyHandle, accountSid, out intPtr, out num); switch (num2) { case -1073741772: return false; default: throw new Win32Exception(SafeNativeMethods.LsaNtStatusToWinError(num2)); case 0: { bool result = false; try { IntPtr intPtr2 = intPtr; for (int i = 0; i < num; i++) { NativeMethods.LSA_UNICODE_STRING_withPointer lSA_UNICODE_STRING_withPointer = new NativeMethods.LSA_UNICODE_STRING_withPointer(); Marshal.PtrToStructure(intPtr2, (object)lSA_UNICODE_STRING_withPointer); char[] array = new char[lSA_UNICODE_STRING_withPointer.length / 2]; Marshal.Copy(lSA_UNICODE_STRING_withPointer.pwstr, array, 0, array.Length); if (string.Compare(new string(array, 0, array.Length), rightName, StringComparison.Ordinal) == 0) { return true; } intPtr2 = (IntPtr)((long)intPtr2 + Marshal.SizeOf(typeof(NativeMethods.LSA_UNICODE_STRING))); } return result; } finally { SafeNativeMethods.LsaFreeMemory(intPtr); } } } } /// Implements the base class method with no class-specific behavior. /// The that represents the service process. public override void CopyFromComponent(IComponent comp) { } private byte[] GetAccountSid(string accountName) { byte[] array = new byte[256]; int[] array2 = new int[1] { array.Length }; char[] array3 = new char[1024]; int[] domNameLen = new int[1] { array3.Length }; int[] sidNameUse = new int[1]; if (accountName.Substring(0, 2) == ".\\") { StringBuilder stringBuilder = new StringBuilder(32); int num = 32; if (!NativeMethods.GetComputerName(stringBuilder, ref num)) { throw new Win32Exception(); } accountName = stringBuilder + accountName.Substring(1); } if (!NativeMethods.LookupAccountName(null, accountName, array, array2, array3, domNameLen, sidNameUse)) { throw new Win32Exception(); } byte[] array4 = new byte[array2[0]]; Array.Copy(array, 0, array4, 0, array2[0]); return array4; } private void GetLoginInfo() { if (base.Context != null && !base.DesignMode && !this.haveLoginInfo) { this.haveLoginInfo = true; if (this.serviceAccount != ServiceAccount.User) { return; } if (base.Context.Parameters.ContainsKey("username")) { this.username = base.Context.Parameters["username"]; } if (base.Context.Parameters.ContainsKey("password")) { this.password = base.Context.Parameters["password"]; } if (this.username != null && this.username.Length != 0 && this.password != null) { return; } if (!base.Context.Parameters.ContainsKey("unattended")) { throw new PlatformNotSupportedException(); } throw new InvalidOperationException(Res.GetString("UnattendedCannotPrompt", base.Context.Parameters["assemblypath"])); } } private static void GrantAccountRight(IntPtr policyHandle, byte[] accountSid, string rightName) { NativeMethods.LSA_UNICODE_STRING lSA_UNICODE_STRING = new NativeMethods.LSA_UNICODE_STRING(); lSA_UNICODE_STRING.buffer = rightName; NativeMethods.LSA_UNICODE_STRING lSA_UNICODE_STRING2 = lSA_UNICODE_STRING; lSA_UNICODE_STRING2.length = (short)(lSA_UNICODE_STRING2.buffer.Length * 2); NativeMethods.LSA_UNICODE_STRING lSA_UNICODE_STRING3 = lSA_UNICODE_STRING; lSA_UNICODE_STRING3.maximumLength = lSA_UNICODE_STRING3.length; int num = NativeMethods.LsaAddAccountRights(policyHandle, accountSid, lSA_UNICODE_STRING, 1); if (num == 0) { return; } throw new Win32Exception(SafeNativeMethods.LsaNtStatusToWinError(num)); } /// Writes service application information to the registry. This method is meant to be used by installation tools, which call the appropriate methods automatically. /// An that contains the context information associated with the installation. /// The is null. /// /// /// /// public override void Install(IDictionary stateSaver) { try { ServiceInstaller.CheckEnvironment(); try { if (!this.haveLoginInfo) { try { this.GetLoginInfo(); } catch { stateSaver["hadServiceLogonRight"] = true; throw; } } } finally { stateSaver["Account"] = this.Account; if (this.Account == ServiceAccount.User) { stateSaver["Username"] = this.Username; } } if (this.Account == ServiceAccount.User) { IntPtr intPtr = this.OpenSecurityPolicy(); bool flag = true; try { byte[] accountSid = this.GetAccountSid(this.Username); flag = ServiceProcessInstaller.AccountHasRight(intPtr, accountSid, "SeServiceLogonRight"); if (!flag) { ServiceProcessInstaller.GrantAccountRight(intPtr, accountSid, "SeServiceLogonRight"); } } finally { stateSaver["hadServiceLogonRight"] = flag; SafeNativeMethods.LsaClose(intPtr); } } } finally { base.Install(stateSaver); } } private IntPtr OpenSecurityPolicy() { GCHandle gCHandle = GCHandle.Alloc(new NativeMethods.LSA_OBJECT_ATTRIBUTES(), GCHandleType.Pinned); try { int num = 0; IntPtr pointerObjectAttributes = gCHandle.AddrOfPinnedObject(); IntPtr result = default(IntPtr); num = NativeMethods.LsaOpenPolicy((NativeMethods.LSA_UNICODE_STRING)null, pointerObjectAttributes, 2064, out result); if (num != 0) { throw new Win32Exception(SafeNativeMethods.LsaNtStatusToWinError(num)); } return result; } finally { gCHandle.Free(); } } private static void RemoveAccountRight(IntPtr policyHandle, byte[] accountSid, string rightName) { NativeMethods.LSA_UNICODE_STRING lSA_UNICODE_STRING = new NativeMethods.LSA_UNICODE_STRING(); lSA_UNICODE_STRING.buffer = rightName; NativeMethods.LSA_UNICODE_STRING lSA_UNICODE_STRING2 = lSA_UNICODE_STRING; lSA_UNICODE_STRING2.length = (short)(lSA_UNICODE_STRING2.buffer.Length * 2); NativeMethods.LSA_UNICODE_STRING lSA_UNICODE_STRING3 = lSA_UNICODE_STRING; lSA_UNICODE_STRING3.maximumLength = lSA_UNICODE_STRING3.length; int num = NativeMethods.LsaRemoveAccountRights(policyHandle, accountSid, false, lSA_UNICODE_STRING, 1); if (num == 0) { return; } throw new Win32Exception(SafeNativeMethods.LsaNtStatusToWinError(num)); } /// Rolls back service application information written to the registry by the installation procedure. This method is meant to be used by installation tools, which process the appropriate methods automatically. /// An that contains the context information associated with the installation. /// The is null.-or- The is corrupted or non-existent. /// /// /// public override void Rollback(IDictionary savedState) { try { if ((ServiceAccount)savedState["Account"] == ServiceAccount.User && !(bool)savedState["hadServiceLogonRight"]) { string accountName = (string)savedState["Username"]; IntPtr intPtr = this.OpenSecurityPolicy(); try { byte[] accountSid = this.GetAccountSid(accountName); ServiceProcessInstaller.RemoveAccountRight(intPtr, accountSid, "SeServiceLogonRight"); } finally { SafeNativeMethods.LsaClose(intPtr); } } } finally { base.Rollback(savedState); } } } }