/Source/Service/ServiceSecurity.cs

https://bitbucket.org/splatteredbits/carbon · C# · 102 lines · 74 code · 13 blank · 15 comment · 5 complexity · 59d68a7ff914288a5811fc30f149316f MD5 · raw file

  1. // Licensed under the Apache License, Version 2.0 (the "License");
  2. // you may not use this file except in compliance with the License.
  3. // You may obtain a copy of the License at
  4. //
  5. // http://www.apache.org/licenses/LICENSE-2.0
  6. //
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS,
  9. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. // See the License for the specific language governing permissions and
  11. // limitations under the License.
  12. using System.Collections.Generic;
  13. using System.ComponentModel;
  14. using System.Runtime.InteropServices;
  15. using System.Security.AccessControl;
  16. using System.ServiceProcess;
  17. using Carbon.Win32;
  18. namespace Carbon.Service
  19. {
  20. public sealed class ServiceSecurity
  21. {
  22. // ReSharper disable InconsistentNaming
  23. [DllImport("advapi32.dll", SetLastError = true)]
  24. private static extern bool QueryServiceObjectSecurity(SafeHandle serviceHandle, SecurityInfos secInfo,
  25. byte[] lpSecDesrBuf, uint bufSize, out uint bufSizeNeeded);
  26. [DllImport("advapi32.dll", SetLastError = true)]
  27. private static extern bool SetServiceObjectSecurity(SafeHandle serviceHandle, SecurityInfos secInfos, byte[] lpSecDesrBuf);
  28. // ReSharper restore InconsistentNaming
  29. // http://msdn.microsoft.com/en-us/library/cc231199.aspx
  30. private static readonly Dictionary<int, string> QueryServiceObjectSecurityReturnCodes =
  31. new Dictionary<int, string>
  32. {
  33. { Win32ErrorCodes.AccessDenied, "Access denied. The specified handle was not opened with READ_CONTROL access, or the calling process is not the owner of the object." },
  34. { Win32ErrorCodes.InvalidHandle, "Invalid handle. The specified handle is not valid."},
  35. { Win32ErrorCodes.InvalidParameter, "Invalid Parameter. The specified security information is not valid." },
  36. { Win32ErrorCodes.InvalidFlags, "Invalid flags." }
  37. };
  38. public static byte[] GetServiceSecurityDescriptor(string serviceName)
  39. {
  40. var sc = new ServiceController(serviceName);
  41. var sdBytes = new byte[0];
  42. uint bufSizeNeeded;
  43. var ok = QueryServiceObjectSecurity(sc.ServiceHandle,
  44. SecurityInfos.DiscretionaryAcl,
  45. sdBytes,
  46. 0,
  47. out bufSizeNeeded);
  48. if (!ok)
  49. {
  50. var errorCode = Marshal.GetLastWin32Error();
  51. if (errorCode == Win32ErrorCodes.InsufficientBuffer)
  52. {
  53. // expected; now we know bufsize
  54. sdBytes = new byte[bufSizeNeeded];
  55. ok = QueryServiceObjectSecurity(sc.ServiceHandle,
  56. SecurityInfos.DiscretionaryAcl,
  57. sdBytes,
  58. bufSizeNeeded,
  59. out bufSizeNeeded);
  60. }
  61. }
  62. HandleWin32Bool(ok, QueryServiceObjectSecurityReturnCodes);
  63. return sdBytes;
  64. }
  65. private static readonly Dictionary<int,string> SetServiceObjectSecurityReturnCodes = new Dictionary<int, string>
  66. {
  67. { Win32ErrorCodes.AccessDenied, "Access denied. The specified handle was not opened with the required access, or the calling process is not the owner of the object." },
  68. { Win32ErrorCodes.InvalidHandle, "Invalid handle. The specified handle is not valid." },
  69. { Win32ErrorCodes.InvalidParameter, "Invalid Parameter. The specified security information or security descriptor is not valid." },
  70. { Win32ErrorCodes.ServiceMarkedForDelete, "Service marked for delete. The specified service has been marked for deletion." }
  71. };
  72. public static void SetServiceSecurityDescriptor(string serviceName, byte[] sdBytes)
  73. {
  74. var sc = new ServiceController(serviceName);
  75. var ok = SetServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, sdBytes);
  76. HandleWin32Bool(ok, SetServiceObjectSecurityReturnCodes);
  77. }
  78. private static void HandleWin32Bool(bool ok, IDictionary<int, string> errorMessageMap )
  79. {
  80. if (ok) return;
  81. var errorCode = Marshal.GetLastWin32Error();
  82. if( errorMessageMap.ContainsKey(errorCode) )
  83. {
  84. throw new Win32Exception(errorCode, errorMessageMap[errorCode]);
  85. }
  86. throw new Win32Exception(errorCode);
  87. }
  88. }
  89. }