##// END OF EJS Templates
Only read .hg/hgrc files from trusted users/groups...
Alexis S. L. Carvalho -
r3551:3b07e223 default
parent child Browse files
Show More
@@ -0,0 +1,113 b''
1 #!/usr/bin/env python
2 # Since it's not easy to write a test that portably deals
3 # with files from different users/groups, we cheat a bit by
4 # monkey-patching some functions in the util module
5
6 import os
7 from mercurial import ui, util
8
9 hgrc = os.environ['HGRCPATH']
10
11 def testui(user='foo', group='bar', tusers=(), tgroups=(),
12 cuser='foo', cgroup='bar', debug=False):
13 # user, group => owners of the file
14 # tusers, tgroups => trusted users/groups
15 # cuser, cgroup => user/group of the current process
16
17 # write a global hgrc with the list of trusted users/groups and
18 # some setting so that we can be sure it was read
19 f = open(hgrc, 'w')
20 f.write('[paths]\n')
21 f.write('global = /some/path\n\n')
22
23 if tusers or tgroups:
24 f.write('[trusted]\n')
25 if tusers:
26 f.write('users = %s\n' % ', '.join(tusers))
27 if tgroups:
28 f.write('groups = %s\n' % ', '.join(tgroups))
29 f.close()
30
31 # override the functions that give names to uids and gids
32 def username(uid=None):
33 if uid is None:
34 return cuser
35 return user
36 util.username = username
37
38 def groupname(gid=None):
39 if gid is None:
40 return 'bar'
41 return group
42 util.groupname = groupname
43
44 # try to read everything
45 #print '# File belongs to user %s, group %s' % (user, group)
46 #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
47 kind = ('different', 'same')
48 who = ('', 'user', 'group', 'user and the group')
49 trusted = who[(user in tusers) + 2*(group in tgroups)]
50 if trusted:
51 trusted = ', but we trust the ' + trusted
52 print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
53 trusted)
54
55 parentui = ui.ui()
56 parentui.updateopts(debug=debug)
57 u = ui.ui(parentui=parentui)
58 u.readconfig('.hg/hgrc')
59 for name, path in u.configitems('paths'):
60 print ' ', name, '=', path
61 print
62
63 return u
64
65 os.mkdir('repo')
66 os.chdir('repo')
67 os.mkdir('.hg')
68 f = open('.hg/hgrc', 'w')
69 f.write('[paths]\n')
70 f.write('local = /another/path\n\n')
71 f.close()
72
73 #print '# Everything is run by user foo, group bar\n'
74
75 # same user, same group
76 testui()
77 # same user, different group
78 testui(group='def')
79 # different user, same group
80 testui(user='abc')
81 # ... but we trust the group
82 testui(user='abc', tgroups=['bar'])
83 # different user, different group
84 testui(user='abc', group='def')
85 # ... but we trust the user
86 testui(user='abc', group='def', tusers=['abc'])
87 # ... but we trust the group
88 testui(user='abc', group='def', tgroups=['def'])
89 # ... but we trust the user and the group
90 testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
91 # ... but we trust all users
92 print '# we trust all users'
93 testui(user='abc', group='def', tusers=['*'])
94 # ... but we trust all groups
95 print '# we trust all groups'
96 testui(user='abc', group='def', tgroups=['*'])
97 # ... but we trust the whole universe
98 print '# we trust all users and groups'
99 testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
100 # ... check that users and groups are in different namespaces
101 print "# we don't get confused by users and groups with the same name"
102 testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
103 # ... lists of user names work
104 print "# list of user names"
105 testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
106 tgroups=['bar', 'baz', 'qux'])
107 # ... lists of group names work
108 print "# list of group names"
109 testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
110 tgroups=['bar', 'def', 'baz', 'qux'])
111
112 print "# Can't figure out the name of the user running this process"
113 testui(user='abc', group='def', cuser=None)
@@ -0,0 +1,67 b''
1 # same user, same group
2 global = /some/path
3 local = /another/path
4
5 # same user, different group
6 global = /some/path
7 local = /another/path
8
9 # different user, same group
10 Not reading file .hg/hgrc from untrusted user abc, group bar
11 global = /some/path
12
13 # different user, same group, but we trust the group
14 global = /some/path
15 local = /another/path
16
17 # different user, different group
18 Not reading file .hg/hgrc from untrusted user abc, group def
19 global = /some/path
20
21 # different user, different group, but we trust the user
22 global = /some/path
23 local = /another/path
24
25 # different user, different group, but we trust the group
26 global = /some/path
27 local = /another/path
28
29 # different user, different group, but we trust the user and the group
30 global = /some/path
31 local = /another/path
32
33 # we trust all users
34 # different user, different group
35 global = /some/path
36 local = /another/path
37
38 # we trust all groups
39 # different user, different group
40 global = /some/path
41 local = /another/path
42
43 # we trust all users and groups
44 # different user, different group
45 global = /some/path
46 local = /another/path
47
48 # we don't get confused by users and groups with the same name
49 # different user, different group
50 Not reading file .hg/hgrc from untrusted user abc, group def
51 global = /some/path
52
53 # list of user names
54 # different user, different group, but we trust the user
55 global = /some/path
56 local = /another/path
57
58 # list of group names
59 # different user, different group, but we trust the group
60 global = /some/path
61 local = /another/path
62
63 # Can't figure out the name of the user running this process
64 # different user, different group
65 global = /some/path
66 local = /another/path
67
@@ -50,6 +50,8 b' installed.'
50 50 particular repository. This file is not version-controlled, and
51 51 will not get transferred during a "clone" operation. Options in
52 52 this file override options in all other configuration files.
53 On Unix, this file is only read if it belongs to a trusted user
54 or to a trusted group.
53 55
54 56 SYNTAX
55 57 ------
@@ -364,6 +366,17 b' server::'
364 366 6Mbps), uncompressed streaming is slower, because of the extra
365 367 data transfer overhead. Default is False.
366 368
369 trusted::
370 Mercurial will only read the .hg/hgrc file from a repository if
371 it belongs to a trusted user or to a trusted group. This section
372 specifies what users and groups are trusted. The current user is
373 always trusted. To trust everybody, list a user or a group with
374 name "*".
375 users;;
376 Comma-separated list of trusted users.
377 groups;;
378 Comma-separated list of trusted groups.
379
367 380 ui::
368 381 User interface controls.
369 382 debug;;
@@ -39,6 +39,8 b' class ui(object):'
39 39 self.debugflag = debug
40 40 self.interactive = interactive
41 41 self.traceback = traceback
42 self.trusted_users = {}
43 self.trusted_groups = {}
42 44 self.cdata = util.configparser()
43 45 self.readconfig(util.rcpath())
44 46 self.updateopts(verbose, debug, quiet, interactive)
@@ -46,6 +48,8 b' class ui(object):'
46 48 # parentui may point to an ui object which is already a child
47 49 self.parentui = parentui.parentui or parentui
48 50 self.readhooks = self.parentui.readhooks[:]
51 self.trusted_users = parentui.trusted_users.copy()
52 self.trusted_groups = parentui.trusted_groups.copy()
49 53 self.cdata = dupconfig(self.parentui.cdata)
50 54 if self.parentui.overlay:
51 55 self.overlay = dupconfig(self.parentui.overlay)
@@ -82,12 +86,32 b' class ui(object):'
82 86 elif self.verbose and self.quiet:
83 87 self.quiet = self.verbose = False
84 88
89 def _is_trusted(self, fp, f, warn=True):
90 tusers = self.trusted_users
91 tgroups = self.trusted_groups
92 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
93 st = util.fstat(fp)
94 user = util.username(st.st_uid)
95 group = util.groupname(st.st_gid)
96 if user not in tusers and group not in tgroups:
97 if warn:
98 self.warn(_('Not reading file %s from untrusted '
99 'user %s, group %s\n') % (f, user, group))
100 return False
101 return True
102
85 103 def readconfig(self, fn, root=None):
86 104 if isinstance(fn, basestring):
87 105 fn = [fn]
88 106 for f in fn:
89 107 try:
90 self.cdata.read(f)
108 fp = open(f)
109 except IOError:
110 continue
111 if not self._is_trusted(fp, f):
112 continue
113 try:
114 self.cdata.readfp(fp, f)
91 115 except ConfigParser.ParsingError, inst:
92 116 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
93 117 # override data from config files with data set with ui.setconfig
@@ -144,6 +168,16 b' class ui(object):'
144 168 if name is None or name == 'interactive':
145 169 self.interactive = self.configbool("ui", "interactive", True)
146 170
171 # update trust information
172 if section is None or section == 'trusted':
173 user = util.username()
174 if user is not None:
175 self.trusted_users[user] = 1
176 for user in self.configlist('trusted', 'users'):
177 self.trusted_users[user] = 1
178 for group in self.configlist('trusted', 'groups'):
179 self.trusted_groups[group] = 1
180
147 181 def setconfig(self, section, name, value):
148 182 if not self.overlay:
149 183 self.overlay = util.configparser()
@@ -519,6 +519,36 b' def is_win_9x():'
519 519 except AttributeError:
520 520 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
521 521
522 def username(uid=None):
523 """Return the name of the user with the given uid.
524
525 If uid is None, return the name of the current user."""
526 try:
527 import pwd
528 if uid is None:
529 uid = os.getuid()
530 try:
531 return pwd.getpwuid(uid)[0]
532 except KeyError:
533 return str(uid)
534 except ImportError:
535 return None
536
537 def groupname(gid=None):
538 """Return the name of the group with the given gid.
539
540 If gid is None, return the name of the current group."""
541 try:
542 import grp
543 if gid is None:
544 gid = os.getgid()
545 try:
546 return grp.getgrgid(gid)[0]
547 except KeyError:
548 return str(gid)
549 except ImportError:
550 return None
551
522 552 # Platform specific variants
523 553 if os.name == 'nt':
524 554 demandload(globals(), "msvcrt")
General Comments 0
You need to be logged in to leave comments. Login now