Show More
@@ -0,0 +1,112 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'): | |
|
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 | u = ui.ui(parentui=parentui) | |
|
57 | u.readconfig('.hg/hgrc') | |
|
58 | for name, path in u.configitems('paths'): | |
|
59 | print name, '=', path | |
|
60 | ||
|
61 | ||
|
62 | return u | |
|
63 | ||
|
64 | os.mkdir('repo') | |
|
65 | os.chdir('repo') | |
|
66 | os.mkdir('.hg') | |
|
67 | f = open('.hg/hgrc', 'w') | |
|
68 | f.write('[paths]\n') | |
|
69 | f.write('local = /another/path\n\n') | |
|
70 | f.close() | |
|
71 | ||
|
72 | #print '# Everything is run by user foo, group bar\n' | |
|
73 | ||
|
74 | # same user, same group | |
|
75 | testui() | |
|
76 | # same user, different group | |
|
77 | testui(group='def') | |
|
78 | # different user, same group | |
|
79 | testui(user='abc') | |
|
80 | # ... but we trust the group | |
|
81 | testui(user='abc', tgroups=['bar']) | |
|
82 | # different user, different group | |
|
83 | testui(user='abc', group='def') | |
|
84 | # ... but we trust the user | |
|
85 | testui(user='abc', group='def', tusers=['abc']) | |
|
86 | # ... but we trust the group | |
|
87 | testui(user='abc', group='def', tgroups=['def']) | |
|
88 | # ... but we trust the user and the group | |
|
89 | testui(user='abc', group='def', tusers=['abc'], tgroups=['def']) | |
|
90 | # ... but we trust all users | |
|
91 | print '# we trust all users' | |
|
92 | testui(user='abc', group='def', tusers=['*']) | |
|
93 | # ... but we trust all groups | |
|
94 | print '# we trust all groups' | |
|
95 | testui(user='abc', group='def', tgroups=['*']) | |
|
96 | # ... but we trust the whole universe | |
|
97 | print '# we trust all users and groups' | |
|
98 | testui(user='abc', group='def', tusers=['*'], tgroups=['*']) | |
|
99 | # ... check that users and groups are in different namespaces | |
|
100 | print "# we don't get confused by users and groups with the same name" | |
|
101 | testui(user='abc', group='def', tusers=['def'], tgroups=['abc']) | |
|
102 | # ... lists of user names work | |
|
103 | print "# list of user names" | |
|
104 | testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'], | |
|
105 | tgroups=['bar', 'baz', 'qux']) | |
|
106 | # ... lists of group names work | |
|
107 | print "# list of group names" | |
|
108 | testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'], | |
|
109 | tgroups=['bar', 'def', 'baz', 'qux']) | |
|
110 | ||
|
111 | print "# Can't figure out the name of the user running this process" | |
|
112 | 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 | ------ |
@@ -349,6 +351,16 b' server::' | |||
|
349 | 351 | 6Mbps), uncompressed streaming is slower, because of the extra |
|
350 | 352 | data transfer overhead. Default is False. |
|
351 | 353 | |
|
354 | trusted:: | |
|
355 | Mercurial will only read the .hg/hgrc file from a repository if | |
|
356 | it belongs to a trusted user or to a trusted group. This section | |
|
357 | specifies what users and groups are trusted. To trust everybody, | |
|
358 | list a user or a group with name "*". | |
|
359 | users;; | |
|
360 | Comma-separated list of trusted users. | |
|
361 | groups;; | |
|
362 | Comma-separated list of trusted groups. | |
|
363 | ||
|
352 | 364 | ui:: |
|
353 | 365 | User interface controls. |
|
354 | 366 | debug;; |
@@ -19,6 +19,8 b' class ui(object):' | |||
|
19 | 19 | # this is the parent of all ui children |
|
20 | 20 | self.parentui = None |
|
21 | 21 | self.readhooks = list(readhooks) |
|
22 | self.trusted_users = {} | |
|
23 | self.trusted_groups = {} | |
|
22 | 24 | self.cdata = ConfigParser.SafeConfigParser() |
|
23 | 25 | self.readconfig(util.rcpath()) |
|
24 | 26 | |
@@ -37,6 +39,8 b' class ui(object):' | |||
|
37 | 39 | # parentui may point to an ui object which is already a child |
|
38 | 40 | self.parentui = parentui.parentui or parentui |
|
39 | 41 | self.readhooks = list(parentui.readhooks or readhooks) |
|
42 | self.trusted_users = parentui.trusted_users.copy() | |
|
43 | self.trusted_groups = parentui.trusted_groups.copy() | |
|
40 | 44 | parent_cdata = self.parentui.cdata |
|
41 | 45 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) |
|
42 | 46 | # make interpolation work |
@@ -72,7 +76,22 b' class ui(object):' | |||
|
72 | 76 | fn = [fn] |
|
73 | 77 | for f in fn: |
|
74 | 78 | try: |
|
75 |
|
|
|
79 | fp = open(f) | |
|
80 | except IOError: | |
|
81 | continue | |
|
82 | if ((self.trusted_users or self.trusted_groups) and | |
|
83 | '*' not in self.trusted_users and | |
|
84 | '*' not in self.trusted_groups): | |
|
85 | st = util.fstat(fp) | |
|
86 | user = util.username(st.st_uid) | |
|
87 | group = util.groupname(st.st_gid) | |
|
88 | if (user not in self.trusted_users and | |
|
89 | group not in self.trusted_groups): | |
|
90 | self.warn(_('not reading file %s from untrusted ' | |
|
91 | 'user %s, group %s\n') % (f, user, group)) | |
|
92 | continue | |
|
93 | try: | |
|
94 | self.cdata.readfp(fp, f) | |
|
76 | 95 | except ConfigParser.ParsingError, inst: |
|
77 | 96 | raise util.Abort(_("Failed to parse %s\n%s") % (f, inst)) |
|
78 | 97 | # translate paths relative to root (or home) into absolute paths |
@@ -81,6 +100,13 b' class ui(object):' | |||
|
81 | 100 | for name, path in self.configitems("paths"): |
|
82 | 101 | if path and "://" not in path and not os.path.isabs(path): |
|
83 | 102 | self.cdata.set("paths", name, os.path.join(root, path)) |
|
103 | user = util.username() | |
|
104 | if user is not None: | |
|
105 | self.trusted_users[user] = 1 | |
|
106 | for user in self.configlist('trusted', 'users'): | |
|
107 | self.trusted_users[user] = 1 | |
|
108 | for group in self.configlist('trusted', 'groups'): | |
|
109 | self.trusted_groups[group] = 1 | |
|
84 | 110 | for hook in self.readhooks: |
|
85 | 111 | hook(self) |
|
86 | 112 |
@@ -15,7 +15,7 b' platform-specific details from the core.' | |||
|
15 | 15 | from i18n import gettext as _ |
|
16 | 16 | from demandload import * |
|
17 | 17 | demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile") |
|
18 | demandload(globals(), "os threading time") | |
|
18 | demandload(globals(), "os threading time pwd grp") | |
|
19 | 19 | |
|
20 | 20 | # used by parsedate |
|
21 | 21 | defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', |
@@ -509,6 +509,38 b' def getuser():' | |||
|
509 | 509 | raise Abort(_('user name not available - set USERNAME ' |
|
510 | 510 | 'environment variable')) |
|
511 | 511 | |
|
512 | def username(uid=None): | |
|
513 | """Return the name of the user with the given uid. | |
|
514 | ||
|
515 | If uid is None, return the name of the current user.""" | |
|
516 | try: | |
|
517 | # force an ImportError if there's no module pwd | |
|
518 | getpwuid = pwd.getpwuid | |
|
519 | if uid is None: | |
|
520 | uid = os.getuid() | |
|
521 | try: | |
|
522 | return getpwuid(uid)[0] | |
|
523 | except KeyError: | |
|
524 | return str(uid) | |
|
525 | except ImportError: | |
|
526 | return None | |
|
527 | ||
|
528 | def groupname(gid=None): | |
|
529 | """Return the name of the group with the given gid. | |
|
530 | ||
|
531 | If gid is None, return the name of the current group.""" | |
|
532 | try: | |
|
533 | # force an ImportError if there's no module grp | |
|
534 | getgrgid = grp.getgrgid | |
|
535 | if gid is None: | |
|
536 | gid = os.getgid() | |
|
537 | try: | |
|
538 | return getgrgid(gid)[0] | |
|
539 | except KeyError: | |
|
540 | return str(gid) | |
|
541 | except ImportError: | |
|
542 | return None | |
|
543 | ||
|
512 | 544 | # Platform specific variants |
|
513 | 545 | if os.name == 'nt': |
|
514 | 546 | demandload(globals(), "msvcrt") |
General Comments 0
You need to be logged in to leave comments.
Login now