module Puppet::Util::SUIDManager

Public Class Methods

asuser(new_uid=nil, new_gid=nil) { || ... } click to toggle source

Runs block setting euid and egid if provided then restoring original ids. If running on Windows or without root, the block will be run with the current euid/egid.

   # File lib/puppet/util/suidmanager.rb
65 def asuser(new_uid=nil, new_gid=nil)
66   return yield if Puppet::Util::Platform.windows?
67   return yield unless root?
68   return yield unless new_uid or new_gid
69 
70   old_euid, old_egid = self.euid, self.egid
71   begin
72     change_privileges(new_uid, new_gid, false)
73 
74     yield
75   ensure
76     change_privileges(new_uid ? old_euid : nil, old_egid, false)
77   end
78 end
change_group(group, permanently=false) click to toggle source

Changes the egid of the process if `permanently` is not set, otherwise changes gid. This method will fail if used on Windows, or attempting to change to a different gid without root.

    # File lib/puppet/util/suidmanager.rb
102 def change_group(group, permanently=false)
103   gid = convert_xid(:gid, group)
104   raise Puppet::Error, _("No such group %{group}") % { group: group } unless gid
105 
106   return if Process.egid == gid
107 
108   if permanently
109     Process::GID.change_privilege(gid)
110   else
111     Process.egid = gid
112   end
113 end
change_privileges(uid=nil, gid=nil, permanently=false) click to toggle source

If `permanently` is set, will permanently change the uid/gid of the process. If not, it will only set the euid/egid. If only uid is supplied, the primary group of the supplied gid will be used. If only gid is supplied, only gid will be changed. This method will fail if used on Windows.

   # File lib/puppet/util/suidmanager.rb
86 def change_privileges(uid=nil, gid=nil, permanently=false)
87   return unless uid or gid
88 
89   unless gid
90     uid = convert_xid(:uid, uid)
91     gid = Etc.getpwuid(uid).gid
92   end
93 
94   change_group(gid, permanently)
95   change_user(uid, permanently) if uid
96 end
change_user(user, permanently=false) click to toggle source

As change_group, but operates on uids. If changing user permanently, supplementary groups will be set the to default groups for the new uid.

    # File lib/puppet/util/suidmanager.rb
118 def change_user(user, permanently=false)
119   uid = convert_xid(:uid, user)
120   raise Puppet::Error, _("No such user %{user}") % { user: user } unless uid
121 
122   return if Process.euid == uid
123 
124   if permanently
125     # If changing uid, we must be root. So initgroups first here.
126     initgroups(uid)
127 
128     Process::UID.change_privilege(uid)
129   else
130     # We must be root to initgroups, so initgroups before dropping euid if
131     # we're root, otherwise elevate euid before initgroups.
132     # change euid (to root) first.
133     if Process.euid == 0
134       initgroups(uid)
135       Process.euid = uid
136     else
137       Process.euid = uid
138       initgroups(uid)
139     end
140   end
141 end
convert_xid(type, id) click to toggle source

Make sure the passed argument is a number.

    # File lib/puppet/util/suidmanager.rb
145 def convert_xid(type, id)
146   return id if id.kind_of? Integer
147   map = {:gid => :group, :uid => :user}
148   raise ArgumentError, _("Invalid id type %{type}") % { type: type } unless map.include?(type)
149   ret = Puppet::Util.send(type, id)
150   if ret == nil
151     raise Puppet::Error, _("Invalid %{klass}: %{id}") % { klass: map[type], id: id }
152   end
153   ret
154 end
groups=(grouplist) click to toggle source
   # File lib/puppet/util/suidmanager.rb
25 def groups=(grouplist)
26   begin
27     return Process.groups = grouplist
28   rescue Errno::EINVAL => e
29     #We catch Errno::EINVAL as some operating systems (OS X in particular) can
30     # cause troubles when using Process#groups= to change *this* user / process
31     # list of supplementary groups membership.  This is done via Ruby's function
32     # "static VALUE proc_setgroups(VALUE obj, VALUE ary)" which is effectively
33     # a wrapper for "int setgroups(size_t size, const gid_t *list)" (part of SVr4
34     # and 4.3BSD but not in POSIX.1-2001) that fails and sets errno to EINVAL.
35     #
36     # This does not appear to be a problem with Ruby but rather an issue on the
37     # operating system side.  Therefore we catch the exception and look whether
38     # we run under OS X or not -- if so, then we acknowledge the problem and
39     # re-throw the exception otherwise.
40     if osx_maj_ver and not osx_maj_ver.empty?
41       return true
42     else
43       raise e
44     end
45   end
46 end
initgroups(uid) click to toggle source

Initialize primary and supplemental groups to those of the target user. We take the UID and manually look up their details in the system database, including username and primary group. This method will fail on Windows, or if used without root to initgroups of another user.

    # File lib/puppet/util/suidmanager.rb
161 def initgroups(uid)
162   pwent = Etc.getpwuid(uid)
163   Process.initgroups(pwent.name, pwent.gid)
164 end
osx_maj_ver() click to toggle source
   # File lib/puppet/util/suidmanager.rb
19 def osx_maj_ver
20   return @osx_maj_ver unless @osx_maj_ver.nil?
21   @osx_maj_ver = Facter.value('macosx_productversion_major') || false
22 end
root?() click to toggle source
   # File lib/puppet/util/suidmanager.rb
49 def self.root?
50   if Puppet::Util::Platform.windows?
51     require_relative '../../puppet/util/windows/user'
52     Puppet::Util::Windows::User.admin?
53   else
54     Process.uid == 0
55   end
56 end

Private Instance Methods

asuser(new_uid=nil, new_gid=nil) { || ... } click to toggle source

Runs block setting euid and egid if provided then restoring original ids. If running on Windows or without root, the block will be run with the current euid/egid.

   # File lib/puppet/util/suidmanager.rb
65 def asuser(new_uid=nil, new_gid=nil)
66   return yield if Puppet::Util::Platform.windows?
67   return yield unless root?
68   return yield unless new_uid or new_gid
69 
70   old_euid, old_egid = self.euid, self.egid
71   begin
72     change_privileges(new_uid, new_gid, false)
73 
74     yield
75   ensure
76     change_privileges(new_uid ? old_euid : nil, old_egid, false)
77   end
78 end
change_group(group, permanently=false) click to toggle source

Changes the egid of the process if `permanently` is not set, otherwise changes gid. This method will fail if used on Windows, or attempting to change to a different gid without root.

    # File lib/puppet/util/suidmanager.rb
102 def change_group(group, permanently=false)
103   gid = convert_xid(:gid, group)
104   raise Puppet::Error, _("No such group %{group}") % { group: group } unless gid
105 
106   return if Process.egid == gid
107 
108   if permanently
109     Process::GID.change_privilege(gid)
110   else
111     Process.egid = gid
112   end
113 end
change_privileges(uid=nil, gid=nil, permanently=false) click to toggle source

If `permanently` is set, will permanently change the uid/gid of the process. If not, it will only set the euid/egid. If only uid is supplied, the primary group of the supplied gid will be used. If only gid is supplied, only gid will be changed. This method will fail if used on Windows.

   # File lib/puppet/util/suidmanager.rb
86 def change_privileges(uid=nil, gid=nil, permanently=false)
87   return unless uid or gid
88 
89   unless gid
90     uid = convert_xid(:uid, uid)
91     gid = Etc.getpwuid(uid).gid
92   end
93 
94   change_group(gid, permanently)
95   change_user(uid, permanently) if uid
96 end
change_user(user, permanently=false) click to toggle source

As change_group, but operates on uids. If changing user permanently, supplementary groups will be set the to default groups for the new uid.

    # File lib/puppet/util/suidmanager.rb
118 def change_user(user, permanently=false)
119   uid = convert_xid(:uid, user)
120   raise Puppet::Error, _("No such user %{user}") % { user: user } unless uid
121 
122   return if Process.euid == uid
123 
124   if permanently
125     # If changing uid, we must be root. So initgroups first here.
126     initgroups(uid)
127 
128     Process::UID.change_privilege(uid)
129   else
130     # We must be root to initgroups, so initgroups before dropping euid if
131     # we're root, otherwise elevate euid before initgroups.
132     # change euid (to root) first.
133     if Process.euid == 0
134       initgroups(uid)
135       Process.euid = uid
136     else
137       Process.euid = uid
138       initgroups(uid)
139     end
140   end
141 end
convert_xid(type, id) click to toggle source

Make sure the passed argument is a number.

    # File lib/puppet/util/suidmanager.rb
145 def convert_xid(type, id)
146   return id if id.kind_of? Integer
147   map = {:gid => :group, :uid => :user}
148   raise ArgumentError, _("Invalid id type %{type}") % { type: type } unless map.include?(type)
149   ret = Puppet::Util.send(type, id)
150   if ret == nil
151     raise Puppet::Error, _("Invalid %{klass}: %{id}") % { klass: map[type], id: id }
152   end
153   ret
154 end
groups=(grouplist) click to toggle source
   # File lib/puppet/util/suidmanager.rb
25 def groups=(grouplist)
26   begin
27     return Process.groups = grouplist
28   rescue Errno::EINVAL => e
29     #We catch Errno::EINVAL as some operating systems (OS X in particular) can
30     # cause troubles when using Process#groups= to change *this* user / process
31     # list of supplementary groups membership.  This is done via Ruby's function
32     # "static VALUE proc_setgroups(VALUE obj, VALUE ary)" which is effectively
33     # a wrapper for "int setgroups(size_t size, const gid_t *list)" (part of SVr4
34     # and 4.3BSD but not in POSIX.1-2001) that fails and sets errno to EINVAL.
35     #
36     # This does not appear to be a problem with Ruby but rather an issue on the
37     # operating system side.  Therefore we catch the exception and look whether
38     # we run under OS X or not -- if so, then we acknowledge the problem and
39     # re-throw the exception otherwise.
40     if osx_maj_ver and not osx_maj_ver.empty?
41       return true
42     else
43       raise e
44     end
45   end
46 end
initgroups(uid) click to toggle source

Initialize primary and supplemental groups to those of the target user. We take the UID and manually look up their details in the system database, including username and primary group. This method will fail on Windows, or if used without root to initgroups of another user.

    # File lib/puppet/util/suidmanager.rb
161 def initgroups(uid)
162   pwent = Etc.getpwuid(uid)
163   Process.initgroups(pwent.name, pwent.gid)
164 end
osx_maj_ver() click to toggle source
   # File lib/puppet/util/suidmanager.rb
19 def osx_maj_ver
20   return @osx_maj_ver unless @osx_maj_ver.nil?
21   @osx_maj_ver = Facter.value('macosx_productversion_major') || false
22 end