File Manager
Viewing File: securable.rb
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright 2011-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# 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.
#
class Chef
module Mixin
module Securable
def owner(arg = nil)
set_or_return(
:owner,
arg,
:regex => Chef::Config[:user_valid_regex]
)
end
alias :user :owner
def group(arg = nil)
set_or_return(
:group,
arg,
:regex => Chef::Config[:group_valid_regex]
)
end
def mode(arg = nil)
set_or_return(
:mode,
arg,
:callbacks => {
"not in valid numeric range" => lambda do |m|
if m.kind_of?(String)
m =~ /^0/ || m = "0#{m}"
end
# Windows does not support the sticky or setuid bits
if Chef::Platform.windows?
Integer(m) <= 0777 && Integer(m) >= 0
else
Integer(m) <= 07777 && Integer(m) >= 0
end
end,
}
)
end
#==WindowsMacros
# Defines methods for adding attributes to a chef resource to describe
# Windows file security metadata.
#
# This module is meant to be used to extend a class (instead of
# `include`-ing). A class is automatically extended with this module when
# it includes WindowsSecurableAttributes.
# --
# TODO should this be separated into different files?
module WindowsMacros
# === rights_attribute
# "meta-method" for dynamically creating rights attributes on resources.
#
# Multiple rights attributes can be declared. This enables resources to
# have multiple rights attributes with separate runtime states.
#
# For example, +Chef::Resource::RemoteDirectory+ supports different
# rights on the directories and files by declaring separate rights
# attributes for each (rights and files_rights).
#
# ==== User Level API
# Given a resource that calls
#
# rights_attribute(:rights)
#
# Then the resource DSL could be used like this:
#
# rights :read, ["Administrators","Everyone"]
# rights :deny, "Pinky"
# rights :full_control, "Users", :applies_to_children => true
# rights :write, "John Keiser", :applies_to_children => :containers_only, :applies_to_self => false, :one_level_deep => true
#
# ==== Internal Data Structure
# rights attributes support multiple right declarations
# in a single resource block--the data will be merged
# into a single internal hash.
#
# The internal representation is a hash with the following keys:
#
# * `:permissions`: Integer of Windows permissions flags, 1..2^32
# or one of `[:full_control, :modify, :read_execute, :read, :write]`
# * `:principals`: String or Array of Strings represnting usernames on
# the system.
# * `:applies_to_children` (optional): Boolean
# * `:applies_to_self` (optional): Boolean
# * `:one_level_deep` (optional): Boolean
#
def rights_attribute(name)
# equivalent to something like:
# def rights(permissions=nil, principals=nil, args_hash=nil)
define_method(name) do |permissions = nil, principals = nil, args_hash = nil|
rights = instance_variable_get("@#{name}".to_sym)
unless permissions.nil?
input = {
:permissions => permissions,
:principals => principals,
}
input.merge!(args_hash) unless args_hash.nil?
validations = { :permissions => { :required => true },
:principals => { :required => true, :kind_of => [String, Array] },
:applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ] },
:applies_to_self => { :kind_of => [ TrueClass, FalseClass ] },
:one_level_deep => { :kind_of => [ TrueClass, FalseClass ] },
}
validate(input, validations)
[ permissions ].flatten.each do |permission|
if permission.is_a?(Integer)
if permission < 0 || permission > 1 << 32
raise ArgumentError, "permissions flags must be positive and <= 32 bits (#{permission})"
end
elsif !([:full_control, :modify, :read_execute, :read, :write].include?(permission.to_sym))
raise ArgumentError, "permissions parameter must be :full_control, :modify, :read_execute, :read, :write or an integer representing Windows permission flags"
end
end
[ principals ].flatten.each do |principal|
if !principal.is_a?(String)
raise ArgumentError, "principals parameter must be a string or array of strings representing usernames"
end
end
if input[:applies_to_children] == false
if input[:applies_to_self] == false
raise ArgumentError, "'rights' attribute must specify either :applies_to_children or :applies_to_self."
end
if input[:one_level_deep] == true
raise ArgumentError, "'rights' attribute specified :one_level_deep without specifying :applies_to_children."
end
end
rights ||= []
rights << input
end
set_or_return(
name,
rights,
{}
)
end
end
end
#==WindowsSecurableAttributes
# Defines #inherits to describe Windows file security ACLs on the
# including class
module WindowsSecurableAttributes
def inherits(arg = nil)
set_or_return(
:inherits,
arg,
:kind_of => [ TrueClass, FalseClass ]
)
end
end
if RUBY_PLATFORM =~ /mswin|mingw|windows/
include WindowsSecurableAttributes
end
# Callback that fires when included; will extend the including class
# with WindowsMacros and define #rights and #deny_rights on it.
def self.included(including_class)
if RUBY_PLATFORM =~ /mswin|mingw|windows/
including_class.extend(WindowsMacros)
# create a default 'rights' attribute
including_class.rights_attribute(:rights)
including_class.rights_attribute(:deny_rights)
end
end
end
end
end