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

groups_of(user) click to toggle source

Returns an array of all the groups that the user's a member of.

   # File lib/puppet/util/posix.rb
15 def groups_of(user)
16   begin
17     require_relative '../../puppet/ffi/posix'
18     groups = get_groups_list(user)
19   rescue StandardError, LoadError => e
20     Puppet.debug("Falling back to Puppet::Etc.group: #{e.message}")
21 
22     groups = []
23     Puppet::Etc.group do |group|
24       groups << group.name if group.mem.include?(user)
25     end
26   end
27 
28   uniq_groups = groups.uniq
29   if uniq_groups != groups
30     Puppet.debug(_('Removing any duplicate group entries'))
31   end
32 
33   uniq_groups
34 end

Private Class Methods

get_groups_list(user) click to toggle source
   # File lib/puppet/util/posix.rb
37 def get_groups_list(user)
38   raise LoadError, "The 'getgrouplist' method is not available" unless Puppet::FFI::POSIX::Functions.respond_to?(:getgrouplist)
39 
40   user_gid = Puppet::Etc.getpwnam(user).gid
41   ngroups = Puppet::FFI::POSIX::Constants::MAXIMUM_NUMBER_OF_GROUPS
42 
43   while true do # rubocop:disable Lint/LiteralInCondition
44     FFI::MemoryPointer.new(:int) do |ngroups_ptr|
45       FFI::MemoryPointer.new(:uint, ngroups) do |groups_ptr|
46         old_ngroups = ngroups
47         ngroups_ptr.write_int(ngroups)
48 
49         if Puppet::FFI::POSIX::Functions::getgrouplist(user, user_gid, groups_ptr, ngroups_ptr) != -1
50           groups_gids = groups_ptr.get_array_of_uint(0, ngroups_ptr.read_int)
51 
52           result = []
53           groups_gids.each do |group_gid|
54             group_info = Puppet::Etc.getgrgid(group_gid)
55             result |= [group_info.name] if group_info.mem.include?(user)
56           end
57           return result
58         end
59 
60         ngroups = ngroups_ptr.read_int
61         if ngroups <= old_ngroups
62           ngroups *= 2
63         end
64       end
65     end
66   end
67 end

Public Instance Methods

get_posix_field(space, field, id) click to toggle source

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
75 def get_posix_field(space, field, id)
76   raise Puppet::DevError, _("Did not get id from caller") unless id
77 
78   if id.is_a?(Integer)
79     if id > Puppet[:maximum_uid].to_i
80       Puppet.err _("Tried to get %{field} field for silly id %{id}") % { field: field, id: id }
81       return nil
82     end
83     method = methodbyid(space)
84   else
85     method = methodbyname(space)
86   end
87 
88   begin
89     return Etc.send(method, id).send(field)
90   rescue NoMethodError, ArgumentError
91     # ignore it; we couldn't find the object
92     return nil
93   end
94 end
gid(group) click to toggle source

Get the GID

    # File lib/puppet/util/posix.rb
158 def gid(group)
159     get_posix_value(:group, :gid, group)
160 end
idfield(space) click to toggle source

Determine what the field name is for users and groups.

    # File lib/puppet/util/posix.rb
128 def idfield(space)
129   case space.intern
130   when :gr, :group; return :gid
131   when :pw, :user, :passwd; return :uid
132   else
133     raise ArgumentError.new(_("Can only handle users and groups"))
134   end
135 end
methodbyid(space) click to toggle source

Determine what the method is to get users and groups by id

    # File lib/puppet/util/posix.rb
138 def methodbyid(space)
139   case space.intern
140   when :gr, :group; return :getgrgid
141   when :pw, :user, :passwd; return :getpwuid
142   else
143     raise ArgumentError.new(_("Can only handle users and groups"))
144   end
145 end
methodbyname(space) click to toggle source

Determine what the method is to get users and groups by name

    # File lib/puppet/util/posix.rb
148 def methodbyname(space)
149   case space.intern
150   when :gr, :group; return :getgrnam
151   when :pw, :user, :passwd; return :getpwnam
152   else
153     raise ArgumentError.new(_("Can only handle users and groups"))
154   end
155 end
search_posix_field(type, field, id) click to toggle source

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
 99 def search_posix_field(type, field, id)
100   idmethod = idfield(type)
101   integer = false
102   if id.is_a?(Integer)
103     integer = true
104     if id > Puppet[:maximum_uid].to_i
105       Puppet.err _("Tried to get %{field} field for silly id %{id}") % { field: field, id: id }
106       return nil
107     end
108   end
109 
110   Etc.send(type) do |object|
111     if integer and object.send(idmethod) == id
112       return object.send(field)
113     elsif object.name == id
114       return object.send(field)
115     end
116   end
117 
118   # Apparently the group/passwd methods need to get reset; if we skip
119   # this call, then new users aren't found.
120   case type
121   when :passwd; Etc.send(:endpwent)
122   when :group; Etc.send(:endgrent)
123   end
124   nil
125 end
uid(user) click to toggle source

Get the UID

    # File lib/puppet/util/posix.rb
163 def uid(user)
164     get_posix_value(:passwd, :uid, user)
165 end

Private Instance Methods

get_posix_value(location, id_field, field) click to toggle source

Get the specified id_field of a given field (user or group), whether an ID name is provided

    # File lib/puppet/util/posix.rb
171 def get_posix_value(location, id_field, field)
172   begin
173     field = Integer(field)
174   rescue ArgumentError
175     # pass
176   end
177   if field.is_a?(Integer)
178     name = get_posix_field(location, :name, field)
179     return nil unless name
180     id = get_posix_field(location, id_field, name)
181     check_value = id
182   else
183     id = get_posix_field(location, id_field, field)
184     return nil unless id
185     name = get_posix_field(location, :name, id)
186     check_value = name
187   end
188 
189   if check_value != field
190     check_value_id = get_posix_field(location, id_field, check_value) if check_value
191 
192     if id == check_value_id
193       Puppet.debug("Multiple entries found for resource: '#{location}' with #{id_field}: #{id}")
194       return id
195     else
196       Puppet.debug("The value retrieved: '#{check_value}' is different than the required state: '#{field}', searching in all entries")
197       return search_posix_field(location, id_field, field)
198     end
199   else
200     return id
201   end
202 end