github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cloudconfig/windowsuserdatafiles/Carbon.cs (about)

     1  /*
     2  Original sources available at: https://bitbucket.org/splatteredbits/carbon
     3  */
     4  
     5  using System;
     6  using System.Collections.Generic;
     7  using System.ComponentModel;
     8  using System.Runtime.InteropServices;
     9  using System.Security.Principal;
    10  using System.Text;
    11  
    12  namespace PSCarbon
    13  {
    14  	public sealed class Lsa
    15  	{
    16  		// ReSharper disable InconsistentNaming
    17  		[StructLayout(LayoutKind.Sequential)]
    18  		internal struct LSA_UNICODE_STRING
    19  		{
    20  			internal LSA_UNICODE_STRING(string inputString)
    21  			{
    22  				if (inputString == null)
    23  				{
    24  					Buffer = IntPtr.Zero;
    25  					Length = 0;
    26  					MaximumLength = 0;
    27  				}
    28  				else
    29  				{
    30  					Buffer = Marshal.StringToHGlobalAuto(inputString);
    31  					Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize);
    32  					MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize);
    33  				}
    34  			}
    35  
    36  			internal ushort Length;
    37  			internal ushort MaximumLength;
    38  			internal IntPtr Buffer;
    39  		}
    40  
    41  		[StructLayout(LayoutKind.Sequential)]
    42  		internal struct LSA_OBJECT_ATTRIBUTES
    43  		{
    44  			internal uint Length;
    45  			internal IntPtr RootDirectory;
    46  			internal LSA_UNICODE_STRING ObjectName;
    47  			internal uint Attributes;
    48  			internal IntPtr SecurityDescriptor;
    49  			internal IntPtr SecurityQualityOfService;
    50  		}
    51  
    52  		[StructLayout(LayoutKind.Sequential)]
    53  		public struct LUID
    54  		{
    55  			public uint LowPart;
    56  			public int HighPart;
    57  		}
    58  
    59  		// ReSharper disable UnusedMember.Local
    60  		private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001;
    61  		private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002;
    62  		private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004;
    63  		private const uint POLICY_TRUST_ADMIN = 0x00000008;
    64  		private const uint POLICY_CREATE_ACCOUNT = 0x00000010;
    65  		private const uint POLICY_CREATE_SECRET = 0x00000014;
    66  		private const uint POLICY_CREATE_PRIVILEGE = 0x00000040;
    67  		private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080;
    68  		private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100;
    69  		private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200;
    70  		private const uint POLICY_SERVER_ADMIN = 0x00000400;
    71  		private const uint POLICY_LOOKUP_NAMES = 0x00000800;
    72  		private const uint POLICY_NOTIFICATION = 0x00001000;
    73  		// ReSharper restore UnusedMember.Local
    74  
    75  		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    76  		public static extern bool LookupPrivilegeValue(
    77  			[MarshalAs(UnmanagedType.LPTStr)] string lpSystemName,
    78  			[MarshalAs(UnmanagedType.LPTStr)] string lpName,
    79  			out LUID lpLuid);
    80  
    81  		[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
    82  		private static extern uint LsaAddAccountRights(
    83  			IntPtr PolicyHandle,
    84  			IntPtr AccountSid,
    85  			LSA_UNICODE_STRING[] UserRights,
    86  			uint CountOfRights);
    87  
    88  		[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
    89  		private static extern uint LsaClose(IntPtr ObjectHandle);
    90  
    91  		[DllImport("advapi32.dll", SetLastError = true)]
    92  		private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle,
    93  			IntPtr AccountSid,
    94  			out IntPtr UserRights,
    95  			out uint CountOfRights
    96  			);
    97  
    98  		[DllImport("advapi32.dll", SetLastError = true)]
    99  		private static extern uint LsaFreeMemory(IntPtr pBuffer);
   100  
   101  		[DllImport("advapi32.dll")]
   102  		private static extern int LsaNtStatusToWinError(long status);
   103  
   104  		[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
   105  		private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle );
   106  
   107  		[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
   108  		static extern uint LsaRemoveAccountRights(
   109  			IntPtr PolicyHandle,
   110  			IntPtr AccountSid,
   111  			[MarshalAs(UnmanagedType.U1)]
   112  			bool AllRights,
   113  			LSA_UNICODE_STRING[] UserRights,
   114  			uint CountOfRights);
   115  		// ReSharper restore InconsistentNaming
   116  
   117  		private static IntPtr GetIdentitySid(string identity)
   118  		{
   119  			SecurityIdentifier sid =
   120  				new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier;
   121  			if (sid == null)
   122  			{
   123  				throw new ArgumentException(string.Format("Account {0} not found.", identity));
   124  			}
   125  			byte[] sidBytes = new byte[sid.BinaryLength];
   126  			sid.GetBinaryForm(sidBytes, 0);
   127  			System.IntPtr sidPtr = Marshal.AllocHGlobal(sidBytes.Length);
   128  			Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length);
   129  			return sidPtr;
   130  		}
   131  
   132  		private static IntPtr GetLsaPolicyHandle()
   133  		{
   134  			string computerName = Environment.MachineName;
   135  			IntPtr hPolicy;
   136  			LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES();
   137  			objectAttributes.Length = 0;
   138  			objectAttributes.RootDirectory = IntPtr.Zero;
   139  			objectAttributes.Attributes = 0;
   140  			objectAttributes.SecurityDescriptor = IntPtr.Zero;
   141  			objectAttributes.SecurityQualityOfService = IntPtr.Zero;
   142  
   143  			const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION;
   144  			LSA_UNICODE_STRING machineNameLsa = new LSA_UNICODE_STRING(computerName);
   145  			uint result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy);
   146  			HandleLsaResult(result);
   147  			return hPolicy;
   148  		}
   149  
   150  		public static string[] GetPrivileges(string identity)
   151  		{
   152  			IntPtr sidPtr = GetIdentitySid(identity);
   153  			IntPtr hPolicy = GetLsaPolicyHandle();
   154  			IntPtr rightsPtr = IntPtr.Zero;
   155  
   156  			try
   157  			{
   158  
   159  				List<string> privileges = new List<string>();
   160  
   161  				uint rightsCount;
   162  				uint result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount);
   163  				int win32ErrorCode = LsaNtStatusToWinError(result);
   164  				// the user has no privileges
   165  				if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND )
   166  				{
   167  					return new string[0];
   168  				}
   169  				HandleLsaResult(result);
   170  
   171  				LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING();
   172  				for (ulong i = 0; i < rightsCount; i++)
   173  				{
   174  					IntPtr itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus)));
   175  					myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType());
   176  					char[] cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize];
   177  					Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize);
   178  					string thisRight = new string(cvt);
   179  					privileges.Add(thisRight);
   180  				}
   181  				return privileges.ToArray();
   182  			}
   183  			finally
   184  			{
   185  				Marshal.FreeHGlobal(sidPtr);
   186  				uint result = LsaClose(hPolicy);
   187  				HandleLsaResult(result);
   188  				result = LsaFreeMemory(rightsPtr);
   189  				HandleLsaResult(result);
   190  			}
   191  		}
   192  
   193  		public static void GrantPrivileges(string identity, string[] privileges)
   194  		{
   195  			IntPtr sidPtr = GetIdentitySid(identity);
   196  			IntPtr hPolicy = GetLsaPolicyHandle();
   197  
   198  			try
   199  			{
   200  				LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges);
   201  				uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length);
   202  				HandleLsaResult(result);
   203  			}
   204  			finally
   205  			{
   206  				Marshal.FreeHGlobal(sidPtr);
   207  				uint result = LsaClose(hPolicy);
   208  				HandleLsaResult(result);
   209  			}
   210  		}
   211  
   212  		const int STATUS_SUCCESS = 0x0;
   213  		const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002;
   214  		const int STATUS_ACCESS_DENIED = 0x00000005;
   215  		const int STATUS_INVALID_HANDLE = 0x00000006;
   216  		const int STATUS_UNSUCCESSFUL = 0x0000001F;
   217  		const int STATUS_INVALID_PARAMETER = 0x00000057;
   218  		const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521;
   219  		const int STATUS_INVALID_SERVER_STATE = 0x00000548;
   220  		const int STATUS_INTERNAL_DB_ERROR = 0x00000567;
   221  		const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA;
   222  
   223  		private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>();
   224  		public Lsa () {
   225  			ErrorMessages.Add(STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation.");
   226  			ErrorMessages.Add(STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used.");
   227  			ErrorMessages.Add(STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure.");
   228  			ErrorMessages.Add(STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid.");
   229  			ErrorMessages.Add(STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist.");
   230  			ErrorMessages.Add(STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled.");
   231  			ErrorMessages.Add(STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency.");
   232  			ErrorMessages.Add(STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call.");
   233  			ErrorMessages.Add(STATUS_OBJECT_NAME_NOT_FOUND, "Object name not found. An object in the LSA policy database was not found. The object may have been specified either by SID or by name, depending on its type.");
   234  		}
   235  
   236  		private static void HandleLsaResult(uint returnCode)
   237  		{
   238  			int win32ErrorCode = LsaNtStatusToWinError(returnCode);
   239  
   240  			if( win32ErrorCode == STATUS_SUCCESS)
   241  				return;
   242  
   243  			if( ErrorMessages.ContainsKey(win32ErrorCode) )
   244  			{
   245  				throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]);
   246  			}
   247  
   248  			throw new Win32Exception(win32ErrorCode);
   249  		}
   250  
   251  		public static void RevokePrivileges(string identity, string[] privileges)
   252  		{
   253  			IntPtr sidPtr = GetIdentitySid(identity);
   254  			IntPtr hPolicy = GetLsaPolicyHandle();
   255  
   256  			try
   257  			{
   258  				string[] currentPrivileges = GetPrivileges(identity);
   259  				if (currentPrivileges.Length == 0)
   260  				{
   261  					return;
   262  				}
   263  				LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges);
   264  				uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length);
   265  				HandleLsaResult(result);
   266  			}
   267  			finally
   268  			{
   269  				Marshal.FreeHGlobal(sidPtr);
   270  				uint result = LsaClose(hPolicy);
   271  				HandleLsaResult(result);
   272  			}
   273  
   274  		}
   275  
   276  		private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges)
   277  		{
   278  			LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length];
   279  			for (int idx = 0; idx < privileges.Length; ++idx)
   280  			{
   281  				lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]);
   282  			}
   283  			return lsaPrivileges;
   284  		}
   285  	}
   286  }