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