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 | ||
|
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 |
|
|
|
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