diff --git a/.rubocop.yml b/.rubocop.yml index 0a1518b..47a0129 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,517 +1,514 @@ require: rubocop-rspec AllCops: - TargetRubyVersion: 1.9 + TargetRubyVersion: 2.2 Include: - ./**/*.rb Exclude: - files/**/* - vendor/**/* - .vendor/**/* - pkg/**/* - spec/fixtures/**/* - Gemfile - Rakefile Lint/ConditionPosition: Enabled: true Lint/ElseLayout: Enabled: true Lint/UnreachableCode: Enabled: true Lint/UselessComparison: Enabled: true Lint/EnsureReturn: Enabled: true Lint/HandleExceptions: Enabled: true -Lint/LiteralInCondition: - Enabled: true - Lint/ShadowingOuterLocalVariable: Enabled: true Lint/LiteralInInterpolation: Enabled: true Style/HashSyntax: Enabled: false Style/RedundantReturn: Enabled: true Lint/AmbiguousOperator: Enabled: true Lint/AssignmentInCondition: Enabled: true Layout/SpaceBeforeComment: Enabled: true Style/AndOr: Enabled: true Style/RedundantSelf: Enabled: true # Method length is not necessarily an indicator of code quality Metrics/MethodLength: Enabled: false # Module length is not necessarily an indicator of code quality Metrics/ModuleLength: Enabled: false Style/WhileUntilModifier: Enabled: true Lint/AmbiguousRegexpLiteral: Enabled: true Security/Eval: Enabled: true Lint/BlockAlignment: Enabled: true Lint/DefEndAlignment: Enabled: true Lint/EndAlignment: Enabled: true Lint/DeprecatedClassMethods: Enabled: true Lint/Loop: Enabled: true Lint/ParenthesesAsGroupedExpression: Enabled: true Lint/RescueException: Enabled: true Lint/StringConversionInInterpolation: Enabled: true Lint/UnusedBlockArgument: Enabled: true Lint/UnusedMethodArgument: Enabled: true Lint/UselessAccessModifier: Enabled: true Lint/UselessAssignment: Enabled: true Lint/Void: Enabled: true Layout/AccessModifierIndentation: Enabled: true -Style/AccessorMethodName: +Naming/AccessorMethodName: Enabled: true Style/Alias: Enabled: true Layout/AlignArray: Enabled: true Layout/AlignHash: Enabled: true Layout/AlignParameters: Enabled: true Metrics/BlockNesting: Enabled: true Style/AsciiComments: Enabled: true Style/Attr: Enabled: true Style/BracesAroundHashParameters: Enabled: true Style/CaseEquality: Enabled: true Layout/CaseIndentation: Enabled: true Style/CharacterLiteral: Enabled: true -Style/ClassAndModuleCamelCase: +Naming/ClassAndModuleCamelCase: Enabled: true Style/ClassAndModuleChildren: Enabled: false Style/ClassCheck: Enabled: true # Class length is not necessarily an indicator of code quality Metrics/ClassLength: Enabled: false Style/ClassMethods: Enabled: true Style/ClassVars: Enabled: true Style/WhenThen: Enabled: true Style/WordArray: Enabled: true Style/UnneededPercentQ: Enabled: true Layout/Tab: Enabled: true Layout/SpaceBeforeSemicolon: Enabled: true Layout/TrailingBlankLines: Enabled: true Layout/SpaceInsideBlockBraces: Enabled: true -Layout/SpaceInsideBrackets: - Enabled: true - Layout/SpaceInsideHashLiteralBraces: Enabled: true Layout/SpaceInsideParens: Enabled: true Layout/LeadingCommentSpace: Enabled: true Layout/SpaceBeforeFirstArg: Enabled: true Layout/SpaceAfterColon: Enabled: true Layout/SpaceAfterComma: Enabled: true Layout/SpaceAfterMethodName: Enabled: true Layout/SpaceAfterNot: Enabled: true Layout/SpaceAfterSemicolon: Enabled: true Layout/SpaceAroundEqualsInParameterDefault: Enabled: true Layout/SpaceAroundOperators: Enabled: true Layout/SpaceBeforeBlockBraces: Enabled: true Layout/SpaceBeforeComma: Enabled: true Style/CollectionMethods: Enabled: true Layout/CommentIndentation: Enabled: true Style/ColonMethodCall: Enabled: true Style/CommentAnnotation: Enabled: true # 'Complexity' is very relative Metrics/CyclomaticComplexity: Enabled: false -Style/ConstantName: +Naming/ConstantName: Enabled: true Style/Documentation: Enabled: false Style/DefWithParentheses: Enabled: true Style/PreferredHashMethods: Enabled: true Layout/DotPosition: EnforcedStyle: trailing Style/DoubleNegation: Enabled: true Style/EachWithObject: Enabled: true Layout/EmptyLineBetweenDefs: Enabled: true Layout/IndentArray: Enabled: true Layout/IndentHash: Enabled: true Layout/IndentationConsistency: Enabled: true Layout/IndentationWidth: Enabled: true Layout/EmptyLines: Enabled: true Layout/EmptyLinesAroundAccessModifier: Enabled: true Style/EmptyLiteral: Enabled: true # Configuration parameters: AllowURI, URISchemes. Metrics/LineLength: Enabled: false Style/MethodDefParentheses: Enabled: true Style/LineEndConcatenation: Enabled: true Layout/TrailingWhitespace: Enabled: true Style/StringLiterals: Enabled: true Style/TrailingCommaInArguments: Enabled: true Style/TrailingCommaInLiteral: Enabled: true Style/GlobalVars: Enabled: true Style/GuardClause: Enabled: true Style/IfUnlessModifier: Enabled: true Style/MultilineIfThen: Enabled: true Style/NegatedIf: Enabled: true Style/NegatedWhile: Enabled: true Style/Next: Enabled: true Style/SingleLineBlockParams: Enabled: true Style/SingleLineMethods: Enabled: true Style/SpecialGlobalVars: Enabled: true Style/TrivialAccessors: Enabled: true Style/UnlessElse: Enabled: true Style/VariableInterpolation: Enabled: true -Style/VariableName: +Naming/VariableName: Enabled: true Style/WhileUntilDo: Enabled: true Style/EvenOdd: Enabled: true -Style/FileName: +Naming/FileName: Enabled: true Style/For: Enabled: true Style/Lambda: Enabled: true -Style/MethodName: +Naming/MethodName: Enabled: true Style/MultilineTernaryOperator: Enabled: true Style/NestedTernaryOperator: Enabled: true Style/NilComparison: Enabled: true Style/FormatString: Enabled: true Style/MultilineBlockChain: Enabled: true Style/Semicolon: Enabled: true Style/SignalException: Enabled: true Style/NonNilCheck: Enabled: true Style/Not: Enabled: true Style/NumericLiterals: Enabled: true Style/OneLineConditional: Enabled: true -Style/OpMethod: +Naming/BinaryOperatorParameterName: Enabled: true Style/ParenthesesAroundCondition: Enabled: true Style/PercentLiteralDelimiters: Enabled: true Style/PerlBackrefs: Enabled: true -Style/PredicateName: +Naming/PredicateName: Enabled: true Style/RedundantException: Enabled: true Style/SelfAssignment: Enabled: true Style/Proc: Enabled: true Style/RaiseArgs: Enabled: true Style/RedundantBegin: Enabled: true Style/RescueModifier: Enabled: true # based on https://github.com/voxpupuli/modulesync_config/issues/168 Style/RegexpLiteral: EnforcedStyle: percent_r Enabled: true Lint/UnderscorePrefixedVariableName: Enabled: true Metrics/ParameterLists: Enabled: false Lint/RequireParentheses: Enabled: true Layout/SpaceBeforeFirstArg: Enabled: true Style/ModuleFunction: Enabled: true Lint/Debugger: Enabled: true Style/IfWithSemicolon: Enabled: true Style/Encoding: Enabled: true Style/BlockDelimiters: Enabled: true Style/FormatStringToken: Enabled: false Layout/MultilineBlockLayout: Enabled: true # 'Complexity' is very relative Metrics/AbcSize: Enabled: False Metrics/BlockLength: Enabled: False # 'Complexity' is very relative Metrics/PerceivedComplexity: Enabled: False Lint/UselessAssignment: Enabled: true Layout/ClosingParenthesisIndentation: Enabled: false Metrics/BlockLength: Enabled: false # RSpec # We don't use rspec in this way RSpec/DescribeClass: Enabled: False # Example length is not necessarily an indicator of code quality RSpec/ExampleLength: Enabled: False RSpec/NestedGroups: Max: 4 + +RSpec/MultipleExpectations: + Max: 2 diff --git a/manifests/conf.pp b/manifests/conf.pp index 998d5f5..ab362f1 100644 --- a/manifests/conf.pp +++ b/manifests/conf.pp @@ -1,124 +1,124 @@ # Define: sudo::conf # # This module manages sudo configurations # # Parameters: # [*ensure*] # Ensure if present or absent. # Default: present # # [*priority*] # Prefix file name with $priority # Default: 10 # # [*content*] # Content of configuration snippet. # Default: undef # # [*source*] # Source of configuration snippet. # Default: undef # # [*sudo_config_dir*] # Where to place configuration snippets. # Only set this, if your platform is not supported or # you know, what you're doing. # Default: auto-set, platform specific # # Actions: # Installs sudo configuration snippets # # Requires: # Class sudo # # Sample Usage: # sudo::conf { 'admins': # source => 'puppet:///files/etc/sudoers.d/admins', # } # # [Remember: No empty lines between comments and class definition] define sudo::conf( $ensure = present, $priority = 10, $content = undef, $source = undef, $template = undef, $sudo_config_dir = undef, $sudo_file_name = undef, $sudo_syntax_path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' ) { include ::sudo # Hack to allow the user to set the config_dir from the # sudo::config parameter, but default to $sudo::params::config_dir # if it is not provided. $sudo::params isn't included before # the parameters are loaded in. $sudo_config_dir_real = $sudo_config_dir ? { undef => $sudo::config_dir, $sudo_config_dir => $sudo_config_dir } # sudo skip file name that contain a "." $dname = regsubst($name, '\.', '-', 'G') if size("x${priority}") == 2 { $priority_real = "0${priority}" } else { $priority_real = $priority } # build current file name with path if $sudo_file_name != undef { $cur_file = "${sudo_config_dir_real}/${sudo_file_name}" } else { $cur_file = "${sudo_config_dir_real}/${priority_real}_${dname}" } # replace whitespace in file name $cur_file_real = regsubst($cur_file, '\s+', '_', 'G') Class['sudo'] -> Sudo::Conf[$name] if $::osfamily == 'RedHat' { if (versioncmp($::sudoversion, '1.7.2p1') < 0) { warning("Found sudo with version ${::sudoversion}, but at least version 1.7.2p1 is required!") } } if $content != undef { - if is_array($content) { + if $content =~ Array { $lines = join($content, "\n") $content_real = "# This file is managed by Puppet; changes may be overwritten\n${lines}\n" } else { $content_real = "# This file is managed by Puppet; changes may be overwritten\n${content}\n" } } elsif $template != undef { $content_real = template($template) } else { $content_real = undef } if $ensure == 'present' { $notify_real = Exec["sudo-syntax-check for file ${cur_file}"] } else { $notify_real = undef } file { "${priority_real}_${dname}": ensure => $ensure, path => $cur_file_real, owner => 'root', group => $sudo::params::config_file_group, mode => $sudo::params::config_file_mode, source => $source, content => $content_real, notify => $notify_real, } exec {"sudo-syntax-check for file ${cur_file}": command => "visudo -c -f '${cur_file_real}' || ( rm -f '${cur_file_real}' && exit 1)", refreshonly => true, path => $sudo_syntax_path, } } diff --git a/manifests/configs.pp b/manifests/configs.pp index 5b49de0..cbf2f82 100644 --- a/manifests/configs.pp +++ b/manifests/configs.pp @@ -1,27 +1,26 @@ # Class: sudo::configs # # This class enables support for a full hiera based sudoers configuration. # Hiera functionality is auto enabled during the initial sudo module load; # this class is not intended to be loaded directly. # # See the primary sudo module documentation for usage and examples. # class sudo::configs ( - $configs_hash = {}, + Hash $configs_hash = {}, ){ - validate_hash ( $configs_hash ) # NOTE: hiera_hash does not work as expected in a parameterized class # definition; so we call it here. # # http://docs.puppetlabs.com/hiera/1/puppet.html#limitations # https://tickets.puppetlabs.com/browse/HI-118 # $configs = lookup('sudo::configs', Hash, {'strategy' => 'deep', 'merge_hash_arrays' => true}, $configs_hash) if !empty($configs) { create_resources('sudo::conf', $configs) } } diff --git a/manifests/init.pp b/manifests/init.pp index b7ad6c2..daf8749 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,178 +1,174 @@ # Class: sudo # # This module manages sudo # # Parameters: # [*ensure*] # Ensure if present or absent. # Default: present # # [*package*] # Name of the package. # Only set this, if your platform is not supported or you know, # what you're doing. # Default: auto-set, platform specific # # [*package_ensure*] # Allows you to ensure a particular version of a package # Default: present / lastest for RHEL < 5.5 # # [*package_source*] # Where to find the package. Only set this on AIX (required) and # Solaris (required) or if your platform is not supported or you # know, what you're doing. # # The default for aix is the perzl sudo package. For solaris 10 we # use the official www.sudo.ws binary package. # # Default: AIX: perzl.org # Solaris: www.sudo.ws # # [*package_admin_file*] # Where to find a Solaris 10 package admin file for # an unattended installation. We do not supply a default file, so # this has to be staged separately # # Only set this on Solaris 10 (required) # Default: /var/sadm/install/admin/puppet # # [*purge*] # Whether or not to purge sudoers.d directory # Default: true # # [*purge_ignore*] # Files to exclude from purging in sudoers.d directory # Default: undef # # [*config_file*] # Main configuration file. # Only set this, if your platform is not supported or you know, # what you're doing. # Default: auto-set, platform specific # # [*config_dir*] # Main directory containing sudo snippets, imported via # includedir stanza in sudoers file # Default: auto-set, platform specific # # [*extra_include_dirs*] # Array of additional directories containing sudo snippets # Default: undef # # [*content*] # Alternate content file location # Only set this, if your platform is not supported or you know, # what you're doing. # Default: auto-set, platform specific # # [*ldap_enable*] # Enable ldap support on the package # Default: false # # Actions: # Installs sudo package and checks the state of sudoers file and # sudoers.d directory. # # Requires: # Nothing # # Sample Usage: # class { 'sudo': } # # [Remember: No empty lines between comments and class definition] class sudo( - $enable = true, - $package = $sudo::params::package, - $package_ldap = $sudo::params::package_ldap, - $package_ensure = $sudo::params::package_ensure, - $package_source = $sudo::params::package_source, - $package_admin_file = $sudo::params::package_admin_file, - $purge = true, - $purge_ignore = undef, - $config_file = $sudo::params::config_file, - $config_file_mode = $sudo::params::config_file_mode, - $config_file_replace = true, - $config_dir = $sudo::params::config_dir, - $config_dir_mode = $sudo::params::config_dir_mode, - $extra_include_dirs = undef, - $content = $sudo::params::content, - $ldap_enable = false, + Boolean $enable = true, + String $package = $sudo::params::package, + String $package_ldap = $sudo::params::package_ldap, + String $package_ensure = $sudo::params::package_ensure, + Optional[String] $package_source = $sudo::params::package_source, + Optional[String] $package_admin_file = $sudo::params::package_admin_file, + Boolean $purge = true, + Optional[String] $purge_ignore = undef, + String $config_file = $sudo::params::config_file, + Boolean $config_file_replace = true, + String $config_file_mode = $sudo::params::config_file_mode, + String $config_dir = $sudo::params::config_dir, + String $config_dir_mode = $sudo::params::config_dir_mode, + Optional[Array[String]] $extra_include_dirs = undef, + String $content = $sudo::params::content, + Boolean $ldap_enable = false, ) inherits sudo::params { - validate_bool($enable) case $enable { true: { $dir_ensure = 'directory' $file_ensure = 'present' } false: { $dir_ensure = 'absent' $file_ensure = 'absent' } default: { fail('no $enable is set') } } - validate_bool($ldap_enable) case $ldap_enable { true: { if $package_ldap == undef { fail('on your os ldap support for sudo is not yet supported') } $package_real = $package_ldap } false: { $package_real = $package } default: { fail('no $ldap_enable is set') } } class { '::sudo::package': package => $package_real, package_ensure => $package_ensure, package_source => $package_source, package_admin_file => $package_admin_file, ldap_enable => $ldap_enable, } file { $config_file: ensure => $file_ensure, owner => 'root', group => $sudo::params::config_file_group, mode => $config_file_mode, replace => $config_file_replace, content => template($content), require => Class['sudo::package'], } file { $config_dir: ensure => $dir_ensure, owner => 'root', group => $sudo::params::config_file_group, mode => $config_dir_mode, recurse => $purge, purge => $purge, ignore => $purge_ignore, require => Class['sudo::package'], } # Load the Hiera based sudoer configuration (if enabled and present) # # NOTE: We must use 'include' here to avoid circular dependencies with # sudo::conf # # NOTE: There is no way to detect the existence of hiera. This automatic # functionality is therefore made exclusive to Puppet 3+ (hiera is embedded) # in order to preserve backwards compatibility. # # http://projects.puppetlabs.com/issues/12345 # if (versioncmp($::puppetversion, '3') != -1) { include '::sudo::configs' } - anchor { 'sudo::begin': } - -> Class['sudo::package'] - -> anchor { 'sudo::end': } + contain class { 'sudo::package': } } diff --git a/spec/acceptance/class_spec.rb b/spec/acceptance/class_spec.rb index 78a21bb..267bc1e 100644 --- a/spec/acceptance/class_spec.rb +++ b/spec/acceptance/class_spec.rb @@ -1,16 +1,16 @@ require 'spec_helper_acceptance' describe 'sudo class' do - context 'default parameters' do + context 'with default parameters' do # Using puppet_apply as a helper it 'works with no errors' do - pp = <<-EOS + pp = <<-PP class { 'sudo': } - EOS + PP # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end end end diff --git a/spec/acceptance/sudo_conf_spec.rb b/spec/acceptance/sudo_conf_spec.rb index 9046388..a682e93 100644 --- a/spec/acceptance/sudo_conf_spec.rb +++ b/spec/acceptance/sudo_conf_spec.rb @@ -1,52 +1,52 @@ require 'spec_helper_acceptance' describe 'sudo::conf class' do - context 'default parameters' do + context 'with default parameters' do # Using puppet_apply as a helper it 'works with no errors' do - pp = <<-EOS + pp = <<-PP group { 'janedoe': ensure => present; } -> user { 'janedoe' : gid => 'janedoe', home => '/home/janedoe', shell => '/bin/bash', managehome => true, membership => minimum, } -> user { 'nosudoguy' : home => '/home/nosudoguy', shell => '/bin/bash', managehome => true, membership => minimum, } -> class {'sudo': purge => false, config_file_replace => false, } -> sudo::conf { 'janedoe_nopasswd': content => "janedoe ALL=(ALL) NOPASSWD: ALL\n" } - EOS + PP # Run it twice and test for idempotency apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_failures => true) end describe command("su - janedoe -c 'sudo echo Hello World'") do its(:stdout) { is_expected.to match %r{Hello World} } its(:exit_status) { is_expected.to eq 0 } end describe command("su - nosudoguy -c 'sudo echo Hello World'") do its(:stderr) { is_expected.to match %r{no tty present and no askpass program specified} } its(:exit_status) { is_expected.to eq 1 } end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3744e12..0b9b0e4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,24 +1,24 @@ require 'puppetlabs_spec_helper/module_spec_helper' RSpec.configure do |c| c.include PuppetlabsSpec::Files - c.before :each do + c.before do # Ensure that we don't accidentally cache facts and environment # between test cases. Facter.clear Facter.clear_messages # Store any environment variables away to be restored later @old_env = {} ENV.each_key { |k| @old_env[k] = ENV[k] } if Gem::Version.new(`puppet --version`) >= Gem::Version.new('3.5') Puppet.settings[:strict_variables] = true end end - c.after :each do + c.after do PuppetlabsSpec::Files.cleanup end end diff --git a/templates/sudoers.rhel7.erb b/templates/sudoers.rhel7.erb index 2bd7196..edb6a1e 100644 --- a/templates/sudoers.rhel7.erb +++ b/templates/sudoers.rhel7.erb @@ -1,116 +1,116 @@ # file managed by puppet (unless config_file_replace=false) # ## Sudoers allows particular users to run various commands as ## the root user, without needing the root password. ## ## Examples are provided at the bottom of the file for collections ## of related commands, which can then be delegated out to particular ## users or groups. ## ## This file must be edited with the 'visudo' command. ## Host Aliases ## Groups of machines. You may prefer to use hostnames (perhaps using ## wildcards for entire domains) or IP addresses instead. # Host_Alias FILESERVERS = fs1, fs2 # Host_Alias MAILSERVERS = smtp, smtp2 ## User Aliases ## These aren't often necessary, as you can use regular groups ## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname ## rather than USERALIAS # User_Alias ADMINS = jsmith, mikem ## Command Aliases ## These are groups of related commands... ## Networking # Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool ## Installation and management of software # Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum ## Services # Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig ## Updating the locate database # Cmnd_Alias LOCATE = /usr/bin/updatedb ## Storage # Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount ## Delegating permissions # Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp ## Processes # Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall ## Drivers # Cmnd_Alias DRIVERS = /sbin/modprobe # Defaults specification # Refuse to run if unable to disable echo on the tty. This setting should also be # changed in order to be able to use sudo without a tty. See requiretty above. # Defaults !visiblepw # # Preserving HOME has security implications since many programs # use it when searching for configuration files. Note that HOME # is already set when the the env_reset option is enabled, so # this option is only effective for configurations where either # env_reset is disabled or HOME is present in the env_keep list. # Defaults always_set_home Defaults env_reset Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS" Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" # # Adding HOME to env_keep may enable a user to run unrestricted # commands via sudo. # # Defaults env_keep += "HOME" Defaults secure_path = /usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/puppetlabs/bin ## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS ## Allows people in group wheel to run all commands -# %wheel ALL=(ALL) ALL +%wheel ALL=(ALL) ALL ## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL ## Allows members of the users group to mount and unmount the ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now ## Read drop-in files #includedir <%= @config_dir %> <% @extra_include_dirs.each do |include_dir| -%> #includedir <%= include_dir %> <% end if @extra_include_dirs -%>