7 from invirt import common
8 from invirt.config import structs as config
9 from invirt import remctl
13 # expandOwner and expandAdmin form the API that needs to be exported
14 # for all authz modules.
18 def expandOwner(name):
19 """Expand an owner to a list of authorized users.
21 For the locker authz module, an owner is an Athena locker. Those
22 users who have been given the administrator ('a') bit on the root
23 of a locker are given access to any VM owned by that locker,
24 unless they also have been given a negative administrator bit.
26 If a locker doesn't exist, or we can't access the permissions, we
27 assume the ACL is empty.
30 path = _lockerPath(name)
31 cell = fs.whichcell(path)
32 auth = _authenticate(cell)
33 a = acl.ACL.retrieve(path)
37 if a.pos[ent] & acl.ADMINISTER:
38 allowed.update(_expandGroup(ent, cell=cell, auth=auth))
40 if a.neg[ent] & acl.ADMINISTER:
41 allowed.difference_update(_expandGroup(ent, cell=cell, auth=auth))
45 if e.errno in (errno.ENOENT, errno.EACCES):
51 def expandAdmin(name):
52 """Expand an administrator to a list of authorized users.
54 For locker-based authorization, the administrator is always
55 interpreted as an AFS entry (either a user or a group) in the
56 machine's home cell (athena.mit.edu for XVM).
58 cell = config.authz.afs.cells[0].cell
59 auth = _authenticate(cell)
60 return _expandGroup(name, cell=cell, auth=auth)
64 # These are helper functions, and aren't part of the authz API
68 def _authenticate(cell):
69 """Acquire AFS tokens for a cell if encryption is required by config.
71 If the Invirt configuration requires connections to this cell to
72 be encrypted, acquires tokens and returns True. Otherwise, returns
73 False. Consumers of this function must still be sure to encrypt
74 their own connections if necessary.
76 Cells not listed in the Invirt configuration default to requiring
77 encryption in order to maintain security by default.
79 Due to AFS's cross-realm auto-PTS-creation mechanism, using
80 authenticated connections by default should only fail for cells
81 which authenticate directly against the machine's home realm and
82 cells distantly related to the machine's home realm.
84 for c in config.authz.afs.cells:
85 if c.cell == cell and not c.auth:
89 common.captureOutput(['aklog', '-c', cell])
93 def _expandGroup(name, cell=None, auth=False):
94 """Expand an AFS group into a list of its members.
96 Because groups are not global, but can vary from cell to cell,
97 this function accepts as an optional argument the cell in which
98 this group should be resolved.
100 If no cell is specified, it is assumed that the default cell (or
101 ThisCell) should be used.
103 If the name is a user, not a group, then a single-element set with
104 the same name is returned.
106 As with expandOwner, if a group doesn't exist or if we're unable
107 to retrieve its membership, we assume it's empty.
110 ent = pts.PTS(cell, pts.PTS_ENCRYPT if auth else pts.PTS_UNAUTH).\
113 return set([ent.name])
115 return set([x.name for x in ent.members])
117 if e.errno in (errno.ENOENT, errno.EACCESS):
123 def _lockerPath(owner):
124 """Given the name of a locker, return a path to that locker.
126 This turns out to be pretty simple, thanks to the /mit
129 return '/mit/%s' % owner