Add attributes and override variables for a separate build
user, with defaults corresponding to the status quo. This
reuses the existing PORTAGE_BUILD_USER and PORTAGE_BUILD_GROUP
variables that were already exported to the ebuild environment.

When PORTAGE_BUILD_USER and PORTAGE_BUILD_GROUP are unset,
the build user can still be overridden by the existing
PORTAGE_USERNAME and PORTAGE_GRPNAME variables.

This sets the stage for migration of internal code to use
a separate build user, as required to solve bug 600804 in a
manner that complies with PMS.

Bug: https://bugs.gentoo.org/600804
---
 pym/portage/data.py                    | 54 +++++++++++++++++++++++++++++-----
 pym/portage/package/ebuild/doebuild.py | 12 ++++----
 2 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/pym/portage/data.py b/pym/portage/data.py
index 28d6eb79db..7b2db21c6b 100644
--- a/pym/portage/data.py
+++ b/pym/portage/data.py
@@ -105,6 +105,15 @@ try:
 except KeyError:
        pass
 
+_attr_env_vars = {
+       # TODO: Migrate all internals to use the build user/group
+       # instead of the "portage" user/group where appropriate.
+       '_build_group': 'PORTAGE_BUILD_GROUP',
+       '_build_user': 'PORTAGE_BUILD_USER',
+       '_portage_grpname': 'PORTAGE_GRPNAME',
+       '_portage_username': 'PORTAGE_USERNAME',
+}
+
 # The portage_uid and portage_gid global constants, and others that
 # depend on them are initialized lazily, in order to allow configuration
 # via make.conf. Eventually, these constants may be deprecated in favor
@@ -142,6 +151,32 @@ def _get_global(k):
                elif _get_global('portage_gid') in os.getgroups():
                        v = 1
 
+       elif k in ('_build_gid', '_build_uid'):
+               keyerror = False
+               try:
+                       build_uid = 
pwd.getpwnam(_get_global('_build_user')).pw_uid
+               except KeyError:
+                       writemsg('!!! PORTAGE_BUILD_USER refers to non-existant 
user "%s"\n'
+                               % _get_global('_build_user'), noiselevel=-1)
+                       build_uid = 0
+
+               try:
+                       build_gid = 
grp.getgrnam(_get_global('_build_group')).gr_gid
+               except KeyError:
+                       writemsg('!!! PORTAGE_BUILD_GROUP refers to 
non-existant user "%s"\n'
+                               % _get_global('_build_group'), noiselevel=-1)
+                       build_gid = 0
+
+               globals()['_build_gid'] = build_gid
+               _initialized_globals.add('_build_gid')
+               globals()['_build_uid'] = build_uid
+               _initialized_globals.add('_build_uid')
+
+               if k == '_build_gid':
+                       return build_gid
+               else:
+                       return build_uid
+
        elif k in ('portage_gid', 'portage_uid'):
 
                #Discover the uid and gid of the portage user/group
@@ -193,7 +228,7 @@ def _get_global(k):
                        # Get a list of group IDs for the portage user. Do not 
use
                        # grp.getgrall() since it is known to trigger spurious
                        # SIGPIPE problems with nss_ldap.
-                       cmd = ["id", "-G", _portage_username]
+                       cmd = ["id", "-G", _get_global('_build_user')]
 
                        if sys.hexversion < 0x3020000 and sys.hexversion >= 
0x3000000:
                                # Python 3.1 _execvp throws TypeError for 
non-absolute executable
@@ -223,12 +258,9 @@ def _get_global(k):
 
        # Avoid instantiating portage.settings when the desired
        # variable is set in os.environ.
-       elif k in ('_portage_grpname', '_portage_username'):
+       elif k in _attr_env_vars:
                v = None
-               if k == '_portage_grpname':
-                       env_key = 'PORTAGE_GRPNAME'
-               else:
-                       env_key = 'PORTAGE_USERNAME'
+               env_key = _attr_env_vars[k]
 
                if env_key in os.environ:
                        v = os.environ[env_key]
@@ -245,7 +277,7 @@ def _get_global(k):
                                pass
                        else:
                                if _unprivileged_mode(eroot_or_parent, 
eroot_st):
-                                       if k == '_portage_grpname':
+                                       if k in ('_build_group', 
'_portage_grpname'):
                                                try:
                                                        grp_struct = 
grp.getgrgid(eroot_st.st_gid)
                                                except KeyError:
@@ -261,7 +293,12 @@ def _get_global(k):
                                                        v = pwd_struct.pw_name
 
                if v is None:
-                       v = 'portage'
+                       if k == '_build_group':
+                               v = _get_global('_portage_grpname')
+                       elif k == '_build_user':
+                               v = _get_global('_portage_username')
+                       else:
+                               v = 'portage'
        else:
                raise AssertionError('unknown name: %s' % k)
 
@@ -281,6 +318,7 @@ class _GlobalProxy(portage.proxy.objectproxy.ObjectProxy):
                return _get_global(object.__getattribute__(self, '_name'))
 
 for k in ('portage_gid', 'portage_uid', 'secpass', 'userpriv_groups',
+       '_build_gid', '_build_group', '_build_uid', '_build_user',
        '_portage_grpname', '_portage_username'):
        globals()[k] = _GlobalProxy(k)
 del k
diff --git a/pym/portage/package/ebuild/doebuild.py 
b/pym/portage/package/ebuild/doebuild.py
index 97a9199a31..3981a7d7ae 100644
--- a/pym/portage/package/ebuild/doebuild.py
+++ b/pym/portage/package/ebuild/doebuild.py
@@ -1592,8 +1592,8 @@ def spawn(mystring, mysettings, debug=False, free=False, 
droppriv=False,
                if "userpriv" in features and "userpriv" not in 
mysettings["PORTAGE_RESTRICT"].split() and secpass >= 2:
                        # Since Python 3.4, getpwuid and getgrgid
                        # require int type (no proxies).
-                       portage_build_uid = int(portage_uid)
-                       portage_build_gid = int(portage_gid)
+                       portage_build_uid = int(portage.data._build_uid)
+                       portage_build_gid = int(portage.data._build_gid)
 
        if "PORTAGE_BUILD_USER" not in mysettings:
                user = None
@@ -1602,8 +1602,8 @@ def spawn(mystring, mysettings, debug=False, free=False, 
droppriv=False,
                except KeyError:
                        if portage_build_uid == 0:
                                user = "root"
-                       elif portage_build_uid == portage_uid:
-                               user = portage.data._portage_username
+                       elif portage_build_uid == portage.data._build_uid:
+                               user = portage.data._build_user
                if user is not None:
                        mysettings["PORTAGE_BUILD_USER"] = user
 
@@ -1614,8 +1614,8 @@ def spawn(mystring, mysettings, debug=False, free=False, 
droppriv=False,
                except KeyError:
                        if portage_build_gid == 0:
                                group = "root"
-                       elif portage_build_gid == portage_gid:
-                               group = portage.data._portage_grpname
+                       elif portage_build_gid == portage.data._build_gid:
+                               group = portage.data._build_group
                if group is not None:
                        mysettings["PORTAGE_BUILD_GROUP"] = group
 
-- 
2.13.6


Reply via email to