1
// Copyright 2016 Canonical Ltd.
2
// Copyright 2016 Cloudbase Solutions SRL
3
// Licensed under the AGPLv3, see LICENCE file for details.
7
// Generated code - do not edit.
10
function create-account ([string]$accountName, [string]$accountDescription, [string]$password) {
12
$comp = [adsi]"WinNT://$hostname"
13
$user = $comp.Create("User", $accountName)
14
$user.SetPassword($password)
16
$user.description = $accountDescription
18
$User.UserFlags[0] = $User.UserFlags[0] -bor 0x10000
21
# This gets the Administrator group name that is localized on different windows versions.
22
# However the SID S-1-5-32-544 is the same on all versions.
23
$adminGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value.Split("\")[1]
25
$objOU = [ADSI]"WinNT://$hostname/$adminGroup,group"
26
$objOU.add("WinNT://$hostname/$accountName")
32
using System.Runtime.InteropServices;
36
public sealed class Win32CryptApi
38
public static long CRYPT_SILENT = 0x00000040;
39
public static long CRYPT_VERIFYCONTEXT = 0xF0000000;
40
public static int PROV_RSA_FULL = 1;
42
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
43
[return : MarshalAs(UnmanagedType.Bool)]
44
public static extern bool CryptAcquireContext(ref IntPtr hProv,
45
StringBuilder pszContainer, // Don't use string, as Powershell replaces $null with an empty string
46
StringBuilder pszProvider, // Don't use string, as Powershell replaces $null with an empty string
50
[DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)]
51
public static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags);
53
[DllImport("advapi32.dll", SetLastError=true)]
54
public static extern bool CryptGenRandom(IntPtr hProv, uint dwLen, byte[] pbBuffer);
56
[DllImport("Kernel32.dll")]
57
public static extern uint GetLastError();
62
Add-Type -TypeDefinition $Source -Language CSharp
64
function Get-RandomPassword
69
[parameter(Mandatory=$true)]
77
if(![PSCloudbase.Win32CryptApi]::CryptAcquireContext([ref]$hProvider, $null, $null,
78
[PSCloudbase.Win32CryptApi]::PROV_RSA_FULL,
79
([PSCloudbase.Win32CryptApi]::CRYPT_VERIFYCONTEXT -bor
80
[PSCloudbase.Win32CryptApi]::CRYPT_SILENT)))
82
throw "CryptAcquireContext failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError()
85
$buffer = New-Object byte[] $Length
86
if(![PSCloudbase.Win32CryptApi]::CryptGenRandom($hProvider, $Length, $buffer))
88
throw "CryptGenRandom failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError()
91
$buffer | ForEach-Object { $password += "{0:X0}" -f $_ }
98
$retVal = [PSCloudbase.Win32CryptApi]::CryptReleaseContext($hProvider, 0)
106
Original sources available at: https://bitbucket.org/splatteredbits/carbon
110
using System.Collections.Generic;
111
using System.ComponentModel;
112
using System.Runtime.InteropServices;
113
using System.Security.Principal;
118
public sealed class Lsa
120
// ReSharper disable InconsistentNaming
121
[StructLayout(LayoutKind.Sequential)]
122
internal struct LSA_UNICODE_STRING
124
internal LSA_UNICODE_STRING(string inputString)
126
if (inputString == null)
128
Buffer = IntPtr.Zero;
134
Buffer = Marshal.StringToHGlobalAuto(inputString);
135
Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize);
136
MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize);
140
internal ushort Length;
141
internal ushort MaximumLength;
142
internal IntPtr Buffer;
145
[StructLayout(LayoutKind.Sequential)]
146
internal struct LSA_OBJECT_ATTRIBUTES
148
internal uint Length;
149
internal IntPtr RootDirectory;
150
internal LSA_UNICODE_STRING ObjectName;
151
internal uint Attributes;
152
internal IntPtr SecurityDescriptor;
153
internal IntPtr SecurityQualityOfService;
156
[StructLayout(LayoutKind.Sequential)]
163
// ReSharper disable UnusedMember.Local
164
private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001;
165
private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002;
166
private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004;
167
private const uint POLICY_TRUST_ADMIN = 0x00000008;
168
private const uint POLICY_CREATE_ACCOUNT = 0x00000010;
169
private const uint POLICY_CREATE_SECRET = 0x00000014;
170
private const uint POLICY_CREATE_PRIVILEGE = 0x00000040;
171
private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080;
172
private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100;
173
private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200;
174
private const uint POLICY_SERVER_ADMIN = 0x00000400;
175
private const uint POLICY_LOOKUP_NAMES = 0x00000800;
176
private const uint POLICY_NOTIFICATION = 0x00001000;
177
// ReSharper restore UnusedMember.Local
179
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
180
public static extern bool LookupPrivilegeValue(
181
[MarshalAs(UnmanagedType.LPTStr)] string lpSystemName,
182
[MarshalAs(UnmanagedType.LPTStr)] string lpName,
185
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
186
private static extern uint LsaAddAccountRights(
189
LSA_UNICODE_STRING[] UserRights,
192
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
193
private static extern uint LsaClose(IntPtr ObjectHandle);
195
[DllImport("advapi32.dll", SetLastError = true)]
196
private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle,
198
out IntPtr UserRights,
199
out uint CountOfRights
202
[DllImport("advapi32.dll", SetLastError = true)]
203
private static extern uint LsaFreeMemory(IntPtr pBuffer);
205
[DllImport("advapi32.dll")]
206
private static extern int LsaNtStatusToWinError(long status);
208
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
209
private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle );
211
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
212
static extern uint LsaRemoveAccountRights(
215
[MarshalAs(UnmanagedType.U1)]
217
LSA_UNICODE_STRING[] UserRights,
219
// ReSharper restore InconsistentNaming
221
private static IntPtr GetIdentitySid(string identity)
223
SecurityIdentifier sid =
224
new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier;
227
throw new ArgumentException(string.Format("Account {0} not found.", identity));
229
byte[] sidBytes = new byte[sid.BinaryLength];
230
sid.GetBinaryForm(sidBytes, 0);
231
System.IntPtr sidPtr = Marshal.AllocHGlobal(sidBytes.Length);
232
Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length);
236
private static IntPtr GetLsaPolicyHandle()
238
string computerName = Environment.MachineName;
240
LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES();
241
objectAttributes.Length = 0;
242
objectAttributes.RootDirectory = IntPtr.Zero;
243
objectAttributes.Attributes = 0;
244
objectAttributes.SecurityDescriptor = IntPtr.Zero;
245
objectAttributes.SecurityQualityOfService = IntPtr.Zero;
247
const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION;
248
LSA_UNICODE_STRING machineNameLsa = new LSA_UNICODE_STRING(computerName);
249
uint result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy);
250
HandleLsaResult(result);
254
public static string[] GetPrivileges(string identity)
256
IntPtr sidPtr = GetIdentitySid(identity);
257
IntPtr hPolicy = GetLsaPolicyHandle();
258
IntPtr rightsPtr = IntPtr.Zero;
263
List<string> privileges = new List<string>();
266
uint result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount);
267
int win32ErrorCode = LsaNtStatusToWinError(result);
268
// the user has no privileges
269
if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND )
271
return new string[0];
273
HandleLsaResult(result);
275
LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING();
276
for (ulong i = 0; i < rightsCount; i++)
278
IntPtr itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus)));
279
myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType());
280
char[] cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize];
281
Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize);
282
string thisRight = new string(cvt);
283
privileges.Add(thisRight);
285
return privileges.ToArray();
289
Marshal.FreeHGlobal(sidPtr);
290
uint result = LsaClose(hPolicy);
291
HandleLsaResult(result);
292
result = LsaFreeMemory(rightsPtr);
293
HandleLsaResult(result);
297
public static void GrantPrivileges(string identity, string[] privileges)
299
IntPtr sidPtr = GetIdentitySid(identity);
300
IntPtr hPolicy = GetLsaPolicyHandle();
304
LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges);
305
uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length);
306
HandleLsaResult(result);
310
Marshal.FreeHGlobal(sidPtr);
311
uint result = LsaClose(hPolicy);
312
HandleLsaResult(result);
316
const int STATUS_SUCCESS = 0x0;
317
const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002;
318
const int STATUS_ACCESS_DENIED = 0x00000005;
319
const int STATUS_INVALID_HANDLE = 0x00000006;
320
const int STATUS_UNSUCCESSFUL = 0x0000001F;
321
const int STATUS_INVALID_PARAMETER = 0x00000057;
322
const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521;
323
const int STATUS_INVALID_SERVER_STATE = 0x00000548;
324
const int STATUS_INTERNAL_DB_ERROR = 0x00000567;
325
const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA;
327
private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>();
329
ErrorMessages.Add(STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation.");
330
ErrorMessages.Add(STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used.");
331
ErrorMessages.Add(STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure.");
332
ErrorMessages.Add(STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid.");
333
ErrorMessages.Add(STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist.");
334
ErrorMessages.Add(STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled.");
335
ErrorMessages.Add(STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency.");
336
ErrorMessages.Add(STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call.");
337
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.");
340
private static void HandleLsaResult(uint returnCode)
342
int win32ErrorCode = LsaNtStatusToWinError(returnCode);
344
if( win32ErrorCode == STATUS_SUCCESS)
347
if( ErrorMessages.ContainsKey(win32ErrorCode) )
349
throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]);
352
throw new Win32Exception(win32ErrorCode);
355
public static void RevokePrivileges(string identity, string[] privileges)
357
IntPtr sidPtr = GetIdentitySid(identity);
358
IntPtr hPolicy = GetLsaPolicyHandle();
362
string[] currentPrivileges = GetPrivileges(identity);
363
if (currentPrivileges.Length == 0)
367
LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges);
368
uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length);
369
HandleLsaResult(result);
373
Marshal.FreeHGlobal(sidPtr);
374
uint result = LsaClose(hPolicy);
375
HandleLsaResult(result);
380
private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges)
382
LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length];
383
for (int idx = 0; idx < privileges.Length; ++idx)
385
lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]);
387
return lsaPrivileges;
393
Add-Type -TypeDefinition $SourcePolicy -Language CSharp
395
function SetAssignPrimaryTokenPrivilege($UserName)
397
$privilege = "SeAssignPrimaryTokenPrivilege"
398
if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -contains $privilege))
400
[PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege)
404
function SetUserLogonAsServiceRights($UserName)
406
$privilege = "SeServiceLogonRight"
407
if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -Contains $privilege))
409
[PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege)
413
$juju_passwd = Get-RandomPassword 20
415
create-account jujud "Juju Admin user" $juju_passwd
417
$juju_user = "$hostname\jujud"
419
SetUserLogonAsServiceRights $juju_user
420
SetAssignPrimaryTokenPrivilege $juju_user
422
$path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList"
423
if(!(Test-Path $path)){
424
New-Item -Path $path -force
426
New-ItemProperty $path -Name "jujud" -Value 0 -PropertyType "DWord"
428
$secpasswd = ConvertTo-SecureString $juju_passwd -AsPlainText -Force
429
$jujuCreds = New-Object System.Management.Automation.PSCredential ($juju_user, $secpasswd)
431
const windowsPowershellHelpers = `
433
$ErrorActionPreference = "Stop"
435
function ExecRetry($command, $retryInterval = 15)
437
$currErrorActionPreference = $ErrorActionPreference
438
$ErrorActionPreference = "Continue"
447
catch [System.Exception]
449
Write-Error $_.Exception
450
Start-Sleep $retryInterval
454
$ErrorActionPreference = $currErrorActionPreference
457
# TryExecAll attempts all of the commands in the supplied array until
458
# one can be executed without throwing an exception. If none of the
459
# commands succeeds, an exception will be raised.
460
function TryExecAll($commands)
462
$currErrorActionPreference = $ErrorActionPreference
463
$ErrorActionPreference = "Continue"
465
foreach ($command in $commands)
470
$ErrorActionPreference = $currErrorActionPreference
473
catch [System.Exception]
475
Write-Error $_.Exception
479
$ErrorActionPreference = $currErrorActionPreference
480
throw "All commands failed"
483
Function GUnZip-File{
489
$input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
490
$tempFile = "$env:TEMP\jujud.tar"
491
$tempOut = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
492
$gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)
494
$buffer = New-Object byte[](1024)
496
$read = $gzipstream.Read($buffer, 0, 1024)
497
if ($read -le 0){break}
498
$tempOut.Write($buffer, 0, $read)
504
$in = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
505
Untar-File $in $outdir
512
Function Untar-File {
517
$DirectoryEntryType = 0x35
518
$headerBytes = New-Object byte[]($HEADERSIZE)
520
# $headerBytes is written inside, function returns whether we've reached the end
521
while(GetHeaderBytes $inStream $headerBytes) {
522
$fileName, $entryType, $sizeInBytes = GetFileInfoFromHeader $headerBytes
524
$totalPath = Join-Path $outDir $fileName
525
if ($entryType -eq $DirectoryEntryType) {
526
[System.IO.Directory]::CreateDirectory($totalPath)
530
$fName = [System.IO.Path]::GetFileName($totalPath)
531
$dirName = [System.IO.Path]::GetDirectoryName($totalPath)
532
[System.IO.Directory]::CreateDirectory($dirName)
533
$file = [System.IO.File]::Create($totalPath)
534
WriteTarEntryToFile $inStream $file $sizeInBytes
539
Function WriteTarEntryToFile {
547
$buf = New-Object byte[](512)
549
$remainingBytesInFile = $sizeInBytes
550
while ($remainingBytesInFile -ne 0) {
551
if ($remainingBytesInFile - 512 -lt 0) {
552
$moveToAlign512 = 512 - $remainingBytesInFile
553
$toRead = $remainingBytesInFile
559
$bytesRemainingToRead = $toRead
560
while ($bytesRead -lt $toRead -and $bytesRemainingToRead -gt 0) {
561
$bytesRead = $inStream.Read($buf, $toRead - $bytesRemainingToRead, $bytesRemainingToRead)
562
$bytesRemainingToRead = $bytesRemainingToRead - $bytesRead
563
$remainingBytesInFile = $remainingBytesInFile - $bytesRead
564
$outFile.Write($buf, 0, $bytesRead)
567
if ($moveToAlign512 -ne 0) {
568
$inStream.Seek($moveToAlign512, [System.IO.SeekOrigin]::Current)
573
Function GetHeaderBytes {
574
Param($inStream, $headerBytes)
577
$bytesRemaining = $HEADERSIZE
578
while ($bytesRemaining -gt 0) {
579
$headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining)
580
$bytesRemaining -= $headerRead
581
if ($headerRead -le 0 -and $bytesRemaining -gt 0) {
582
throw "Error reading tar header. Header size invalid"
586
# Proper end of archive is 2 empty headers
587
if (IsEmptyByteArray $headerBytes) {
588
$bytesRemaining = $HEADERSIZE
589
while ($bytesRemaining -gt 0) {
590
$headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining)
591
$bytesRemaining -= $headerRead
592
if ($headerRead -le 0 -and $bytesRemaining -gt 0) {
593
throw "Broken end archive"
596
if ($bytesRemaining -eq 0 -and (IsEmptyByteArray($headerBytes))) {
599
throw "Error occurred: expected end of archive"
605
Function GetFileInfoFromHeader {
608
$FileName = [System.Text.Encoding]::UTF8.GetString($headerBytes, 0, 100);
609
$EntryType = $headerBytes[156];
610
$SizeInBytes = [Convert]::ToInt64([System.Text.Encoding]::ASCII.GetString($headerBytes, 124, 11).Trim(), 8);
611
Return $FileName.replace("` + "`" + `0", [String].Empty), $EntryType, $SizeInBytes
614
Function IsEmptyByteArray {
616
foreach($b in $bytes) {
624
Function Get-FileSHA256{
629
$hash = [Security.Cryptography.HashAlgorithm]::Create( "SHA256" )
630
$stream = ([IO.StreamReader]$FilePath).BaseStream
631
$res = -join ($hash.ComputeHash($stream) | ForEach { "{0:x2}" -f $_ })
634
} catch [System.Management.Automation.RuntimeException] {
635
return (Get-FileHash -Path $FilePath).Hash
639
Function Invoke-FastWebRequest {
645
if(!([System.Management.Automation.PSTypeName]'System.Net.Http.HttpClient').Type)
647
$assembly = [System.Reflection.Assembly]::LoadWithPartialName("System.Net.Http")
650
$client = new-object System.Net.Http.HttpClient
652
$task = $client.GetStreamAsync($URI)
653
$response = $task.Result
654
$outStream = New-Object IO.FileStream $OutFile, Create, Write, None
658
$buffer = New-Object Byte[] 1MB
659
while (($read = $response.Read($buffer, 0, $buffer.Length)) -gt 0) {
661
$outStream.Write($buffer, 0, $read);