github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cloudconfig/windows_userdata_test.go (about) 1 // Copyright 2014, 2015 Canonical Ltd. 2 // Copyright 2014, 2015 Cloudbase Solutions 3 // Copyright 2012 Aaron Jensen 4 // 5 // Licensed under the AGPLv3, see LICENCE file for details. 6 // 7 // This file borrowed some code from https://bitbucket.org/splatteredbits/carbon 8 // (see Source/Security/Privilege.cs). This external source is licensed under 9 // Apache-2.0 license which is compatible with AGPLv3 license. Because it's 10 // compatible we can and have licensed this derived work under AGPLv3. The original 11 // Apache-2.0 license for the external source can be found inside Apache-License.txt. 12 // Copyright statement of the external source: Copyright 2012 Aaron Jensen 13 14 package cloudconfig_test 15 16 var WindowsUserdata = `#ps1_sysnative 17 18 19 20 $ErrorActionPreference = "Stop" 21 22 function ExecRetry($command, $retryInterval = 15) 23 { 24 $currErrorActionPreference = $ErrorActionPreference 25 $ErrorActionPreference = "Continue" 26 27 while ($true) 28 { 29 try 30 { 31 & $command 32 break 33 } 34 catch [System.Exception] 35 { 36 Write-Error $_.Exception 37 Start-Sleep $retryInterval 38 } 39 } 40 41 $ErrorActionPreference = $currErrorActionPreference 42 } 43 44 # TryExecAll attempts all of the commands in the supplied array until 45 # one can be executed without throwing an exception. If none of the 46 # commands succeeds, an exception will be raised. 47 function TryExecAll($commands) 48 { 49 $currErrorActionPreference = $ErrorActionPreference 50 $ErrorActionPreference = "Continue" 51 52 foreach ($command in $commands) 53 { 54 try 55 { 56 & $command 57 $ErrorActionPreference = $currErrorActionPreference 58 return 59 } 60 catch [System.Exception] 61 { 62 Write-Error $_.Exception 63 } 64 } 65 66 $ErrorActionPreference = $currErrorActionPreference 67 throw "All commands failed" 68 } 69 70 Function GUnZip-File{ 71 Param( 72 $infile, 73 $outdir 74 ) 75 76 $input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) 77 $tempFile = "$env:TEMP\jujud.tar" 78 $tempOut = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None) 79 $gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress) 80 81 $buffer = New-Object byte[](1024) 82 while($true) { 83 $read = $gzipstream.Read($buffer, 0, 1024) 84 if ($read -le 0){break} 85 $tempOut.Write($buffer, 0, $read) 86 } 87 $gzipStream.Close() 88 $tempOut.Close() 89 $input.Close() 90 91 $in = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) 92 Untar-File $in $outdir 93 $in.Close() 94 rm $tempFile 95 } 96 97 $HEADERSIZE = 512 98 99 Function Untar-File { 100 Param( 101 $inStream, 102 $outdir 103 ) 104 $DirectoryEntryType = 0x35 105 $headerBytes = New-Object byte[]($HEADERSIZE) 106 107 # $headerBytes is written inside, function returns whether we've reached the end 108 while(GetHeaderBytes $inStream $headerBytes) { 109 $fileName, $entryType, $sizeInBytes = GetFileInfoFromHeader $headerBytes 110 111 $totalPath = Join-Path $outDir $fileName 112 if ($entryType -eq $DirectoryEntryType) { 113 [System.IO.Directory]::CreateDirectory($totalPath) 114 continue; 115 } 116 117 $fName = [System.IO.Path]::GetFileName($totalPath) 118 $dirName = [System.IO.Path]::GetDirectoryName($totalPath) 119 [System.IO.Directory]::CreateDirectory($dirName) 120 $file = [System.IO.File]::Create($totalPath) 121 WriteTarEntryToFile $inStream $file $sizeInBytes 122 $file.Close() 123 } 124 } 125 126 Function WriteTarEntryToFile { 127 Param( 128 $inStream, 129 $outFile, 130 $sizeInBytes 131 ) 132 $moveToAlign512 = 0 133 $toRead = 0 134 $buf = New-Object byte[](512) 135 136 $remainingBytesInFile = $sizeInBytes 137 while ($remainingBytesInFile -ne 0) { 138 if ($remainingBytesInFile - 512 -lt 0) { 139 $moveToAlign512 = 512 - $remainingBytesInFile 140 $toRead = $remainingBytesInFile 141 } else { 142 $toRead = 512 143 } 144 145 $bytesRead = 0 146 $bytesRemainingToRead = $toRead 147 while ($bytesRead -lt $toRead -and $bytesRemainingToRead -gt 0) { 148 $bytesRead = $inStream.Read($buf, $toRead - $bytesRemainingToRead, $bytesRemainingToRead) 149 $bytesRemainingToRead = $bytesRemainingToRead - $bytesRead 150 $remainingBytesInFile = $remainingBytesInFile - $bytesRead 151 $outFile.Write($buf, 0, $bytesRead) 152 } 153 154 if ($moveToAlign512 -ne 0) { 155 $inStream.Seek($moveToAlign512, [System.IO.SeekOrigin]::Current) 156 } 157 } 158 } 159 160 Function GetHeaderBytes { 161 Param($inStream, $headerBytes) 162 163 $headerRead = 0 164 $bytesRemaining = $HEADERSIZE 165 while ($bytesRemaining -gt 0) { 166 $headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining) 167 $bytesRemaining -= $headerRead 168 if ($headerRead -le 0 -and $bytesRemaining -gt 0) { 169 throw "Error reading tar header. Header size invalid" 170 } 171 } 172 173 # Proper end of archive is 2 empty headers 174 if (IsEmptyByteArray $headerBytes) { 175 $bytesRemaining = $HEADERSIZE 176 while ($bytesRemaining -gt 0) { 177 $headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining) 178 $bytesRemaining -= $headerRead 179 if ($headerRead -le 0 -and $bytesRemaining -gt 0) { 180 throw "Broken end archive" 181 } 182 } 183 if ($bytesRemaining -eq 0 -and (IsEmptyByteArray($headerBytes))) { 184 return $false 185 } 186 throw "Error occurred: expected end of archive" 187 } 188 189 return $true 190 } 191 192 Function GetFileInfoFromHeader { 193 Param($headerBytes) 194 195 $FileName = [System.Text.Encoding]::UTF8.GetString($headerBytes, 0, 100); 196 $EntryType = $headerBytes[156]; 197 $SizeInBytes = [Convert]::ToInt64([System.Text.Encoding]::ASCII.GetString($headerBytes, 124, 11).Trim(), 8); 198 Return $FileName.replace("` + "`" + `0", [String].Empty), $EntryType, $SizeInBytes 199 } 200 201 Function IsEmptyByteArray { 202 Param ($bytes) 203 foreach($b in $bytes) { 204 if ($b -ne 0) { 205 return $false 206 } 207 } 208 return $true 209 } 210 211 Function Get-FileSHA256{ 212 Param( 213 $FilePath 214 ) 215 try { 216 $hash = [Security.Cryptography.HashAlgorithm]::Create( "SHA256" ) 217 $stream = ([IO.StreamReader]$FilePath).BaseStream 218 $res = -join ($hash.ComputeHash($stream) | ForEach { "{0:x2}" -f $_ }) 219 $stream.Close() 220 return $res 221 } catch [System.Management.Automation.RuntimeException] { 222 return (Get-FileHash -Path $FilePath).Hash 223 } 224 } 225 226 Function Invoke-FastWebRequest { 227 Param( 228 $URI, 229 $OutFile 230 ) 231 232 if(!([System.Management.Automation.PSTypeName]'System.Net.Http.HttpClient').Type) 233 { 234 $assembly = [System.Reflection.Assembly]::LoadWithPartialName("System.Net.Http") 235 } 236 237 $client = new-object System.Net.Http.HttpClient 238 239 $task = $client.GetStreamAsync($URI) 240 $response = $task.Result 241 $outStream = New-Object IO.FileStream $OutFile, Create, Write, None 242 243 try { 244 $totRead = 0 245 $buffer = New-Object Byte[] 1MB 246 while (($read = $response.Read($buffer, 0, $buffer.Length)) -gt 0) { 247 $totRead += $read 248 $outStream.Write($buffer, 0, $read); 249 } 250 } 251 finally { 252 $outStream.Close() 253 } 254 } 255 256 257 258 function create-account ([string]$accountName, [string]$accountDescription, [string]$password) { 259 $hostname = hostname 260 $comp = [adsi]"WinNT://$hostname" 261 $user = $comp.Create("User", $accountName) 262 $user.SetPassword($password) 263 $user.SetInfo() 264 $user.description = $accountDescription 265 $user.SetInfo() 266 $User.UserFlags[0] = $User.UserFlags[0] -bor 0x10000 267 $user.SetInfo() 268 269 # This gets the Administrator group name that is localized on different windows versions. 270 # However the SID S-1-5-32-544 is the same on all versions. 271 $adminGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value.Split("\")[1] 272 273 $objOU = [ADSI]"WinNT://$hostname/$adminGroup,group" 274 $objOU.add("WinNT://$hostname/$accountName") 275 } 276 277 $Source = @" 278 using System; 279 using System.Text; 280 using System.Runtime.InteropServices; 281 282 namespace PSCloudbase 283 { 284 public sealed class Win32CryptApi 285 { 286 public static long CRYPT_SILENT = 0x00000040; 287 public static long CRYPT_VERIFYCONTEXT = 0xF0000000; 288 public static int PROV_RSA_FULL = 1; 289 290 [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 291 [return : MarshalAs(UnmanagedType.Bool)] 292 public static extern bool CryptAcquireContext(ref IntPtr hProv, 293 StringBuilder pszContainer, // Don't use string, as Powershell replaces $null with an empty string 294 StringBuilder pszProvider, // Don't use string, as Powershell replaces $null with an empty string 295 uint dwProvType, 296 uint dwFlags); 297 298 [DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)] 299 public static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); 300 301 [DllImport("advapi32.dll", SetLastError=true)] 302 public static extern bool CryptGenRandom(IntPtr hProv, uint dwLen, byte[] pbBuffer); 303 304 [DllImport("Kernel32.dll")] 305 public static extern uint GetLastError(); 306 } 307 } 308 "@ 309 310 Add-Type -TypeDefinition $Source -Language CSharp 311 312 function Get-RandomPassword 313 { 314 [CmdletBinding()] 315 param 316 ( 317 [parameter(Mandatory=$true)] 318 [int]$Length 319 ) 320 process 321 { 322 $hProvider = 0 323 try 324 { 325 if(![PSCloudbase.Win32CryptApi]::CryptAcquireContext([ref]$hProvider, $null, $null, 326 [PSCloudbase.Win32CryptApi]::PROV_RSA_FULL, 327 ([PSCloudbase.Win32CryptApi]::CRYPT_VERIFYCONTEXT -bor 328 [PSCloudbase.Win32CryptApi]::CRYPT_SILENT))) 329 { 330 throw "CryptAcquireContext failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError() 331 } 332 333 $buffer = New-Object byte[] $Length 334 if(![PSCloudbase.Win32CryptApi]::CryptGenRandom($hProvider, $Length, $buffer)) 335 { 336 throw "CryptGenRandom failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError() 337 } 338 339 $buffer | ForEach-Object { $password += "{0:X0}" -f $_ } 340 return $password 341 } 342 finally 343 { 344 if($hProvider) 345 { 346 $retVal = [PSCloudbase.Win32CryptApi]::CryptReleaseContext($hProvider, 0) 347 } 348 } 349 } 350 } 351 $SourcePolicy = @" 352 /* 353 Original sources available at: https://bitbucket.org/splatteredbits/carbon 354 */ 355 356 using System; 357 using System.Collections.Generic; 358 using System.ComponentModel; 359 using System.Runtime.InteropServices; 360 using System.Security.Principal; 361 using System.Text; 362 363 namespace PSCarbon 364 { 365 public sealed class Lsa 366 { 367 // ReSharper disable InconsistentNaming 368 [StructLayout(LayoutKind.Sequential)] 369 internal struct LSA_UNICODE_STRING 370 { 371 internal LSA_UNICODE_STRING(string inputString) 372 { 373 if (inputString == null) 374 { 375 Buffer = IntPtr.Zero; 376 Length = 0; 377 MaximumLength = 0; 378 } 379 else 380 { 381 Buffer = Marshal.StringToHGlobalAuto(inputString); 382 Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); 383 MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); 384 } 385 } 386 387 internal ushort Length; 388 internal ushort MaximumLength; 389 internal IntPtr Buffer; 390 } 391 392 [StructLayout(LayoutKind.Sequential)] 393 internal struct LSA_OBJECT_ATTRIBUTES 394 { 395 internal uint Length; 396 internal IntPtr RootDirectory; 397 internal LSA_UNICODE_STRING ObjectName; 398 internal uint Attributes; 399 internal IntPtr SecurityDescriptor; 400 internal IntPtr SecurityQualityOfService; 401 } 402 403 [StructLayout(LayoutKind.Sequential)] 404 public struct LUID 405 { 406 public uint LowPart; 407 public int HighPart; 408 } 409 410 // ReSharper disable UnusedMember.Local 411 private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001; 412 private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002; 413 private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004; 414 private const uint POLICY_TRUST_ADMIN = 0x00000008; 415 private const uint POLICY_CREATE_ACCOUNT = 0x00000010; 416 private const uint POLICY_CREATE_SECRET = 0x00000014; 417 private const uint POLICY_CREATE_PRIVILEGE = 0x00000040; 418 private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080; 419 private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100; 420 private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200; 421 private const uint POLICY_SERVER_ADMIN = 0x00000400; 422 private const uint POLICY_LOOKUP_NAMES = 0x00000800; 423 private const uint POLICY_NOTIFICATION = 0x00001000; 424 // ReSharper restore UnusedMember.Local 425 426 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 427 public static extern bool LookupPrivilegeValue( 428 [MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, 429 [MarshalAs(UnmanagedType.LPTStr)] string lpName, 430 out LUID lpLuid); 431 432 [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] 433 private static extern uint LsaAddAccountRights( 434 IntPtr PolicyHandle, 435 IntPtr AccountSid, 436 LSA_UNICODE_STRING[] UserRights, 437 uint CountOfRights); 438 439 [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)] 440 private static extern uint LsaClose(IntPtr ObjectHandle); 441 442 [DllImport("advapi32.dll", SetLastError = true)] 443 private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle, 444 IntPtr AccountSid, 445 out IntPtr UserRights, 446 out uint CountOfRights 447 ); 448 449 [DllImport("advapi32.dll", SetLastError = true)] 450 private static extern uint LsaFreeMemory(IntPtr pBuffer); 451 452 [DllImport("advapi32.dll")] 453 private static extern int LsaNtStatusToWinError(long status); 454 455 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 456 private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle ); 457 458 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 459 static extern uint LsaRemoveAccountRights( 460 IntPtr PolicyHandle, 461 IntPtr AccountSid, 462 [MarshalAs(UnmanagedType.U1)] 463 bool AllRights, 464 LSA_UNICODE_STRING[] UserRights, 465 uint CountOfRights); 466 // ReSharper restore InconsistentNaming 467 468 private static IntPtr GetIdentitySid(string identity) 469 { 470 SecurityIdentifier sid = 471 new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier; 472 if (sid == null) 473 { 474 throw new ArgumentException(string.Format("Account {0} not found.", identity)); 475 } 476 byte[] sidBytes = new byte[sid.BinaryLength]; 477 sid.GetBinaryForm(sidBytes, 0); 478 System.IntPtr sidPtr = Marshal.AllocHGlobal(sidBytes.Length); 479 Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); 480 return sidPtr; 481 } 482 483 private static IntPtr GetLsaPolicyHandle() 484 { 485 string computerName = Environment.MachineName; 486 IntPtr hPolicy; 487 LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES(); 488 objectAttributes.Length = 0; 489 objectAttributes.RootDirectory = IntPtr.Zero; 490 objectAttributes.Attributes = 0; 491 objectAttributes.SecurityDescriptor = IntPtr.Zero; 492 objectAttributes.SecurityQualityOfService = IntPtr.Zero; 493 494 const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION; 495 LSA_UNICODE_STRING machineNameLsa = new LSA_UNICODE_STRING(computerName); 496 uint result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy); 497 HandleLsaResult(result); 498 return hPolicy; 499 } 500 501 public static string[] GetPrivileges(string identity) 502 { 503 IntPtr sidPtr = GetIdentitySid(identity); 504 IntPtr hPolicy = GetLsaPolicyHandle(); 505 IntPtr rightsPtr = IntPtr.Zero; 506 507 try 508 { 509 510 List<string> privileges = new List<string>(); 511 512 uint rightsCount; 513 uint result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount); 514 int win32ErrorCode = LsaNtStatusToWinError(result); 515 // the user has no privileges 516 if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND ) 517 { 518 return new string[0]; 519 } 520 HandleLsaResult(result); 521 522 LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING(); 523 for (ulong i = 0; i < rightsCount; i++) 524 { 525 IntPtr itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus))); 526 myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType()); 527 char[] cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize]; 528 Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize); 529 string thisRight = new string(cvt); 530 privileges.Add(thisRight); 531 } 532 return privileges.ToArray(); 533 } 534 finally 535 { 536 Marshal.FreeHGlobal(sidPtr); 537 uint result = LsaClose(hPolicy); 538 HandleLsaResult(result); 539 result = LsaFreeMemory(rightsPtr); 540 HandleLsaResult(result); 541 } 542 } 543 544 public static void GrantPrivileges(string identity, string[] privileges) 545 { 546 IntPtr sidPtr = GetIdentitySid(identity); 547 IntPtr hPolicy = GetLsaPolicyHandle(); 548 549 try 550 { 551 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 552 uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length); 553 HandleLsaResult(result); 554 } 555 finally 556 { 557 Marshal.FreeHGlobal(sidPtr); 558 uint result = LsaClose(hPolicy); 559 HandleLsaResult(result); 560 } 561 } 562 563 const int STATUS_SUCCESS = 0x0; 564 const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002; 565 const int STATUS_ACCESS_DENIED = 0x00000005; 566 const int STATUS_INVALID_HANDLE = 0x00000006; 567 const int STATUS_UNSUCCESSFUL = 0x0000001F; 568 const int STATUS_INVALID_PARAMETER = 0x00000057; 569 const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521; 570 const int STATUS_INVALID_SERVER_STATE = 0x00000548; 571 const int STATUS_INTERNAL_DB_ERROR = 0x00000567; 572 const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA; 573 574 private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>(); 575 public Lsa () { 576 ErrorMessages.Add(STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation."); 577 ErrorMessages.Add(STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used."); 578 ErrorMessages.Add(STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure."); 579 ErrorMessages.Add(STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid."); 580 ErrorMessages.Add(STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist."); 581 ErrorMessages.Add(STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled."); 582 ErrorMessages.Add(STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency."); 583 ErrorMessages.Add(STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call."); 584 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."); 585 } 586 587 private static void HandleLsaResult(uint returnCode) 588 { 589 int win32ErrorCode = LsaNtStatusToWinError(returnCode); 590 591 if( win32ErrorCode == STATUS_SUCCESS) 592 return; 593 594 if( ErrorMessages.ContainsKey(win32ErrorCode) ) 595 { 596 throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]); 597 } 598 599 throw new Win32Exception(win32ErrorCode); 600 } 601 602 public static void RevokePrivileges(string identity, string[] privileges) 603 { 604 IntPtr sidPtr = GetIdentitySid(identity); 605 IntPtr hPolicy = GetLsaPolicyHandle(); 606 607 try 608 { 609 string[] currentPrivileges = GetPrivileges(identity); 610 if (currentPrivileges.Length == 0) 611 { 612 return; 613 } 614 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 615 uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length); 616 HandleLsaResult(result); 617 } 618 finally 619 { 620 Marshal.FreeHGlobal(sidPtr); 621 uint result = LsaClose(hPolicy); 622 HandleLsaResult(result); 623 } 624 625 } 626 627 private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges) 628 { 629 LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length]; 630 for (int idx = 0; idx < privileges.Length; ++idx) 631 { 632 lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]); 633 } 634 return lsaPrivileges; 635 } 636 } 637 } 638 "@ 639 Add-Type -TypeDefinition $SourcePolicy -Language CSharp 640 641 function SetAssignPrimaryTokenPrivilege($UserName) 642 { 643 $privilege = "SeAssignPrimaryTokenPrivilege" 644 if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -contains $privilege)) 645 { 646 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 647 } 648 } 649 650 function SetUserLogonAsServiceRights($UserName) 651 { 652 $privilege = "SeServiceLogonRight" 653 if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -Contains $privilege)) 654 { 655 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 656 } 657 } 658 function Test-RegistryValue { 659 param ([parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Path, 660 [parameter(Mandatory=$true)] 661 [ValidateNotNullOrEmpty()]$Value) 662 try { 663 Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null 664 return $true 665 }catch {return $false} 666 } 667 $juju_passwd = Get-RandomPassword 20 668 $juju_passwd += "^" 669 if (& net users | select-string "jujud") { 670 net user "jujud" /DELETE 671 } 672 create-account jujud "Juju Admin user" $juju_passwd 673 $hostname = hostname 674 $juju_user = "$hostname\jujud" 675 SetUserLogonAsServiceRights $juju_user 676 SetAssignPrimaryTokenPrivilege $juju_user 677 $path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" 678 if (Test-RegistryValue -Path $path -Value "jujud") { 679 Remove-ItemProperty -Path $path -Name "jujud" 680 } 681 if(!(Test-Path $path)){ 682 New-Item -Path $path -force 683 } 684 if(Test-Path "C:\Juju") { 685 rm -Recurse -Force "C:\Juju" 686 } 687 if(Test-Path "HKLM:\SOFTWARE\juju-core") { 688 Remove-Item -Path "HKLM:\SOFTWARE\juju-core" -Recurse -Force 689 } 690 New-ItemProperty $path -Name "jujud" -Value 0 -PropertyType "DWord" 691 $secpasswd = ConvertTo-SecureString $juju_passwd -AsPlainText -Force 692 $jujuCreds = New-Object System.Management.Automation.PSCredential ($juju_user, $secpasswd) 693 694 mkdir -Force "C:\Juju" 695 mkdir C:\Juju\tmp 696 mkdir "C:\Juju\bin" 697 mkdir "C:\Juju\lib\juju\locks" 698 setx /m PATH "$env:PATH;C:\Juju\bin\" 699 $adminsGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]) 700 icacls "C:\Juju" /inheritance:r /grant "${adminsGroup}:(OI)(CI)(F)" /t 701 icacls "C:\Juju" /inheritance:r /grant "jujud:(OI)(CI)(F)" /t 702 Set-Content "C:\Juju\lib\juju\nonce.txt" "'FAKE_NONCE'" 703 $binDir="C:\Juju\lib\juju\tools\1.2.3-win8-amd64" 704 mkdir 'C:\Juju\log\juju' 705 mkdir $binDir 706 $WebClient = New-Object System.Net.WebClient 707 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 708 [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 709 ExecRetry { TryExecAll @({ $WebClient.DownloadFile('https://state-addr.testing.invalid:54321/deadbeef-0bad-400d-8000-4b1d0d06f00d/tools/1.2.3-win8-amd64', "$binDir\tools.tar.gz"); }) } 710 $dToolsHash = Get-FileSHA256 -FilePath "$binDir\tools.tar.gz" 711 $dToolsHash > "$binDir\juju1.2.3-win8-amd64.sha256" 712 if ($dToolsHash.ToLower() -ne "1234"){ Throw "Tools checksum mismatch"} 713 GUnZip-File -infile $binDir\tools.tar.gz -outdir $binDir 714 rm "$binDir\tools.tar*" 715 Set-Content $binDir\downloaded-tools.txt '{"version":"1.2.3-win8-amd64","url":"https://state-addr.testing.invalid:54321/deadbeef-0bad-400d-8000-4b1d0d06f00d/tools/1.2.3-win8-amd64","sha256":"1234","size":10}' 716 New-Item -Path 'HKLM:\SOFTWARE\juju-core' 717 $acl = Get-Acl -Path 'HKLM:\SOFTWARE\juju-core' 718 $acl.SetAccessRuleProtection($true, $false) 719 $adminPerm = "$adminsGroup", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow" 720 $rule = New-Object System.Security.AccessControl.RegistryAccessRule $adminPerm 721 $acl.AddAccessRule($rule) 722 $jujudPerm = "jujud", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow" 723 $rule = New-Object System.Security.AccessControl.RegistryAccessRule $jujudPerm 724 $acl.AddAccessRule($rule) 725 Set-Acl -Path 'HKLM:\SOFTWARE\juju-core' -AclObject $acl 726 New-ItemProperty -Path 'HKLM:\SOFTWARE\juju-core' -Name 'JUJU_DEV_FEATURE_FLAGS' 727 Set-ItemProperty -Path 'HKLM:\SOFTWARE\juju-core' -Name 'JUJU_DEV_FEATURE_FLAGS' -Value '' 728 mkdir 'C:\Juju\lib\juju\agents\machine-10' 729 Set-Content 'C:/Juju/lib/juju/agents/machine-10/agent.conf' @" 730 # format 2.0 731 tag: machine-10 732 datadir: C:/Juju/lib/juju 733 logdir: C:/Juju/log/juju 734 metricsspooldir: C:/Juju/lib/juju/metricspool 735 nonce: FAKE_NONCE 736 jobs: 737 - JobHostUnits 738 upgradedToVersion: 1.2.3 739 cacert: | 740 CA CERT 741 SERVER CERT 742 -----BEGIN CERTIFICATE----- 743 MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwHjENMAsGA1UEChMEanVqdTEN 744 MAsGA1UEAxMEcm9vdDAeFw0xMjExMDgxNjIyMzRaFw0xMzExMDgxNjI3MzRaMBwx 745 DDAKBgNVBAoTA2htbTEMMAoGA1UEAxMDYW55MFowCwYJKoZIhvcNAQEBA0sAMEgC 746 QQCACqz6JPwM7nbxAWub+APpnNB7myckWJ6nnsPKi9SipP1hyhfzkp8RGMJ5Uv7y 747 8CSTtJ8kg/ibka1VV8LvP9tnAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIAsDAdBgNV 748 HQ4EFgQU6G1ERaHCgfAv+yoDMFVpDbLOmIQwHwYDVR0jBBgwFoAUP/mfUdwOlHfk 749 fR+gLQjslxf64w0wCwYJKoZIhvcNAQEFA0EAbn0MaxWVgGYBomeLYfDdb8vCq/5/ 750 G/2iCUQCXsVrBparMLFnor/iKOkJB5n3z3rtu70rFt+DpX6L8uBR3LB3+A== 751 -----END CERTIFICATE----- 752 controller: controller-deadbeef-1bad-500d-9000-4b1d0d06f00d 753 model: model-deadbeef-0bad-400d-8000-4b1d0d06f00d 754 apiaddresses: 755 - state-addr.testing.invalid:54321 756 oldpassword: bletch 757 values: 758 AGENT_SERVICE_NAME: jujud-machine-10 759 PROVIDER_TYPE: dummy 760 mongoversion: "0.0" 761 762 "@ 763 cmd.exe /C mklink /D C:\Juju\lib\juju\tools\machine-10 1.2.3-win8-amd64 764 if ($jujuCreds) { 765 New-Service -Credential $jujuCreds -Name 'jujud-machine-10' -DependsOn Winmgmt -DisplayName 'juju agent for machine-10' '"C:\Juju\lib\juju\tools\machine-10\jujud.exe" machine --data-dir "C:\Juju\lib\juju" --machine-id 10 --debug' 766 } else { 767 New-Service -Name 'jujud-machine-10' -DependsOn Winmgmt -DisplayName 'juju agent for machine-10' '"C:\Juju\lib\juju\tools\machine-10\jujud.exe" machine --data-dir "C:\Juju\lib\juju" --machine-id 10 --debug' 768 } 769 sc.exe failure 'jujud-machine-10' reset=5 actions=restart/1000 770 sc.exe failureflag 'jujud-machine-10' 1 771 Start-Service 'jujud-machine-10'`