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'`