github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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, $maxRetryCount = 10, $retryInterval=2) 23 { 24 $currErrorActionPreference = $ErrorActionPreference 25 $ErrorActionPreference = "Continue" 26 27 $retryCount = 0 28 while ($true) 29 { 30 try 31 { 32 & $command 33 break 34 } 35 catch [System.Exception] 36 { 37 $retryCount++ 38 if ($retryCount -ge $maxRetryCount) 39 { 40 $ErrorActionPreference = $currErrorActionPreference 41 throw 42 } 43 else 44 { 45 Write-Error $_.Exception 46 Start-Sleep $retryInterval 47 } 48 } 49 } 50 51 $ErrorActionPreference = $currErrorActionPreference 52 } 53 54 function create-account ([string]$accountName, [string]$accountDescription, [string]$password) { 55 $hostname = hostname 56 $comp = [adsi]"WinNT://$hostname" 57 $user = $comp.Create("User", $accountName) 58 $user.SetPassword($password) 59 $user.SetInfo() 60 $user.description = $accountDescription 61 $user.SetInfo() 62 $User.UserFlags[0] = $User.UserFlags[0] -bor 0x10000 63 $user.SetInfo() 64 65 $objOU = [ADSI]"WinNT://$hostname/Administrators,group" 66 $objOU.add("WinNT://$hostname/$accountName") 67 } 68 69 $Source = @" 70 using System; 71 using System.Text; 72 using System.Runtime.InteropServices; 73 74 namespace PSCloudbase 75 { 76 public sealed class Win32CryptApi 77 { 78 public static long CRYPT_SILENT = 0x00000040; 79 public static long CRYPT_VERIFYCONTEXT = 0xF0000000; 80 public static int PROV_RSA_FULL = 1; 81 82 [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 83 [return : MarshalAs(UnmanagedType.Bool)] 84 public static extern bool CryptAcquireContext(ref IntPtr hProv, 85 StringBuilder pszContainer, // Don't use string, as Powershell replaces $null with an empty string 86 StringBuilder pszProvider, // Don't use string, as Powershell replaces $null with an empty string 87 uint dwProvType, 88 uint dwFlags); 89 90 [DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)] 91 public static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); 92 93 [DllImport("advapi32.dll", SetLastError=true)] 94 public static extern bool CryptGenRandom(IntPtr hProv, uint dwLen, byte[] pbBuffer); 95 96 [DllImport("Kernel32.dll")] 97 public static extern uint GetLastError(); 98 } 99 } 100 "@ 101 102 Add-Type -TypeDefinition $Source -Language CSharp 103 104 function Get-RandomPassword 105 { 106 [CmdletBinding()] 107 param 108 ( 109 [parameter(Mandatory=$true)] 110 [int]$Length 111 ) 112 process 113 { 114 $hProvider = 0 115 try 116 { 117 if(![PSCloudbase.Win32CryptApi]::CryptAcquireContext([ref]$hProvider, $null, $null, 118 [PSCloudbase.Win32CryptApi]::PROV_RSA_FULL, 119 ([PSCloudbase.Win32CryptApi]::CRYPT_VERIFYCONTEXT -bor 120 [PSCloudbase.Win32CryptApi]::CRYPT_SILENT))) 121 { 122 throw "CryptAcquireContext failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError() 123 } 124 125 $buffer = New-Object byte[] $Length 126 if(![PSCloudbase.Win32CryptApi]::CryptGenRandom($hProvider, $Length, $buffer)) 127 { 128 throw "CryptGenRandom failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError() 129 } 130 131 $buffer | ForEach-Object { $password += "{0:X0}" -f $_ } 132 return $password 133 } 134 finally 135 { 136 if($hProvider) 137 { 138 $retVal = [PSCloudbase.Win32CryptApi]::CryptReleaseContext($hProvider, 0) 139 } 140 } 141 } 142 } 143 144 $SourcePolicy = @" 145 /* 146 Original sources available at: https://bitbucket.org/splatteredbits/carbon 147 */ 148 149 using System; 150 using System.Collections.Generic; 151 using System.ComponentModel; 152 using System.Runtime.InteropServices; 153 using System.Security.Principal; 154 using System.Text; 155 156 namespace PSCarbon 157 { 158 public sealed class Lsa 159 { 160 // ReSharper disable InconsistentNaming 161 [StructLayout(LayoutKind.Sequential)] 162 internal struct LSA_UNICODE_STRING 163 { 164 internal LSA_UNICODE_STRING(string inputString) 165 { 166 if (inputString == null) 167 { 168 Buffer = IntPtr.Zero; 169 Length = 0; 170 MaximumLength = 0; 171 } 172 else 173 { 174 Buffer = Marshal.StringToHGlobalAuto(inputString); 175 Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); 176 MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); 177 } 178 } 179 180 internal ushort Length; 181 internal ushort MaximumLength; 182 internal IntPtr Buffer; 183 } 184 185 [StructLayout(LayoutKind.Sequential)] 186 internal struct LSA_OBJECT_ATTRIBUTES 187 { 188 internal uint Length; 189 internal IntPtr RootDirectory; 190 internal LSA_UNICODE_STRING ObjectName; 191 internal uint Attributes; 192 internal IntPtr SecurityDescriptor; 193 internal IntPtr SecurityQualityOfService; 194 } 195 196 [StructLayout(LayoutKind.Sequential)] 197 public struct LUID 198 { 199 public uint LowPart; 200 public int HighPart; 201 } 202 203 // ReSharper disable UnusedMember.Local 204 private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001; 205 private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002; 206 private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004; 207 private const uint POLICY_TRUST_ADMIN = 0x00000008; 208 private const uint POLICY_CREATE_ACCOUNT = 0x00000010; 209 private const uint POLICY_CREATE_SECRET = 0x00000014; 210 private const uint POLICY_CREATE_PRIVILEGE = 0x00000040; 211 private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080; 212 private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100; 213 private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200; 214 private const uint POLICY_SERVER_ADMIN = 0x00000400; 215 private const uint POLICY_LOOKUP_NAMES = 0x00000800; 216 private const uint POLICY_NOTIFICATION = 0x00001000; 217 // ReSharper restore UnusedMember.Local 218 219 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 220 public static extern bool LookupPrivilegeValue( 221 [MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, 222 [MarshalAs(UnmanagedType.LPTStr)] string lpName, 223 out LUID lpLuid); 224 225 [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] 226 private static extern uint LsaAddAccountRights( 227 IntPtr PolicyHandle, 228 IntPtr AccountSid, 229 LSA_UNICODE_STRING[] UserRights, 230 uint CountOfRights); 231 232 [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)] 233 private static extern uint LsaClose(IntPtr ObjectHandle); 234 235 [DllImport("advapi32.dll", SetLastError = true)] 236 private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle, 237 IntPtr AccountSid, 238 out IntPtr UserRights, 239 out uint CountOfRights 240 ); 241 242 [DllImport("advapi32.dll", SetLastError = true)] 243 private static extern uint LsaFreeMemory(IntPtr pBuffer); 244 245 [DllImport("advapi32.dll")] 246 private static extern int LsaNtStatusToWinError(long status); 247 248 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 249 private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle ); 250 251 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 252 static extern uint LsaRemoveAccountRights( 253 IntPtr PolicyHandle, 254 IntPtr AccountSid, 255 [MarshalAs(UnmanagedType.U1)] 256 bool AllRights, 257 LSA_UNICODE_STRING[] UserRights, 258 uint CountOfRights); 259 // ReSharper restore InconsistentNaming 260 261 private static IntPtr GetIdentitySid(string identity) 262 { 263 var sid = 264 new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier; 265 if (sid == null) 266 { 267 throw new ArgumentException(string.Format("Account {0} not found.", identity)); 268 } 269 var sidBytes = new byte[sid.BinaryLength]; 270 sid.GetBinaryForm(sidBytes, 0); 271 var sidPtr = Marshal.AllocHGlobal(sidBytes.Length); 272 Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); 273 return sidPtr; 274 } 275 276 private static IntPtr GetLsaPolicyHandle() 277 { 278 var computerName = Environment.MachineName; 279 IntPtr hPolicy; 280 var objectAttributes = new LSA_OBJECT_ATTRIBUTES 281 { 282 Length = 0, 283 RootDirectory = IntPtr.Zero, 284 Attributes = 0, 285 SecurityDescriptor = IntPtr.Zero, 286 SecurityQualityOfService = IntPtr.Zero 287 }; 288 289 const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION; 290 var machineNameLsa = new LSA_UNICODE_STRING(computerName); 291 var result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy); 292 HandleLsaResult(result); 293 return hPolicy; 294 } 295 296 public static string[] GetPrivileges(string identity) 297 { 298 var sidPtr = GetIdentitySid(identity); 299 var hPolicy = GetLsaPolicyHandle(); 300 var rightsPtr = IntPtr.Zero; 301 302 try 303 { 304 305 var privileges = new List<string>(); 306 307 uint rightsCount; 308 var result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount); 309 var win32ErrorCode = LsaNtStatusToWinError(result); 310 // the user has no privileges 311 if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND ) 312 { 313 return new string[0]; 314 } 315 HandleLsaResult(result); 316 317 var myLsaus = new LSA_UNICODE_STRING(); 318 for (ulong i = 0; i < rightsCount; i++) 319 { 320 var itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus))); 321 myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType()); 322 var cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize]; 323 Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize); 324 var thisRight = new string(cvt); 325 privileges.Add(thisRight); 326 } 327 return privileges.ToArray(); 328 } 329 finally 330 { 331 Marshal.FreeHGlobal(sidPtr); 332 var result = LsaClose(hPolicy); 333 HandleLsaResult(result); 334 result = LsaFreeMemory(rightsPtr); 335 HandleLsaResult(result); 336 } 337 } 338 339 public static void GrantPrivileges(string identity, string[] privileges) 340 { 341 var sidPtr = GetIdentitySid(identity); 342 var hPolicy = GetLsaPolicyHandle(); 343 344 try 345 { 346 var lsaPrivileges = StringsToLsaStrings(privileges); 347 var result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length); 348 HandleLsaResult(result); 349 } 350 finally 351 { 352 Marshal.FreeHGlobal(sidPtr); 353 var result = LsaClose(hPolicy); 354 HandleLsaResult(result); 355 } 356 } 357 358 const int STATUS_SUCCESS = 0x0; 359 const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002; 360 const int STATUS_ACCESS_DENIED = 0x00000005; 361 const int STATUS_INVALID_HANDLE = 0x00000006; 362 const int STATUS_UNSUCCESSFUL = 0x0000001F; 363 const int STATUS_INVALID_PARAMETER = 0x00000057; 364 const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521; 365 const int STATUS_INVALID_SERVER_STATE = 0x00000548; 366 const int STATUS_INTERNAL_DB_ERROR = 0x00000567; 367 const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA; 368 369 private static readonly Dictionary<int, string> ErrorMessages = new Dictionary<int, string> 370 { 371 {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."}, 372 {STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation."}, 373 {STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used."}, 374 {STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure."}, 375 {STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid."}, 376 {STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist."}, 377 {STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled."}, 378 {STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency."}, 379 {STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call."} 380 }; 381 382 private static void HandleLsaResult(uint returnCode) 383 { 384 var win32ErrorCode = LsaNtStatusToWinError(returnCode); 385 386 if( win32ErrorCode == STATUS_SUCCESS) 387 return; 388 389 if( ErrorMessages.ContainsKey(win32ErrorCode) ) 390 { 391 throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]); 392 } 393 394 throw new Win32Exception(win32ErrorCode); 395 } 396 397 public static void RevokePrivileges(string identity, string[] privileges) 398 { 399 var sidPtr = GetIdentitySid(identity); 400 var hPolicy = GetLsaPolicyHandle(); 401 402 try 403 { 404 var currentPrivileges = GetPrivileges(identity); 405 if (currentPrivileges.Length == 0) 406 { 407 return; 408 } 409 var lsaPrivileges = StringsToLsaStrings(privileges); 410 var result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length); 411 HandleLsaResult(result); 412 } 413 finally 414 { 415 Marshal.FreeHGlobal(sidPtr); 416 var result = LsaClose(hPolicy); 417 HandleLsaResult(result); 418 } 419 420 } 421 422 private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges) 423 { 424 var lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length]; 425 for (var idx = 0; idx < privileges.Length; ++idx) 426 { 427 lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]); 428 } 429 return lsaPrivileges; 430 } 431 } 432 } 433 "@ 434 435 Add-Type -TypeDefinition $SourcePolicy -Language CSharp 436 437 $ServiceChangeErrors = @{} 438 $ServiceChangeErrors.Add(1, "Not Supported") 439 $ServiceChangeErrors.Add(2, "Access Denied") 440 $ServiceChangeErrors.Add(3, "Dependent Services Running") 441 $ServiceChangeErrors.Add(4, "Invalid Service Control") 442 $ServiceChangeErrors.Add(5, "Service Cannot Accept Control") 443 $ServiceChangeErrors.Add(6, "Service Not Active") 444 $ServiceChangeErrors.Add(7, "Service Request Timeout") 445 $ServiceChangeErrors.Add(8, "Unknown Failure") 446 $ServiceChangeErrors.Add(9, "Path Not Found") 447 $ServiceChangeErrors.Add(10, "Service Already Running") 448 $ServiceChangeErrors.Add(11, "Service Database Locked") 449 $ServiceChangeErrors.Add(12, "Service Dependency Deleted") 450 $ServiceChangeErrors.Add(13, "Service Dependency Failure") 451 $ServiceChangeErrors.Add(14, "Service Disabled") 452 $ServiceChangeErrors.Add(15, "Service Logon Failure") 453 $ServiceChangeErrors.Add(16, "Service Marked For Deletion") 454 $ServiceChangeErrors.Add(17, "Service No Thread") 455 $ServiceChangeErrors.Add(18, "Status Circular Dependency") 456 $ServiceChangeErrors.Add(19, "Status Duplicate Name") 457 $ServiceChangeErrors.Add(20, "Status Invalid Name") 458 $ServiceChangeErrors.Add(21, "Status Invalid Parameter") 459 $ServiceChangeErrors.Add(22, "Status Invalid Service Account") 460 $ServiceChangeErrors.Add(23, "Status Service Exists") 461 $ServiceChangeErrors.Add(24, "Service Already Paused") 462 463 464 function SetAssignPrimaryTokenPrivilege($UserName) 465 { 466 $privilege = "SeAssignPrimaryTokenPrivilege" 467 if (![PSCarbon.Lsa]::GetPrivileges($UserName).Contains($privilege)) 468 { 469 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 470 } 471 } 472 473 function SetUserLogonAsServiceRights($UserName) 474 { 475 $privilege = "SeServiceLogonRight" 476 if (![PSCarbon.Lsa]::GetPrivileges($UserName).Contains($privilege)) 477 { 478 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 479 } 480 } 481 482 $Source = @" 483 using System; 484 using System.Text; 485 using System.Runtime.InteropServices; 486 using System.Security.Principal; 487 using System.ComponentModel; 488 489 namespace PSCloudbase 490 { 491 public class ProcessManager 492 { 493 const int LOGON32_LOGON_SERVICE = 5; 494 const int LOGON32_PROVIDER_DEFAULT = 0; 495 const int TOKEN_ALL_ACCESS = 0x000f01ff; 496 const uint GENERIC_ALL_ACCESS = 0x10000000; 497 const uint INFINITE = 0xFFFFFFFF; 498 const uint PI_NOUI = 0x00000001; 499 const uint WAIT_FAILED = 0xFFFFFFFF; 500 501 enum SECURITY_IMPERSONATION_LEVEL 502 { 503 SecurityAnonymous, 504 SecurityIdentification, 505 SecurityImpersonation, 506 SecurityDelegation 507 } 508 509 enum TOKEN_TYPE 510 { 511 TokenPrimary = 1, 512 TokenImpersonation 513 } 514 515 [StructLayout(LayoutKind.Sequential)] 516 struct SECURITY_ATTRIBUTES 517 { 518 public int nLength; 519 public IntPtr lpSecurityDescriptor; 520 public int bInheritHandle; 521 } 522 523 [StructLayout(LayoutKind.Sequential)] 524 struct PROCESS_INFORMATION 525 { 526 public IntPtr hProcess; 527 public IntPtr hThread; 528 public int dwProcessId; 529 public int dwThreadId; 530 } 531 532 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 533 struct STARTUPINFO 534 { 535 public Int32 cb; 536 public string lpReserved; 537 public string lpDesktop; 538 public string lpTitle; 539 public Int32 dwX; 540 public Int32 dwY; 541 public Int32 dwXSize; 542 public Int32 dwYSize; 543 public Int32 dwXCountChars; 544 public Int32 dwYCountChars; 545 public Int32 dwFillAttribute; 546 public Int32 dwFlags; 547 public Int16 wShowWindow; 548 public Int16 cbReserved2; 549 public IntPtr lpReserved2; 550 public IntPtr hStdInput; 551 public IntPtr hStdOutput; 552 public IntPtr hStdError; 553 } 554 555 [StructLayout(LayoutKind.Sequential)] 556 struct PROFILEINFO { 557 public int dwSize; 558 public uint dwFlags; 559 [MarshalAs(UnmanagedType.LPTStr)] 560 public String lpUserName; 561 [MarshalAs(UnmanagedType.LPTStr)] 562 public String lpProfilePath; 563 [MarshalAs(UnmanagedType.LPTStr)] 564 public String lpDefaultPath; 565 [MarshalAs(UnmanagedType.LPTStr)] 566 public String lpServerName; 567 [MarshalAs(UnmanagedType.LPTStr)] 568 public String lpPolicyPath; 569 public IntPtr hProfile; 570 } 571 572 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 573 public struct USER_INFO_4 574 { 575 public string name; 576 public string password; 577 public int password_age; 578 public uint priv; 579 public string home_dir; 580 public string comment; 581 public uint flags; 582 public string script_path; 583 public uint auth_flags; 584 public string full_name; 585 public string usr_comment; 586 public string parms; 587 public string workstations; 588 public int last_logon; 589 public int last_logoff; 590 public int acct_expires; 591 public int max_storage; 592 public int units_per_week; 593 public IntPtr logon_hours; // This is a PBYTE 594 public int bad_pw_count; 595 public int num_logons; 596 public string logon_server; 597 public int country_code; 598 public int code_page; 599 public IntPtr user_sid; // This is a PSID 600 public int primary_group_id; 601 public string profile; 602 public string home_dir_drive; 603 public int password_expired; 604 } 605 606 [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 607 extern static bool DuplicateTokenEx( 608 IntPtr hExistingToken, 609 uint dwDesiredAccess, 610 ref SECURITY_ATTRIBUTES lpTokenAttributes, 611 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 612 TOKEN_TYPE TokenType, 613 out IntPtr phNewToken); 614 615 [DllImport("advapi32.dll", SetLastError=true)] 616 static extern bool LogonUser( 617 string lpszUsername, 618 string lpszDomain, 619 string lpszPassword, 620 int dwLogonType, 621 int dwLogonProvider, 622 out IntPtr phToken); 623 624 [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)] 625 static extern bool CreateProcessAsUser( 626 IntPtr hToken, 627 string lpApplicationName, 628 string lpCommandLine, 629 ref SECURITY_ATTRIBUTES lpProcessAttributes, 630 ref SECURITY_ATTRIBUTES lpThreadAttributes, 631 bool bInheritHandles, 632 uint dwCreationFlags, 633 IntPtr lpEnvironment, 634 string lpCurrentDirectory, 635 ref STARTUPINFO lpStartupInfo, 636 out PROCESS_INFORMATION lpProcessInformation); 637 638 [DllImport("kernel32.dll", SetLastError=true)] 639 static extern UInt32 WaitForSingleObject(IntPtr hHandle, 640 UInt32 dwMilliseconds); 641 642 [DllImport("Kernel32.dll")] 643 static extern int GetLastError(); 644 645 [DllImport("Kernel32.dll")] 646 extern static int CloseHandle(IntPtr handle); 647 648 [DllImport("kernel32.dll", SetLastError = true)] 649 [return: MarshalAs(UnmanagedType.Bool)] 650 static extern bool GetExitCodeProcess(IntPtr hProcess, 651 out uint lpExitCode); 652 653 [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)] 654 [return: MarshalAs(UnmanagedType.Bool)] 655 static extern bool LoadUserProfile(IntPtr hToken, 656 ref PROFILEINFO lpProfileInfo); 657 658 [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)] 659 [return: MarshalAs(UnmanagedType.Bool)] 660 static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile); 661 662 [DllImport("Netapi32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)] 663 extern static int NetUserGetInfo( 664 [MarshalAs(UnmanagedType.LPWStr)] string ServerName, 665 [MarshalAs(UnmanagedType.LPWStr)] string UserName, 666 int level, out IntPtr BufPtr); 667 668 public static uint RunProcess(string userName, string password, 669 string domain, string cmd, 670 string arguments, 671 bool loadUserProfile = true) 672 { 673 bool retValue; 674 IntPtr phToken = IntPtr.Zero; 675 IntPtr phTokenDup = IntPtr.Zero; 676 PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION(); 677 PROFILEINFO pi = new PROFILEINFO(); 678 679 try 680 { 681 retValue = LogonUser(userName, domain, password, 682 LOGON32_LOGON_SERVICE, 683 LOGON32_PROVIDER_DEFAULT, 684 out phToken); 685 if(!retValue) 686 throw new Win32Exception(GetLastError()); 687 688 var sa = new SECURITY_ATTRIBUTES(); 689 sa.nLength = Marshal.SizeOf(sa); 690 691 retValue = DuplicateTokenEx( 692 phToken, GENERIC_ALL_ACCESS, ref sa, 693 SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, 694 TOKEN_TYPE.TokenPrimary, out phTokenDup); 695 if(!retValue) 696 throw new Win32Exception(GetLastError()); 697 698 STARTUPINFO sInfo = new STARTUPINFO(); 699 sInfo.lpDesktop = ""; 700 701 if(loadUserProfile) 702 { 703 IntPtr userInfoPtr = IntPtr.Zero; 704 int retValueNetUser = NetUserGetInfo(null, userName, 4, 705 out userInfoPtr); 706 if(retValueNetUser != 0) 707 throw new Win32Exception(retValueNetUser); 708 709 USER_INFO_4 userInfo = (USER_INFO_4)Marshal.PtrToStructure( 710 userInfoPtr, typeof(USER_INFO_4)); 711 712 pi.dwSize = Marshal.SizeOf(pi); 713 pi.dwFlags = PI_NOUI; 714 pi.lpUserName = userName; 715 pi.lpProfilePath = userInfo.profile; 716 717 retValue = LoadUserProfile(phTokenDup, ref pi); 718 if(!retValue) 719 throw new Win32Exception(GetLastError()); 720 } 721 722 retValue = CreateProcessAsUser(phTokenDup, cmd, arguments, 723 ref sa, ref sa, false, 0, 724 IntPtr.Zero, null, 725 ref sInfo, out pInfo); 726 if(!retValue) 727 throw new Win32Exception(GetLastError()); 728 729 if(WaitForSingleObject(pInfo.hProcess, INFINITE) == WAIT_FAILED) 730 throw new Win32Exception(GetLastError()); 731 732 uint exitCode; 733 retValue = GetExitCodeProcess(pInfo.hProcess, out exitCode); 734 if(!retValue) 735 throw new Win32Exception(GetLastError()); 736 737 return exitCode; 738 } 739 finally 740 { 741 if(pi.hProfile != IntPtr.Zero) 742 UnloadUserProfile(phTokenDup, pi.hProfile); 743 if(phToken != IntPtr.Zero) 744 CloseHandle(phToken); 745 if(phTokenDup != IntPtr.Zero) 746 CloseHandle(phTokenDup); 747 if(pInfo.hProcess != IntPtr.Zero) 748 CloseHandle(pInfo.hProcess); 749 } 750 } 751 } 752 } 753 "@ 754 755 Add-Type -TypeDefinition $Source -Language CSharp 756 757 function Start-ProcessAsUser 758 { 759 [CmdletBinding()] 760 param 761 ( 762 [parameter(Mandatory=$true, ValueFromPipeline=$true)] 763 [string]$Command, 764 765 [parameter()] 766 [string]$Arguments, 767 768 [parameter(Mandatory=$true)] 769 [PSCredential]$Credential, 770 771 [parameter()] 772 [bool]$LoadUserProfile = $true 773 ) 774 process 775 { 776 $nc = $Credential.GetNetworkCredential() 777 778 $domain = "." 779 if($nc.Domain) 780 { 781 $domain = $nc.Domain 782 } 783 784 [PSCloudbase.ProcessManager]::RunProcess($nc.UserName, $nc.Password, 785 $domain, $Command, 786 $Arguments, $LoadUserProfile) 787 } 788 } 789 790 $powershell = "$ENV:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" 791 $cmdExe = "$ENV:SystemRoot\System32\cmd.exe" 792 793 $juju_passwd = Get-RandomPassword 20 794 $juju_passwd += "^" 795 create-account jujud "Juju Admin user" $juju_passwd 796 $hostname = hostname 797 $juju_user = "$hostname\jujud" 798 799 SetUserLogonAsServiceRights $juju_user 800 SetAssignPrimaryTokenPrivilege $juju_user 801 802 New-ItemProperty "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" -Name "jujud" -Value 0 -PropertyType "DWord" 803 804 $secpasswd = ConvertTo-SecureString $juju_passwd -AsPlainText -Force 805 $jujuCreds = New-Object System.Management.Automation.PSCredential ($juju_user, $secpasswd) 806 807 808 icacls "C:\Juju" /grant "jujud:(OI)(CI)(F)" /T 809 mkdir C:\Juju\tmp 810 mkdir "C:\Juju\bin" 811 812 813 Set-Content "C:\juju\bin\save_pass.ps1" @" 814 Param ( 815 [Parameter(Mandatory=` + "`" + `$true)] 816 [string]` + "`" + `$pass 817 ) 818 819 ` + "`" + `$secpasswd = ConvertTo-SecureString ` + "`" + `$pass -AsPlainText -Force 820 ` + "`" + `$secpasswd | convertfrom-securestring | Add-Content C:\Juju\Jujud.pass 821 "@ 822 823 824 Start-ProcessAsUser -Command $powershell -Arguments "-File C:\juju\bin\save_pass.ps1 $juju_passwd" -Credential $jujuCreds 825 mkdir "C:\Juju\lib\juju\locks" 826 Start-ProcessAsUser -Command $cmdExe -Arguments '/C setx PATH "%PATH%` + ";" + `C:\Juju\bin"' -Credential $jujuCreds 827 Set-Content "C:\Juju\lib\juju\nonce.txt" "'FAKE_NONCE'" 828 $binDir="C:\Juju\lib\juju\tools\1.2.3-win8-amd64" 829 $tmpBinDir=$binDir.Replace('\', '\\') 830 mkdir 'C:\Juju\log\juju' 831 mkdir $binDir 832 $WebClient = New-Object System.Net.WebClient 833 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 834 ExecRetry { $WebClient.DownloadFile('http://foo.com/tools/released/juju1.2.3-win8-amd64.tgz', "$binDir\tools.tar.gz") } 835 $dToolsHash = (Get-FileHash -Algorithm SHA256 "$binDir\tools.tar.gz").hash 836 $dToolsHash > "$binDir\juju1.2.3-win8-amd64.sha256" 837 if ($dToolsHash.ToLower() -ne "1234"){ Throw "Tools checksum mismatch"} 838 & "${env:ProgramFiles(x86)}\Cloudbase Solutions\Cloudbase-Init\Python27\python.exe" -c "import tarfile;archive = tarfile.open('$tmpBinDir\\tools.tar.gz');archive.extractall(path='$tmpBinDir')" 839 rm "$binDir\tools.tar*" 840 Set-Content $binDir\downloaded-tools.txt '{"version":"1.2.3-win8-amd64","url":"http://foo.com/tools/released/juju1.2.3-win8-amd64.tgz","sha256":"1234","size":10}' 841 New-Item -Path 'HKLM:\SOFTWARE\juju-core' 842 $acl = Get-Acl -Path 'HKLM:\SOFTWARE\juju-core' 843 $acl.SetAccessRuleProtection($true, $false) 844 $perm = "BUILTIN\Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow" 845 $rule = New-Object System.Security.AccessControl.RegistryAccessRule $perm 846 $acl.SetAccessRule($rule) 847 Set-Acl -Path 'HKLM:\SOFTWARE\juju-core' -AclObject $acl 848 New-ItemProperty -Path 'HKLM:\SOFTWARE\juju-core' -Name 'JUJU_DEV_FEATURE_FLAGS' 849 Set-ItemProperty -Path 'HKLM:\SOFTWARE\juju-core' -Name 'JUJU_DEV_FEATURE_FLAGS' -Value '' 850 mkdir 'C:\Juju\lib\juju\agents\machine-10' 851 Set-Content 'C:/Juju/lib/juju/agents/machine-10/agent.conf' @" 852 # format 1.18 853 tag: machine-10 854 datadir: C:/Juju/lib/juju 855 logdir: C:/Juju/log/juju 856 nonce: FAKE_NONCE 857 jobs: 858 - JobHostUnits 859 upgradedToVersion: 1.2.3 860 cacert: | 861 CA CERT 862 SERVER CERT 863 -----BEGIN CERTIFICATE----- 864 MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwHjENMAsGA1UEChMEanVqdTEN 865 MAsGA1UEAxMEcm9vdDAeFw0xMjExMDgxNjIyMzRaFw0xMzExMDgxNjI3MzRaMBwx 866 DDAKBgNVBAoTA2htbTEMMAoGA1UEAxMDYW55MFowCwYJKoZIhvcNAQEBA0sAMEgC 867 QQCACqz6JPwM7nbxAWub+APpnNB7myckWJ6nnsPKi9SipP1hyhfzkp8RGMJ5Uv7y 868 8CSTtJ8kg/ibka1VV8LvP9tnAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIAsDAdBgNV 869 HQ4EFgQU6G1ERaHCgfAv+yoDMFVpDbLOmIQwHwYDVR0jBBgwFoAUP/mfUdwOlHfk 870 fR+gLQjslxf64w0wCwYJKoZIhvcNAQEFA0EAbn0MaxWVgGYBomeLYfDdb8vCq/5/ 871 G/2iCUQCXsVrBparMLFnor/iKOkJB5n3z3rtu70rFt+DpX6L8uBR3LB3+A== 872 -----END CERTIFICATE----- 873 stateaddresses: 874 - state-addr.testing.invalid:12345 875 environment: environment-deadbeef-0bad-400d-8000-4b1d0d06f00d 876 apiaddresses: 877 - state-addr.testing.invalid:54321 878 oldpassword: arble 879 values: 880 AGENT_SERVICE_NAME: jujud-machine-10 881 PROVIDER_TYPE: dummy 882 883 "@ 884 cmd.exe /C mklink /D C:\Juju\lib\juju\tools\machine-10 1.2.3-win8-amd64 885 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' 886 Start-Service 'jujud-machine-10'`