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
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

get_groups_list(user) click to toggle source
   # 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

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
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
gid(group) click to toggle source

Get the GID

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

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
methodbyid(space) click to toggle source

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
methodbyname(space) click to toggle source

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
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
 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
uid(user) click to toggle source

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_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
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