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