module Puppet::Util::POSIX
Utility methods for interacting with POSIX
objects; mostly user and group
Constants
- LOCALE_ENV_VARS
This is a list of environment variables that we will set when we want to override the
POSIX
locale- USER_ENV_VARS
This is a list of user-related environment variables that we will unset when we want to provide a pristine environment for “exec” runs
Public Class Methods
Returns an array of all the groups that the user's a member of.
# File lib/puppet/util/posix.rb 14 def groups_of(user) 15 begin 16 require_relative '../../puppet/ffi/posix' 17 groups = get_groups_list(user) 18 rescue StandardError, LoadError => e 19 Puppet.debug("Falling back to Puppet::Etc.group: #{e.message}") 20 21 groups = [] 22 Puppet::Etc.group do |group| 23 groups << group.name if group.mem.include?(user) 24 end 25 end 26 27 uniq_groups = groups.uniq 28 if uniq_groups != groups 29 Puppet.debug(_('Removing any duplicate group entries')) 30 end 31 32 uniq_groups 33 end
Private Class Methods
# File lib/puppet/util/posix.rb 36 def get_groups_list(user) 37 raise LoadError, "The 'getgrouplist' method is not available" unless Puppet::FFI::POSIX::Functions.respond_to?(:getgrouplist) 38 39 user_gid = Puppet::Etc.getpwnam(user).gid 40 ngroups = Puppet::FFI::POSIX::Constants::MAXIMUM_NUMBER_OF_GROUPS 41 42 while true do # rubocop:disable Lint/LiteralInCondition 43 FFI::MemoryPointer.new(:int) do |ngroups_ptr| 44 FFI::MemoryPointer.new(:uint, ngroups) do |groups_ptr| 45 old_ngroups = ngroups 46 ngroups_ptr.write_int(ngroups) 47 48 if Puppet::FFI::POSIX::Functions::getgrouplist(user, user_gid, groups_ptr, ngroups_ptr) != -1 49 groups_gids = groups_ptr.get_array_of_uint(0, ngroups_ptr.read_int) 50 51 result = [] 52 groups_gids.each do |group_gid| 53 group_info = Puppet::Etc.getgrgid(group_gid) 54 result |= [group_info.name] if group_info.mem.include?(user) 55 end 56 return result 57 end 58 59 ngroups = ngroups_ptr.read_int 60 if ngroups <= old_ngroups 61 ngroups *= 2 62 end 63 end 64 end 65 end 66 end
Public Instance Methods
Retrieve a field from a POSIX
Etc
object. The id can be either an integer or a name. This only works for users and groups. It's also broken on some platforms, unfortunately, which is why we fall back to the other method search_posix_field
in the gid and uid methods if a sanity check fails
# File lib/puppet/util/posix.rb 74 def get_posix_field(space, field, id) 75 raise Puppet::DevError, _("Did not get id from caller") unless id 76 77 if id.is_a?(Integer) 78 if id > Puppet[:maximum_uid].to_i 79 Puppet.err _("Tried to get %{field} field for silly id %{id}") % { field: field, id: id } 80 return nil 81 end 82 method = methodbyid(space) 83 else 84 method = methodbyname(space) 85 end 86 87 begin 88 return Etc.send(method, id).send(field) 89 rescue NoMethodError, ArgumentError 90 # ignore it; we couldn't find the object 91 return nil 92 end 93 end
Get the GID
# File lib/puppet/util/posix.rb 157 def gid(group) 158 get_posix_value(:group, :gid, group) 159 end
Determine what the field name is for users and groups.
# File lib/puppet/util/posix.rb 127 def idfield(space) 128 case space.intern 129 when :gr, :group; return :gid 130 when :pw, :user, :passwd; return :uid 131 else 132 raise ArgumentError.new(_("Can only handle users and groups")) 133 end 134 end
Determine what the method is to get users and groups by id
# File lib/puppet/util/posix.rb 137 def methodbyid(space) 138 case space.intern 139 when :gr, :group; return :getgrgid 140 when :pw, :user, :passwd; return :getpwuid 141 else 142 raise ArgumentError.new(_("Can only handle users and groups")) 143 end 144 end
Determine what the method is to get users and groups by name
# File lib/puppet/util/posix.rb 147 def methodbyname(space) 148 case space.intern 149 when :gr, :group; return :getgrnam 150 when :pw, :user, :passwd; return :getpwnam 151 else 152 raise ArgumentError.new(_("Can only handle users and groups")) 153 end 154 end
A degenerate method of retrieving name/id mappings. The job of this method is to retrieve all objects of a certain type, search for a specific entry and then return a given field from that entry.
# File lib/puppet/util/posix.rb 98 def search_posix_field(type, field, id) 99 idmethod = idfield(type) 100 integer = false 101 if id.is_a?(Integer) 102 integer = true 103 if id > Puppet[:maximum_uid].to_i 104 Puppet.err _("Tried to get %{field} field for silly id %{id}") % { field: field, id: id } 105 return nil 106 end 107 end 108 109 Etc.send(type) do |object| 110 if integer and object.send(idmethod) == id 111 return object.send(field) 112 elsif object.name == id 113 return object.send(field) 114 end 115 end 116 117 # Apparently the group/passwd methods need to get reset; if we skip 118 # this call, then new users aren't found. 119 case type 120 when :passwd; Etc.send(:endpwent) 121 when :group; Etc.send(:endgrent) 122 end 123 nil 124 end
Get the UID
# File lib/puppet/util/posix.rb 162 def uid(user) 163 get_posix_value(:passwd, :uid, user) 164 end
Private Instance Methods
Get the specified id_field of a given field (user or group), whether an ID name is provided
# File lib/puppet/util/posix.rb 170 def get_posix_value(location, id_field, field) 171 begin 172 field = Integer(field) 173 rescue ArgumentError 174 # pass 175 end 176 if field.is_a?(Integer) 177 name = get_posix_field(location, :name, field) 178 return nil unless name 179 id = get_posix_field(location, id_field, name) 180 check_value = id 181 else 182 id = get_posix_field(location, id_field, field) 183 return nil unless id 184 name = get_posix_field(location, :name, id) 185 check_value = name 186 end 187 188 if check_value != field 189 check_value_id = get_posix_field(location, id_field, check_value) if check_value 190 191 if id == check_value_id 192 Puppet.debug("Multiple entries found for resource: '#{location}' with #{id_field}: #{id}") 193 return id 194 else 195 Puppet.debug("The value retrieved: '#{check_value}' is different than the required state: '#{field}', searching in all entries") 196 return search_posix_field(location, id_field, field) 197 end 198 else 199 return id 200 end 201 end