Greg Karékinian bdfb3a1afb Downgrade mysql cookbook for now
It doesn't play well with our current dev server setup
2017-06-16 22:44:57 +02:00

290 lines
8.9 KiB
Ruby

# -*- coding: utf-8 -*-
#
# Author:: Sölvi Páll Ásgeirsson (<solvip@gmail.com>), Richard Lavey (richard.lavey@calastone.com)
# Cookbook:: windows
# Resource:: share
#
# Copyright:: 2014-2017, Sölvi Páll Ásgeirsson.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
property :share_name, String, name_property: true
property :path, String, required: true
property :description, String, default: ''
property :full_users, Array, default: []
property :change_users, Array, default: []
property :read_users, Array, default: []
include Windows::Helper
include Chef::Mixin::PowershellOut
require 'win32ole' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
ACCESS_FULL = 2_032_127
ACCESS_CHANGE = 1_245_631
ACCESS_READ = 1_179_817
action :create do
if different_path?
unless current_resource.path.nil? || current_resource.path.empty?
converge_by('Removing previous share') do
delete_share
end
end
converge_by("Creating share #{current_resource.share_name}") do
create_share
end
end
if different_members?(:full_users) ||
different_members?(:change_users) ||
different_members?(:read_users) ||
different_description?
converge_by("Setting permissions and description for #{new_resource.share_name}") do
set_share_permissions
end
end
end
action :delete do
if !current_resource.path.nil? && !current_resource.path.empty?
converge_by("Deleting #{current_resource.share_name}") do
delete_share
end
else
Chef::Log.debug("#{current_resource.share_name} does not exist - nothing to do")
end
end
load_current_value do |desired|
wmi = WIN32OLE.connect('winmgmts://')
shares = wmi.ExecQuery("SELECT * FROM Win32_Share WHERE name = '#{desired.share_name}'")
existing_share = shares.Count == 0 ? nil : shares.ItemIndex(0)
description ''
unless existing_share.nil?
path existing_share.Path
description existing_share.Description
end
perms = share_permissions name
unless perms.nil?
full_users perms[:full_users]
change_users perms[:change_users]
read_users perms[:read_users]
end
end
def share_permissions(name)
wmi = WIN32OLE.connect('winmgmts://')
shares = wmi.ExecQuery("SELECT * FROM Win32_LogicalShareSecuritySetting WHERE name = '#{name}'")
# The security descriptor is an output parameter
sd = nil
begin
shares.ItemIndex(0).GetSecurityDescriptor(sd)
sd = WIN32OLE::ARGV[0]
rescue WIN32OLERuntimeError
Chef::Log.warn('Failed to retrieve any security information about the share.')
end
read = []
change = []
full = []
unless sd.nil?
sd.DACL.each do |dacl|
trustee = "#{dacl.Trustee.Domain}\\#{dacl.Trustee.Name}".downcase
case dacl.AccessMask
when ACCESS_FULL
full.push(trustee)
when ACCESS_CHANGE
change.push(trustee)
when ACCESS_READ
read.push(trustee)
else
Chef::Log.warn "Unknown access mask #{dacl.AccessMask} for user #{trustee}. This will be lost if permissions are updated"
end
end
end
{
full_users: full,
change_users: change,
read_users: read,
}
end
action_class do
def description_exists?(resource)
!resource.description.nil?
end
def different_description?
if description_exists?(new_resource) && description_exists?(current_resource)
new_resource.description.casecmp(current_resource.description) != 0
else
description_exists?(new_resource) || description_exists?(current_resource)
end
end
def different_path?
return true if current_resource.path.nil?
win_friendly_path(new_resource.path).casecmp(win_friendly_path(current_resource.path)) != 0
end
def different_members?(permission_type)
!(current_resource.send(permission_type.to_sym) - new_resource.send(permission_type.to_sym).map(&:downcase)).empty? &&
!(new_resource.send(permission_type.to_sym).map(&:downcase) - current_resource.send(permission_type.to_sym)).empty?
end
def find_share_by_name(name)
wmi = WIN32OLE.connect('winmgmts://')
shares = wmi.ExecQuery("SELECT * FROM Win32_Share WHERE name = '#{name}'")
shares.Count == 0 ? nil : shares.ItemIndex(0)
end
def delete_share
find_share_by_name(new_resource.share_name).delete
end
def create_share
raise "#{new_resource.path} is missing or not a directory" unless ::File.directory? new_resource.path
new_share_script = <<-EOH
$share = [wmiclass]"\\\\#{ENV['COMPUTERNAME']}\\root\\CimV2:Win32_Share"
$result=$share.Create('#{new_resource.path}',
'#{new_resource.share_name}',
0,
16777216,
'#{new_resource.description}',
$null,
$null)
exit $result.returnValue
EOH
r = powershell_out new_share_script
message = case r.exitstatus
when 2
'2 : Access Denied'
when 8
'8 : Unknown Failure'
when 9
'9 : Invalid Name'
when 10
'10 : Invalid Level'
when 21
'21 : Invalid Parameter'
when 22
'22 : Duplicate Share'
when 23
'23 : Redirected Path'
when 24
'24 : Unknown Device or Directory'
when 25
'25 : Net Name Not Found'
else
r.exitstatus.to_s
end
raise "Could not create share. Win32_Share.create returned #{message}" if r.error?
end
# set_share_permissions - Enforce the share permissions as dictated by the resource attributes
def set_share_permissions
share_permissions_script = <<-EOH
Function New-SecurityDescriptor
{
param (
[array]$ACEs
)
#Create SeCDesc object
$SecDesc = ([WMIClass] "\\\\$env:ComputerName\\root\\cimv2:Win32_SecurityDescriptor").CreateInstance()
foreach ($ACE in $ACEs )
{
$SecDesc.DACL += $ACE.psobject.baseobject
}
#Return the security Descriptor
return $SecDesc
}
Function New-ACE
{
param (
[string] $Name,
[string] $Domain,
[string] $Permission = "Read"
)
#Create the Trusteee Object
$Trustee = ([WMIClass] "\\\\$env:computername\\root\\cimv2:Win32_Trustee").CreateInstance()
$account = get-wmiobject Win32_Account -filter "Name like '$Name' and Domain like '$Domain'"
$accountSID = [WMI] "\\\\$env:ComputerName\\root\\cimv2:Win32_SID.SID='$($account.sid)'"
$Trustee.Domain = $Domain
$Trustee.Name = $Name
$Trustee.SID = $accountSID.BinaryRepresentation
#Create ACE (Access Control List) object.
$ACE = ([WMIClass] "\\\\$env:ComputerName\\root\\cimv2:Win32_ACE").CreateInstance()
switch ($Permission)
{
"Read" { $ACE.AccessMask = 1179817 }
"Change" { $ACE.AccessMask = 1245631 }
"Full" { $ACE.AccessMask = 2032127 }
default { throw "$Permission is not a supported permission value. Possible values are 'Read','Change','Full'" }
}
$ACE.AceFlags = 3
$ACE.AceType = 0
$ACE.Trustee = $Trustee
$ACE
}
$dacl_array = @()
EOH
new_resource.full_users.each do |user|
share_permissions_script += user_to_ace(user, 'Full')
end
new_resource.change_users.each do |user|
share_permissions_script += user_to_ace(user, 'Change')
end
new_resource.read_users.each do |user|
share_permissions_script += user_to_ace(user, 'Read')
end
share_permissions_script += <<-EOH
$dacl = New-SecurityDescriptor -Aces $dacl_array
$share = get-wmiobject win32_share -filter 'Name like "#{new_resource.share_name}"'
$return = $share.SetShareInfo($null, '#{new_resource.description}', $dacl)
exit $return.returnValue
EOH
r = powershell_out(share_permissions_script)
raise "Could not set share permissions. Win32_Share.SedtShareInfo returned #{r.exitstatus}" if r.error?
end
def user_to_ace(fully_qualified_user_name, access)
domain, user = fully_qualified_user_name.split('\\')
unless domain && user
raise "Invalid user entry #{fully_qualified_user_name}. The user names must be specified as 'DOMAIN\\user'"
end
"\n$dacl_array += new-ace -Name '#{user}' -domain '#{domain}' -permission '#{access}'"
end
end