github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 352 $SourcePolicy = @" 353 /* 354 Original sources available at: https://bitbucket.org/splatteredbits/carbon 355 */ 356 357 using System; 358 using System.Collections.Generic; 359 using System.ComponentModel; 360 using System.Runtime.InteropServices; 361 using System.Security.Principal; 362 using System.Text; 363 364 namespace PSCarbon 365 { 366 public sealed class Lsa 367 { 368 // ReSharper disable InconsistentNaming 369 [StructLayout(LayoutKind.Sequential)] 370 internal struct LSA_UNICODE_STRING 371 { 372 internal LSA_UNICODE_STRING(string inputString) 373 { 374 if (inputString == null) 375 { 376 Buffer = IntPtr.Zero; 377 Length = 0; 378 MaximumLength = 0; 379 } 380 else 381 { 382 Buffer = Marshal.StringToHGlobalAuto(inputString); 383 Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); 384 MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); 385 } 386 } 387 388 internal ushort Length; 389 internal ushort MaximumLength; 390 internal IntPtr Buffer; 391 } 392 393 [StructLayout(LayoutKind.Sequential)] 394 internal struct LSA_OBJECT_ATTRIBUTES 395 { 396 internal uint Length; 397 internal IntPtr RootDirectory; 398 internal LSA_UNICODE_STRING ObjectName; 399 internal uint Attributes; 400 internal IntPtr SecurityDescriptor; 401 internal IntPtr SecurityQualityOfService; 402 } 403 404 [StructLayout(LayoutKind.Sequential)] 405 public struct LUID 406 { 407 public uint LowPart; 408 public int HighPart; 409 } 410 411 // ReSharper disable UnusedMember.Local 412 private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001; 413 private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002; 414 private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004; 415 private const uint POLICY_TRUST_ADMIN = 0x00000008; 416 private const uint POLICY_CREATE_ACCOUNT = 0x00000010; 417 private const uint POLICY_CREATE_SECRET = 0x00000014; 418 private const uint POLICY_CREATE_PRIVILEGE = 0x00000040; 419 private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080; 420 private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100; 421 private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200; 422 private const uint POLICY_SERVER_ADMIN = 0x00000400; 423 private const uint POLICY_LOOKUP_NAMES = 0x00000800; 424 private const uint POLICY_NOTIFICATION = 0x00001000; 425 // ReSharper restore UnusedMember.Local 426 427 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 428 public static extern bool LookupPrivilegeValue( 429 [MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, 430 [MarshalAs(UnmanagedType.LPTStr)] string lpName, 431 out LUID lpLuid); 432 433 [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] 434 private static extern uint LsaAddAccountRights( 435 IntPtr PolicyHandle, 436 IntPtr AccountSid, 437 LSA_UNICODE_STRING[] UserRights, 438 uint CountOfRights); 439 440 [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)] 441 private static extern uint LsaClose(IntPtr ObjectHandle); 442 443 [DllImport("advapi32.dll", SetLastError = true)] 444 private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle, 445 IntPtr AccountSid, 446 out IntPtr UserRights, 447 out uint CountOfRights 448 ); 449 450 [DllImport("advapi32.dll", SetLastError = true)] 451 private static extern uint LsaFreeMemory(IntPtr pBuffer); 452 453 [DllImport("advapi32.dll")] 454 private static extern int LsaNtStatusToWinError(long status); 455 456 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 457 private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle ); 458 459 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 460 static extern uint LsaRemoveAccountRights( 461 IntPtr PolicyHandle, 462 IntPtr AccountSid, 463 [MarshalAs(UnmanagedType.U1)] 464 bool AllRights, 465 LSA_UNICODE_STRING[] UserRights, 466 uint CountOfRights); 467 // ReSharper restore InconsistentNaming 468 469 private static IntPtr GetIdentitySid(string identity) 470 { 471 SecurityIdentifier sid = 472 new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier; 473 if (sid == null) 474 { 475 throw new ArgumentException(string.Format("Account {0} not found.", identity)); 476 } 477 byte[] sidBytes = new byte[sid.BinaryLength]; 478 sid.GetBinaryForm(sidBytes, 0); 479 System.IntPtr sidPtr = Marshal.AllocHGlobal(sidBytes.Length); 480 Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); 481 return sidPtr; 482 } 483 484 private static IntPtr GetLsaPolicyHandle() 485 { 486 string computerName = Environment.MachineName; 487 IntPtr hPolicy; 488 LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES(); 489 objectAttributes.Length = 0; 490 objectAttributes.RootDirectory = IntPtr.Zero; 491 objectAttributes.Attributes = 0; 492 objectAttributes.SecurityDescriptor = IntPtr.Zero; 493 objectAttributes.SecurityQualityOfService = IntPtr.Zero; 494 495 const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION; 496 LSA_UNICODE_STRING machineNameLsa = new LSA_UNICODE_STRING(computerName); 497 uint result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy); 498 HandleLsaResult(result); 499 return hPolicy; 500 } 501 502 public static string[] GetPrivileges(string identity) 503 { 504 IntPtr sidPtr = GetIdentitySid(identity); 505 IntPtr hPolicy = GetLsaPolicyHandle(); 506 IntPtr rightsPtr = IntPtr.Zero; 507 508 try 509 { 510 511 List<string> privileges = new List<string>(); 512 513 uint rightsCount; 514 uint result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount); 515 int win32ErrorCode = LsaNtStatusToWinError(result); 516 // the user has no privileges 517 if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND ) 518 { 519 return new string[0]; 520 } 521 HandleLsaResult(result); 522 523 LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING(); 524 for (ulong i = 0; i < rightsCount; i++) 525 { 526 IntPtr itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus))); 527 myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType()); 528 char[] cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize]; 529 Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize); 530 string thisRight = new string(cvt); 531 privileges.Add(thisRight); 532 } 533 return privileges.ToArray(); 534 } 535 finally 536 { 537 Marshal.FreeHGlobal(sidPtr); 538 uint result = LsaClose(hPolicy); 539 HandleLsaResult(result); 540 result = LsaFreeMemory(rightsPtr); 541 HandleLsaResult(result); 542 } 543 } 544 545 public static void GrantPrivileges(string identity, string[] privileges) 546 { 547 IntPtr sidPtr = GetIdentitySid(identity); 548 IntPtr hPolicy = GetLsaPolicyHandle(); 549 550 try 551 { 552 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 553 uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length); 554 HandleLsaResult(result); 555 } 556 finally 557 { 558 Marshal.FreeHGlobal(sidPtr); 559 uint result = LsaClose(hPolicy); 560 HandleLsaResult(result); 561 } 562 } 563 564 const int STATUS_SUCCESS = 0x0; 565 const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002; 566 const int STATUS_ACCESS_DENIED = 0x00000005; 567 const int STATUS_INVALID_HANDLE = 0x00000006; 568 const int STATUS_UNSUCCESSFUL = 0x0000001F; 569 const int STATUS_INVALID_PARAMETER = 0x00000057; 570 const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521; 571 const int STATUS_INVALID_SERVER_STATE = 0x00000548; 572 const int STATUS_INTERNAL_DB_ERROR = 0x00000567; 573 const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA; 574 575 private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>(); 576 public Lsa () { 577 ErrorMessages.Add(STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation."); 578 ErrorMessages.Add(STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used."); 579 ErrorMessages.Add(STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure."); 580 ErrorMessages.Add(STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid."); 581 ErrorMessages.Add(STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist."); 582 ErrorMessages.Add(STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled."); 583 ErrorMessages.Add(STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency."); 584 ErrorMessages.Add(STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call."); 585 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."); 586 } 587 588 private static void HandleLsaResult(uint returnCode) 589 { 590 int win32ErrorCode = LsaNtStatusToWinError(returnCode); 591 592 if( win32ErrorCode == STATUS_SUCCESS) 593 return; 594 595 if( ErrorMessages.ContainsKey(win32ErrorCode) ) 596 { 597 throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]); 598 } 599 600 throw new Win32Exception(win32ErrorCode); 601 } 602 603 public static void RevokePrivileges(string identity, string[] privileges) 604 { 605 IntPtr sidPtr = GetIdentitySid(identity); 606 IntPtr hPolicy = GetLsaPolicyHandle(); 607 608 try 609 { 610 string[] currentPrivileges = GetPrivileges(identity); 611 if (currentPrivileges.Length == 0) 612 { 613 return; 614 } 615 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 616 uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length); 617 HandleLsaResult(result); 618 } 619 finally 620 { 621 Marshal.FreeHGlobal(sidPtr); 622 uint result = LsaClose(hPolicy); 623 HandleLsaResult(result); 624 } 625 626 } 627 628 private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges) 629 { 630 LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length]; 631 for (int idx = 0; idx < privileges.Length; ++idx) 632 { 633 lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]); 634 } 635 return lsaPrivileges; 636 } 637 } 638 } 639 "@ 640 641 Add-Type -TypeDefinition $SourcePolicy -Language CSharp 642 643 function SetAssignPrimaryTokenPrivilege($UserName) 644 { 645 $privilege = "SeAssignPrimaryTokenPrivilege" 646 if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -contains $privilege)) 647 { 648 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 649 } 650 } 651 652 function SetUserLogonAsServiceRights($UserName) 653 { 654 $privilege = "SeServiceLogonRight" 655 if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -Contains $privilege)) 656 { 657 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 658 } 659 } 660 661 $juju_passwd = Get-RandomPassword 20 662 $juju_passwd += "^" 663 create-account jujud "Juju Admin user" $juju_passwd 664 $hostname = hostname 665 $juju_user = "$hostname\jujud" 666 667 SetUserLogonAsServiceRights $juju_user 668 SetAssignPrimaryTokenPrivilege $juju_user 669 670 $path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" 671 if(!(Test-Path $path)){ 672 New-Item -Path $path -force 673 } 674 New-ItemProperty $path -Name "jujud" -Value 0 -PropertyType "DWord" 675 676 $secpasswd = ConvertTo-SecureString $juju_passwd -AsPlainText -Force 677 $jujuCreds = New-Object System.Management.Automation.PSCredential ($juju_user, $secpasswd) 678 679 mkdir -Force "C:\Juju" 680 mkdir C:\Juju\tmp 681 mkdir "C:\Juju\bin" 682 mkdir "C:\Juju\lib\juju\locks" 683 setx /m PATH "$env:PATH;C:\Juju\bin\" 684 $adminsGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]) 685 icacls "C:\Juju" /inheritance:r /grant "${adminsGroup}:(OI)(CI)(F)" /t 686 icacls "C:\Juju" /inheritance:r /grant "jujud:(OI)(CI)(F)" /t 687 Set-Content "C:\Juju\lib\juju\nonce.txt" "'FAKE_NONCE'" 688 $binDir="C:\Juju\lib\juju\tools\1.2.3-win8-amd64" 689 mkdir 'C:\Juju\log\juju' 690 mkdir $binDir 691 $WebClient = New-Object System.Net.WebClient 692 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 693 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"); }) } 694 $dToolsHash = Get-FileSHA256 -FilePath "$binDir\tools.tar.gz" 695 $dToolsHash > "$binDir\juju1.2.3-win8-amd64.sha256" 696 if ($dToolsHash.ToLower() -ne "1234"){ Throw "Tools checksum mismatch"} 697 GUnZip-File -infile $binDir\tools.tar.gz -outdir $binDir 698 rm "$binDir\tools.tar*" 699 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}' 700 New-Item -Path 'HKLM:\SOFTWARE\juju-core' 701 $acl = Get-Acl -Path 'HKLM:\SOFTWARE\juju-core' 702 $acl.SetAccessRuleProtection($true, $false) 703 $adminPerm = "$adminsGroup", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow" 704 $rule = New-Object System.Security.AccessControl.RegistryAccessRule $adminPerm 705 $acl.AddAccessRule($rule) 706 $jujudPerm = "jujud", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow" 707 $rule = New-Object System.Security.AccessControl.RegistryAccessRule $jujudPerm 708 $acl.AddAccessRule($rule) 709 Set-Acl -Path 'HKLM:\SOFTWARE\juju-core' -AclObject $acl 710 New-ItemProperty -Path 'HKLM:\SOFTWARE\juju-core' -Name 'JUJU_DEV_FEATURE_FLAGS' 711 Set-ItemProperty -Path 'HKLM:\SOFTWARE\juju-core' -Name 'JUJU_DEV_FEATURE_FLAGS' -Value '' 712 mkdir 'C:\Juju\lib\juju\agents\machine-10' 713 Set-Content 'C:/Juju/lib/juju/agents/machine-10/agent.conf' @" 714 # format 1.18 715 tag: machine-10 716 datadir: C:/Juju/lib/juju 717 logdir: C:/Juju/log/juju 718 metricsspooldir: C:/Juju/lib/juju/metricspool 719 nonce: FAKE_NONCE 720 jobs: 721 - JobHostUnits 722 upgradedToVersion: 1.2.3 723 cacert: | 724 CA CERT 725 SERVER CERT 726 -----BEGIN CERTIFICATE----- 727 MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwHjENMAsGA1UEChMEanVqdTEN 728 MAsGA1UEAxMEcm9vdDAeFw0xMjExMDgxNjIyMzRaFw0xMzExMDgxNjI3MzRaMBwx 729 DDAKBgNVBAoTA2htbTEMMAoGA1UEAxMDYW55MFowCwYJKoZIhvcNAQEBA0sAMEgC 730 QQCACqz6JPwM7nbxAWub+APpnNB7myckWJ6nnsPKi9SipP1hyhfzkp8RGMJ5Uv7y 731 8CSTtJ8kg/ibka1VV8LvP9tnAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIAsDAdBgNV 732 HQ4EFgQU6G1ERaHCgfAv+yoDMFVpDbLOmIQwHwYDVR0jBBgwFoAUP/mfUdwOlHfk 733 fR+gLQjslxf64w0wCwYJKoZIhvcNAQEFA0EAbn0MaxWVgGYBomeLYfDdb8vCq/5/ 734 G/2iCUQCXsVrBparMLFnor/iKOkJB5n3z3rtu70rFt+DpX6L8uBR3LB3+A== 735 -----END CERTIFICATE----- 736 stateaddresses: 737 - state-addr.testing.invalid:12345 738 model: model-deadbeef-0bad-400d-8000-4b1d0d06f00d 739 apiaddresses: 740 - state-addr.testing.invalid:54321 741 oldpassword: arble 742 values: 743 AGENT_SERVICE_NAME: jujud-machine-10 744 PROVIDER_TYPE: dummy 745 mongoversion: "0.0" 746 747 "@ 748 cmd.exe /C mklink /D C:\Juju\lib\juju\tools\machine-10 1.2.3-win8-amd64 749 if ($jujuCreds) { 750 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' 751 } else { 752 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' 753 } 754 sc.exe failure 'jujud-machine-10' reset=5 actions=restart/1000 755 sc.exe failureflag 'jujud-machine-10' 1 756 Start-Service 'jujud-machine-10'`