2015-07-15 13:15:18 +00:00
# encoding: utf-8
# copyright: 2015, Vulcano Security GmbH
2015-10-06 16:55:44 +00:00
# author: Dominik Richter
# author: Christoph Hartmann
2015-07-15 13:15:18 +00:00
2016-03-31 00:23:23 +00:00
require 'shellwords'
2015-10-26 03:04:18 +00:00
module Inspec::Resources
2016-10-13 14:05:57 +00:00
module FilePermissionsSelector
2016-10-12 01:55:45 +00:00
def select_file_perms_style ( os )
if os . unix?
2016-10-25 15:18:14 +00:00
UnixFilePermissions . new ( inspec )
2016-10-12 01:55:45 +00:00
elsif os . windows?
2016-10-25 15:18:14 +00:00
WindowsFilePermissions . new ( inspec )
2016-10-12 01:55:45 +00:00
end
end
end
2016-11-03 11:45:04 +00:00
class FileResource < Inspec . resource ( 1 )
2016-10-13 14:05:57 +00:00
include FilePermissionsSelector
2017-02-22 17:29:49 +00:00
include LinuxMountParser
2016-10-12 01:55:45 +00:00
2015-08-30 00:14:17 +00:00
name 'file'
2015-11-27 13:02:38 +00:00
desc 'Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, named pipes, sockets, character devices, block devices, and doors.'
example "
describe file ( 'path' ) do
it { should exist }
it { should be_file }
it { should be_readable }
it { should be_writable }
2016-10-25 19:03:42 +00:00
it { should be_executable . by_user ( 'root' ) }
2015-11-27 13:02:38 +00:00
it { should be_owned_by 'root' }
2016-04-20 11:06:40 +00:00
its ( 'mode' ) { should cmp '0644' }
2015-11-27 13:02:38 +00:00
end
"
2015-08-29 07:44:16 +00:00
2016-04-28 16:35:55 +00:00
attr_reader :file , :mount_options
2015-08-30 00:14:17 +00:00
def initialize ( path )
2016-10-12 01:55:45 +00:00
# select permissions style
@perms_provider = select_file_perms_style ( inspec . os )
2016-04-28 16:35:55 +00:00
@file = inspec . backend . file ( path )
2015-08-30 00:14:17 +00:00
end
2015-08-29 07:44:16 +00:00
2015-08-30 00:14:17 +00:00
%w{
2015-09-18 10:35:32 +00:00
type exist? file? block_device? character_device? socket? directory?
2016-04-28 16:35:55 +00:00
symlink? pipe? mode mode? owner owned_by? group grouped_into?
2016-02-22 03:44:49 +00:00
link_path linked_to? mtime size selinux_label immutable?
2015-09-05 14:07:54 +00:00
product_version file_version version? md5sum sha256sum
2016-04-29 17:28:34 +00:00
path basename source source_path uid gid
2015-09-03 14:17:52 +00:00
} . each do | m |
define_method m . to_sym do | * args |
2015-12-07 19:41:05 +00:00
file . method ( m . to_sym ) . call ( * args )
2015-08-30 00:14:17 +00:00
end
2015-08-29 07:44:16 +00:00
end
2016-02-22 03:44:49 +00:00
def content
res = file . content
return nil if res . nil?
res . force_encoding ( 'utf-8' )
end
2015-09-09 16:52:27 +00:00
def contain ( * _ )
2017-02-08 22:49:16 +00:00
raise 'Contain is not supported. Please use standard RSpec matchers.'
2015-08-30 00:14:17 +00:00
end
2015-08-29 07:44:16 +00:00
2015-12-07 19:41:05 +00:00
def readable? ( by_usergroup , by_specific_user )
return false unless exist?
2016-10-17 13:41:36 +00:00
return skip_resource '`readable?` is not supported on your OS yet.' if @perms_provider . nil?
2015-12-07 19:41:05 +00:00
2016-10-12 01:55:45 +00:00
file_permission_granted? ( 'read' , by_usergroup , by_specific_user )
2015-08-30 00:14:17 +00:00
end
2015-08-29 07:44:16 +00:00
2015-12-07 19:41:05 +00:00
def writable? ( by_usergroup , by_specific_user )
return false unless exist?
2016-10-17 13:41:36 +00:00
return skip_resource '`writable?` is not supported on your OS yet.' if @perms_provider . nil?
2015-12-07 19:41:05 +00:00
2016-10-12 01:55:45 +00:00
file_permission_granted? ( 'write' , by_usergroup , by_specific_user )
2015-06-21 09:23:30 +00:00
end
2015-08-29 07:44:16 +00:00
2015-12-07 19:41:05 +00:00
def executable? ( by_usergroup , by_specific_user )
return false unless exist?
2016-10-17 13:41:36 +00:00
return skip_resource '`executable?` is not supported on your OS yet.' if @perms_provider . nil?
2015-12-07 19:41:05 +00:00
2016-10-12 01:55:45 +00:00
file_permission_granted? ( 'execute' , by_usergroup , by_specific_user )
2015-08-29 07:44:16 +00:00
end
2015-12-31 00:08:57 +00:00
def mounted? ( expected_options = nil , identical = false )
mounted = file . mounted
# return if no additional parameters have been provided
return file . mounted? if expected_options . nil?
2016-01-02 23:01:54 +00:00
# deprecation warning, this functionality will be removed in future version
2016-04-28 23:56:13 +00:00
warn " [DEPRECATION] `be_mounted.with and be_mounted.only_with` are deprecated. Please use `mount(' #{ source_path } ')` instead. "
2016-01-02 23:01:54 +00:00
2016-01-02 21:57:52 +00:00
# we cannot read mount data on non-Linux systems
return nil if ! inspec . os . linux?
2015-12-31 00:08:57 +00:00
# parse content if we are on linux
@mount_options || = parse_mount_options ( mounted . stdout , true )
if identical
# check if the options should be identical
@mount_options == expected_options
else
# otherwise compare the selected values
@mount_options . contains ( expected_options )
end
end
2016-07-10 18:40:06 +00:00
def suid
( mode & 04000 ) > 0
end
def sgid
( mode & 02000 ) > 0
end
def sticky
( mode & 01000 ) > 0
end
2015-08-30 00:14:17 +00:00
def to_s
2016-04-28 23:56:13 +00:00
" File #{ source_path } "
2015-08-30 00:14:17 +00:00
end
2015-10-25 20:35:35 +00:00
private
2016-11-03 11:45:04 +00:00
def file_permission_granted? ( access_type , by_usergroup , by_specific_user )
2017-02-08 22:49:16 +00:00
raise '`file_permission_granted?` is not supported on your OS' if @perms_provider . nil?
2015-12-21 22:12:29 +00:00
if by_specific_user . nil? || by_specific_user . empty?
2016-11-03 11:45:04 +00:00
@perms_provider . check_file_permission_by_mask ( file , access_type , by_usergroup , by_specific_user )
2015-12-07 19:41:05 +00:00
else
2016-11-03 11:45:04 +00:00
@perms_provider . check_file_permission_by_user ( access_type , by_specific_user , source_path )
2015-10-25 20:35:35 +00:00
end
2015-12-07 19:41:05 +00:00
end
2016-11-03 11:45:04 +00:00
end
2015-12-07 19:41:05 +00:00
2016-11-03 11:45:04 +00:00
class FilePermissions
attr_reader :inspec
def initialize ( inspec )
@inspec = inspec
end
end
2015-10-25 20:35:35 +00:00
2016-11-03 11:45:04 +00:00
class UnixFilePermissions < FilePermissions
def permission_flag ( access_type )
case access_type
when 'read'
'r'
when 'write'
'w'
when 'execute'
'x'
else
2017-02-08 22:49:16 +00:00
raise 'Invalid access_type provided'
2016-11-03 11:45:04 +00:00
end
2015-12-07 19:41:05 +00:00
end
2016-10-12 01:55:45 +00:00
def usergroup_for ( usergroup , specific_user )
if usergroup == 'others'
'other'
elsif ( usergroup . nil? || usergroup . empty? ) && specific_user . nil?
'all'
else
usergroup
end
end
2016-11-03 11:45:04 +00:00
def check_file_permission_by_mask ( file , access_type , usergroup , specific_user )
usergroup = usergroup_for ( usergroup , specific_user )
flag = permission_flag ( access_type )
mask = file . unix_mode_mask ( usergroup , flag )
2017-02-08 22:49:16 +00:00
raise 'Invalid usergroup/owner provided' if mask . nil?
2016-11-03 11:45:04 +00:00
( file . mode & mask ) != 0
2016-10-12 01:55:45 +00:00
end
2016-11-03 11:45:04 +00:00
def check_file_permission_by_user ( access_type , user , path )
flag = permission_flag ( access_type )
2016-01-28 22:33:11 +00:00
if inspec . os . linux?
2016-10-12 01:55:45 +00:00
perm_cmd = " su -s /bin/sh -c \" test - #{ flag } #{ path } \" #{ user } "
2016-01-28 22:33:11 +00:00
elsif inspec . os . bsd? || inspec . os . solaris?
2016-10-12 01:55:45 +00:00
perm_cmd = " sudo -u #{ user } test - #{ flag } #{ path } "
2016-01-28 22:33:11 +00:00
elsif inspec . os . aix?
2016-10-12 01:55:45 +00:00
perm_cmd = " su #{ user } -c test - #{ flag } #{ path } "
2016-04-26 09:23:28 +00:00
elsif inspec . os . hpux?
2016-10-12 01:55:45 +00:00
perm_cmd = " su #{ user } -c \" test - #{ flag } #{ path } \" "
2015-10-25 20:35:35 +00:00
else
return skip_resource 'The `file` resource does not support `by_user` on your OS.'
end
2015-12-07 19:41:05 +00:00
cmd = inspec . command ( perm_cmd )
cmd . exit_status == 0 ? true : false
end
2016-10-12 01:55:45 +00:00
end
2015-12-07 19:41:05 +00:00
2016-10-13 14:05:57 +00:00
class WindowsFilePermissions < FilePermissions
2016-11-03 11:45:04 +00:00
def check_file_permission_by_mask ( _file , _access_type , _usergroup , _specific_user )
2017-02-08 22:49:16 +00:00
raise '`check_file_permission_by_mask` is not supported on Windows'
2016-11-03 11:45:04 +00:00
end
def check_file_permission_by_user ( access_type , user , path )
2016-10-12 01:55:45 +00:00
access_rule = case access_type
when 'read'
'@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'Read\', \'ListDirectory\')'
when 'write'
'@(\'FullControl\', \'Modify\', \'Write\')'
when 'execute'
'@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'ExecuteFile\')'
2016-10-17 13:41:36 +00:00
else
2017-02-08 22:49:16 +00:00
raise 'Invalid access_type provided'
2016-10-12 01:55:45 +00:00
end
2016-10-25 15:18:14 +00:00
cmd = inspec . command ( " @(@((Get-Acl ' #{ path } ').access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq ' #{ user } ' }) | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? { #{ access_rule } -contains $_}) -ne $null}) | measure | % { $_.Count } " )
2016-10-12 01:55:45 +00:00
cmd . stdout . chomp == '0' ? false : true
2015-12-07 19:41:05 +00:00
end
2015-08-29 07:44:16 +00:00
end
end