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 | particular repository. This file is not version-controlled, and |
|
50 | particular repository. This file is not version-controlled, and | |
51 | will not get transferred during a "clone" operation. Options in |
|
51 | will not get transferred during a "clone" operation. Options in | |
52 | this file override options in all other configuration files. |
|
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 | SYNTAX |
|
56 | SYNTAX | |
55 | ------ |
|
57 | ------ | |
@@ -349,6 +351,16 b' server::' | |||||
349 | 6Mbps), uncompressed streaming is slower, because of the extra |
|
351 | 6Mbps), uncompressed streaming is slower, because of the extra | |
350 | data transfer overhead. Default is False. |
|
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 | ui:: |
|
364 | ui:: | |
353 | User interface controls. |
|
365 | User interface controls. | |
354 | debug;; |
|
366 | debug;; |
@@ -19,6 +19,8 b' class ui(object):' | |||||
19 | # this is the parent of all ui children |
|
19 | # this is the parent of all ui children | |
20 | self.parentui = None |
|
20 | self.parentui = None | |
21 | self.readhooks = list(readhooks) |
|
21 | self.readhooks = list(readhooks) | |
|
22 | self.trusted_users = {} | |||
|
23 | self.trusted_groups = {} | |||
22 | self.cdata = ConfigParser.SafeConfigParser() |
|
24 | self.cdata = ConfigParser.SafeConfigParser() | |
23 | self.readconfig(util.rcpath()) |
|
25 | self.readconfig(util.rcpath()) | |
24 |
|
26 | |||
@@ -37,6 +39,8 b' class ui(object):' | |||||
37 | # parentui may point to an ui object which is already a child |
|
39 | # parentui may point to an ui object which is already a child | |
38 | self.parentui = parentui.parentui or parentui |
|
40 | self.parentui = parentui.parentui or parentui | |
39 | self.readhooks = list(parentui.readhooks or readhooks) |
|
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 | parent_cdata = self.parentui.cdata |
|
44 | parent_cdata = self.parentui.cdata | |
41 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) |
|
45 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) | |
42 | # make interpolation work |
|
46 | # make interpolation work | |
@@ -72,7 +76,22 b' class ui(object):' | |||||
72 | fn = [fn] |
|
76 | fn = [fn] | |
73 | for f in fn: |
|
77 | for f in fn: | |
74 | try: |
|
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 | except ConfigParser.ParsingError, inst: |
|
95 | except ConfigParser.ParsingError, inst: | |
77 | raise util.Abort(_("Failed to parse %s\n%s") % (f, inst)) |
|
96 | raise util.Abort(_("Failed to parse %s\n%s") % (f, inst)) | |
78 | # translate paths relative to root (or home) into absolute paths |
|
97 | # translate paths relative to root (or home) into absolute paths | |
@@ -81,6 +100,13 b' class ui(object):' | |||||
81 | for name, path in self.configitems("paths"): |
|
100 | for name, path in self.configitems("paths"): | |
82 | if path and "://" not in path and not os.path.isabs(path): |
|
101 | if path and "://" not in path and not os.path.isabs(path): | |
83 | self.cdata.set("paths", name, os.path.join(root, path)) |
|
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 | for hook in self.readhooks: |
|
110 | for hook in self.readhooks: | |
85 | hook(self) |
|
111 | hook(self) | |
86 |
|
112 |
@@ -15,7 +15,7 b' platform-specific details from the core.' | |||||
15 | from i18n import gettext as _ |
|
15 | from i18n import gettext as _ | |
16 | from demandload import * |
|
16 | from demandload import * | |
17 | demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile") |
|
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 | # used by parsedate |
|
20 | # used by parsedate | |
21 | defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', |
|
21 | defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', | |
@@ -509,6 +509,38 b' def getuser():' | |||||
509 | raise Abort(_('user name not available - set USERNAME ' |
|
509 | raise Abort(_('user name not available - set USERNAME ' | |
510 | 'environment variable')) |
|
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 | # Platform specific variants |
|
544 | # Platform specific variants | |
513 | if os.name == 'nt': |
|
545 | if os.name == 'nt': | |
514 | demandload(globals(), "msvcrt") |
|
546 | demandload(globals(), "msvcrt") |
General Comments 0
You need to be logged in to leave comments.
Login now