# # Author:: Adam Jacob () # Copyright:: Copyright 2008-2017, 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. # require "pathname" require "chef/provider/user" class Chef class Provider class User class Useradd < Chef::Provider::User # the linux version of this has been forked off, this is the base class now of solaris and AIX and should be abandoned # and those provider should be rewritten like the linux version. UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]].freeze def create_user command = compile_command("useradd") do |useradd| useradd.concat(universal_options) useradd.concat(useradd_options) end shell_out_compact!(command) end def manage_user return if universal_options.empty? command = compile_command("usermod") do |u| u.concat(universal_options) end shell_out_compact!(command) end def remove_user command = [ "userdel" ] command << "-r" if new_resource.manage_home command << "-f" if new_resource.force command << new_resource.username shell_out_compact!(command) end def check_lock # we can get an exit code of 1 even when it's successful on # rhel/centos (redhat bug 578534). See additional error checks below. passwd_s = shell_out_compact!("passwd", "-S", new_resource.username, returns: [0, 1]) if whyrun_mode? && passwd_s.stdout.empty? && passwd_s.stderr.match(/does not exist/) # if we're in whyrun mode and the user is not yet created we assume it would be return false end raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if passwd_s.stdout.empty? status_line = passwd_s.stdout.split(" ") case status_line[1] when /^P/ @locked = false when /^N/ @locked = false when /^L/ @locked = true end unless passwd_s.exitstatus == 0 raise_lock_error = false if %w{redhat centos}.include?(node[:platform]) passwd_version_check = shell_out_compact!("rpm", "-q", "passwd") passwd_version = passwd_version_check.stdout.chomp unless passwd_version == "passwd-0.73-1" raise_lock_error = true end else raise_lock_error = true end raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if raise_lock_error end @locked end def lock_user shell_out_compact!("usermod", "-L", new_resource.username) end def unlock_user shell_out_compact!("usermod", "-U", new_resource.username) end def compile_command(base_command) base_command = Array(base_command) yield base_command base_command << new_resource.username base_command end def universal_options @universal_options ||= begin opts = [] # magic allows UNIVERSAL_OPTIONS to be overridden in a subclass self.class::UNIVERSAL_OPTIONS.each do |field, option| update_options(field, option, opts) end if updating_home? opts << "-d" << new_resource.home if new_resource.manage_home Chef::Log.debug("#{new_resource} managing the users home directory") opts << "-m" else Chef::Log.debug("#{new_resource} setting home to #{new_resource.home}") end end opts << "-o" if new_resource.non_unique opts end end def update_options(field, option, opts) return unless current_resource.send(field).to_s != new_resource.send(field).to_s return unless new_resource.send(field) Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}") opts << option << new_resource.send(field).to_s end def useradd_options opts = [] opts << "-r" if new_resource.system opts << "-M" unless new_resource.manage_home opts end def updating_home? # will return false if paths are equivalent # Pathname#cleanpath does a better job than ::File::expand_path (on both unix and windows) # ::File.expand_path("///tmp") == ::File.expand_path("/tmp") => false # ::File.expand_path("\\tmp") => "C:/tmp" return true if current_resource.home.nil? && new_resource.home new_resource.home && Pathname.new(current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath end end end end end