1 # data.py -- Calculated/Discovered Data Values
2 # Copyright 1998-2010 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
5 import os, pwd, grp, platform
8 portage.proxy.lazyimport.lazyimport(globals(),
9 'portage.output:colorize',
10 'portage.util:writemsg',
12 from portage.localization import _
14 ostype=platform.system()
16 if ostype == "DragonFly" or ostype.endswith("BSD"):
21 lchown = getattr(os, "lchown", None)
24 if ostype == "Darwin":
25 def lchown(*pos_args, **key_args):
28 def lchown(*pargs, **kwargs):
29 writemsg(colorize("BAD", "!!!") + _(
30 " It seems that os.lchown does not"
31 " exist. Please rebuild python.\n"), noiselevel=-1)
34 lchown = portage._unicode_func_wrapper(lchown)
36 def portage_group_warning():
37 warn_prefix = colorize("BAD", "*** WARNING *** ")
39 "For security reasons, only system administrators should be",
40 "allowed in the portage group. Untrusted users or processes",
41 "can potentially exploit the portage group for attacks such as",
42 "local privilege escalation."
45 writemsg(warn_prefix, noiselevel=-1)
46 writemsg(x, noiselevel=-1)
47 writemsg("\n", noiselevel=-1)
48 writemsg("\n", noiselevel=-1)
50 # Portage has 3 security levels that depend on the uid and gid of the main
51 # process and are assigned according to the following table:
53 # Privileges secpass uid gid
55 # group 1 any portage_gid
58 # If the "wheel" group does not exist then wheelgid falls back to 0.
59 # If the "portage" group does not exist then portage_uid falls back to wheelgid.
65 wheelgid=grp.getgrnam("wheel")[2]
69 # The portage_uid and portage_gid global constants, and others that
70 # depend on them are initialized lazily, in order to allow configuration
71 # via make.conf. Eventually, these constants may be deprecated in favor
72 # of config attributes, since it's conceivable that multiple
73 # configurations with different constants could be used simultaneously.
74 _initialized_globals = set()
77 if k in _initialized_globals:
80 if k in ('portage_gid', 'portage_uid', 'secpass'):
81 global portage_gid, portage_uid, secpass
85 elif portage.const.EPREFIX:
87 #Discover the uid and gid of the portage user/group
89 portage_uid = pwd.getpwnam(_get_global('_portage_uname')).pw_uid
90 portage_gid = grp.getgrnam(_get_global('_portage_grpname')).gr_gid
91 if secpass < 1 and portage_gid in os.getgroups():
96 writemsg(colorize("BAD",
97 _("portage: 'portage' user or group missing.")) + "\n", noiselevel=-1)
99 " For the defaults, line 1 goes into passwd, "
100 "and 2 into group.\n"), noiselevel=-1)
101 writemsg(colorize("GOOD",
102 " portage:x:250:250:portage:/var/tmp/portage:/bin/false") \
103 + "\n", noiselevel=-1)
104 writemsg(colorize("GOOD", " portage::250:portage") + "\n",
106 portage_group_warning()
108 _initialized_globals.add('portage_gid')
109 _initialized_globals.add('portage_uid')
110 _initialized_globals.add('secpass')
112 if k == 'portage_gid':
114 elif k == 'portage_uid':
119 raise AssertionError('unknown name: %s' % k)
121 elif k == 'userpriv_groups':
124 # Get a list of group IDs for the portage user. Do not use
125 # grp.getgrall() since it is known to trigger spurious
126 # SIGPIPE problems with nss_ldap.
127 mystatus, myoutput = \
128 portage.subprocess_getstatusoutput("id -G %s" % _portage_uname)
129 if mystatus == os.EX_OK:
130 for x in myoutput.split():
137 elif k == '_portage_grpname':
138 env = getattr(portage, 'settings', os.environ)
139 v = env.get('PORTAGE_GRPNAME', 'portage')
140 elif k == '_portage_uname':
141 env = getattr(portage, 'settings', os.environ)
142 v = env.get('PORTAGE_USERNAME', 'portage')
144 raise AssertionError('unknown name: %s' % k)
147 _initialized_globals.add(k)
150 class _GlobalProxy(portage.proxy.objectproxy.ObjectProxy):
152 __slots__ = ('_name',)
154 def __init__(self, name):
155 portage.proxy.objectproxy.ObjectProxy.__init__(self)
156 object.__setattr__(self, '_name', name)
158 def _get_target(self):
159 return _get_global(object.__getattribute__(self, '_name'))
161 for k in ('portage_gid', 'portage_uid', 'secpass', 'userpriv_groups',
162 '_portage_grpname', '_portage_uname'):
163 globals()[k] = _GlobalProxy(k)
168 Use config variables like PORTAGE_GRPNAME and PORTAGE_USERNAME to
169 initialize global variables. This allows settings to come from make.conf
170 instead of requiring them to be set in the calling environment.
172 if '_portage_grpname' not in _initialized_globals and \
173 '_portage_uname' not in _initialized_globals:
175 v = settings.get('PORTAGE_GRPNAME')
177 globals()['_portage_grpname'] = v
178 _initialized_globals.add('_portage_grpname')
180 v = settings.get('PORTAGE_USERNAME')
182 globals()['_portage_uname'] = v
183 _initialized_globals.add('_portage_uname')