Add support for PORTAGE_USERNAME and PORTAGE_GROUPNAME environment
[portage.git] / pym / portage / data.py
1 # data.py -- Calculated/Discovered Data Values
2 # Copyright 1998-2009 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Id$
5
6 import os, sys, pwd, grp, platform
7 from portage.const import PORTAGE_GROUPNAME, PORTAGE_USERNAME
8
9 import portage
10 portage.proxy.lazyimport.lazyimport(globals(),
11         'portage.output:colorize',
12         'portage.util:writemsg',
13 )
14 from portage.localization import _
15
16 ostype=platform.system()
17 userland = None
18 if ostype == "DragonFly" or ostype.endswith("BSD"):
19         userland = "BSD"
20 else:
21         userland = "GNU"
22
23 lchown = getattr(os, "lchown", None)
24
25 if not lchown:
26         if ostype == "Darwin":
27                 def lchown(*pos_args, **key_args):
28                         pass
29         else:
30                 try:
31                         import missingos
32                         lchown = missingos.lchown
33                 except ImportError:
34                         def lchown(*pos_args, **key_args):
35                                 writemsg(colorize("BAD", "!!!") + _(
36                                         " It seems that os.lchown does not"
37                                         " exist.  Please rebuild python.\n"), noiselevel=-1)
38                         lchown()
39
40 lchown = portage._unicode_func_wrapper(lchown)
41
42 def portage_group_warning():
43         warn_prefix = colorize("BAD", "*** WARNING ***  ")
44         mylines = [
45                 "For security reasons, only system administrators should be",
46                 "allowed in the portage group.  Untrusted users or processes",
47                 "can potentially exploit the portage group for attacks such as",
48                 "local privilege escalation."
49         ]
50         for x in mylines:
51                 writemsg(warn_prefix, noiselevel=-1)
52                 writemsg(x, noiselevel=-1)
53                 writemsg("\n", noiselevel=-1)
54         writemsg("\n", noiselevel=-1)
55
56 # Portage has 3 security levels that depend on the uid and gid of the main
57 # process and are assigned according to the following table:
58 #
59 # Privileges  secpass  uid    gid
60 # normal      0        any    any
61 # group       1        any    portage_gid
62 # super       2        0      any
63 #
64 # If the "wheel" group does not exist then wheelgid falls back to 0.
65 # If the "portage" group does not exist then portage_uid falls back to wheelgid.
66
67 secpass=0
68
69 uid=os.getuid()
70 wheelgid=0
71
72 if uid==0:
73         secpass=2
74 try:
75         wheelgid=grp.getgrnam("wheel")[2]
76 except KeyError:
77         pass
78
79 #Discover the uid and gid of the portage user/group
80 try:
81         portage_uid = pwd.getpwnam(PORTAGE_USERNAME)[2]
82         portage_gid = grp.getgrnam(PORTAGE_GROUPNAME)[2]
83         if secpass < 1 and portage_gid in os.getgroups():
84                 secpass=1
85 except KeyError:
86         portage_uid=0
87         portage_gid=0
88         userpriv_groups = [portage_gid]
89         writemsg(colorize("BAD",
90                 _("portage: 'portage' user or group missing.")) + "\n", noiselevel=-1)
91         writemsg(_(
92                 "         For the defaults, line 1 goes into passwd, "
93                 "and 2 into group.\n"), noiselevel=-1)
94         writemsg(colorize("GOOD",
95                 "         portage:x:250:250:portage:/var/tmp/portage:/bin/false") \
96                 + "\n", noiselevel=-1)
97         writemsg(colorize("GOOD", "         portage::250:portage") + "\n",
98                 noiselevel=-1)
99         portage_group_warning()
100 else:
101         userpriv_groups = [portage_gid]
102         if secpass >= 2:
103                 # Get a list of group IDs for the portage user. Do not use
104                 # grp.getgrall() since it is known to trigger spurious
105                 # SIGPIPE problems with nss_ldap.
106                 try:
107                         from subprocess import getstatusoutput
108                 except ImportError:
109                         from commands import getstatusoutput
110                 mystatus, myoutput = getstatusoutput("id -G portage")
111                 if mystatus == os.EX_OK:
112                         for x in myoutput.split():
113                                 try:
114                                         userpriv_groups.append(int(x))
115                                 except ValueError:
116                                         pass
117                                 del x
118                         userpriv_groups = list(set(userpriv_groups))
119                 del getstatusoutput, mystatus, myoutput