| 1 | from afs import _acl | 
|---|
| 2 | from afs._acl import READ, WRITE, INSERT, LOOKUP, DELETE, LOCK, ADMINISTER, \ | 
|---|
| 3 |     USR0, USR1, USR2, USR3, USR4, USR5, USR6, USR7 | 
|---|
| 4 | from afs._acl import getCallerAccess | 
|---|
| 5 |  | 
|---|
| 6 | _canonical = { | 
|---|
| 7 |     "read": "rl", | 
|---|
| 8 |     "write": "rlidwk", | 
|---|
| 9 |     "all": "rlidwka", | 
|---|
| 10 |     "mail": "lik", | 
|---|
| 11 |     "none": "", | 
|---|
| 12 | } | 
|---|
| 13 |  | 
|---|
| 14 | _reverseCanonical = dict((y, x) for (x, y) in _canonical.iteritems()) | 
|---|
| 15 |  | 
|---|
| 16 | _charBitAssoc = [ | 
|---|
| 17 |     ('r', READ), | 
|---|
| 18 |     ('l', LOOKUP), | 
|---|
| 19 |     ('i', INSERT), | 
|---|
| 20 |     ('d', DELETE), | 
|---|
| 21 |     ('w', WRITE), | 
|---|
| 22 |     ('k', LOCK), | 
|---|
| 23 |     ('a', ADMINISTER), | 
|---|
| 24 |     ('A', USR0), | 
|---|
| 25 |     ('B', USR1), | 
|---|
| 26 |     ('C', USR2), | 
|---|
| 27 |     ('D', USR3), | 
|---|
| 28 |     ('E', USR4), | 
|---|
| 29 |     ('F', USR5), | 
|---|
| 30 |     ('G', USR6), | 
|---|
| 31 |     ('H', USR7), | 
|---|
| 32 | ] | 
|---|
| 33 |  | 
|---|
| 34 | _char2bit = dict(_charBitAssoc) | 
|---|
| 35 |  | 
|---|
| 36 |  | 
|---|
| 37 | def rightsToEnglish(s): | 
|---|
| 38 |     """Turns a rlwidwka string into a canonical name if possible""" | 
|---|
| 39 |     if s in _reverseCanonical: | 
|---|
| 40 |         return _reverseCanonical[s] | 
|---|
| 41 |     else: | 
|---|
| 42 |         return '' | 
|---|
| 43 |  | 
|---|
| 44 | def readRights(s): | 
|---|
| 45 |     """Canonicalizes string rights to bitmask""" | 
|---|
| 46 |     if s in _canonical: s = _canonical[s] | 
|---|
| 47 |     return _parseRights(s) | 
|---|
| 48 |  | 
|---|
| 49 | def showRights(r): | 
|---|
| 50 |     """Takes a bitmask and returns a rwlidka string""" | 
|---|
| 51 |     s = "" | 
|---|
| 52 |     for char,mask in _charBitAssoc: | 
|---|
| 53 |         if r & mask == mask: s += char | 
|---|
| 54 |     return s | 
|---|
| 55 |  | 
|---|
| 56 | def _parseRights(s): | 
|---|
| 57 |     """Parses a rwlid... rights tring to bitmask""" | 
|---|
| 58 |     r = 0 | 
|---|
| 59 |     try: | 
|---|
| 60 |         for c in s: | 
|---|
| 61 |             r = r | _char2bit[c] | 
|---|
| 62 |     except KeyError: | 
|---|
| 63 |         raise ValueError | 
|---|
| 64 |     return r | 
|---|
| 65 |  | 
|---|
| 66 | def _parseAcl(inp): | 
|---|
| 67 |     lines = inp.split("\n") | 
|---|
| 68 |     npos = int(lines[0].split(" ")[0]) | 
|---|
| 69 |     pos = {} | 
|---|
| 70 |     neg = {} | 
|---|
| 71 |     for l in lines[2:]: | 
|---|
| 72 |         if l == "": continue | 
|---|
| 73 |         name, acl = l.split() | 
|---|
| 74 |         if npos: | 
|---|
| 75 |             npos -= 1 | 
|---|
| 76 |             pos[name] = int(acl) | 
|---|
| 77 |         else: | 
|---|
| 78 |             # negative acl | 
|---|
| 79 |             neg[name] = int(acl) | 
|---|
| 80 |     return (pos, neg) | 
|---|
| 81 |  | 
|---|
| 82 | def _unparseAcl(pos, neg): | 
|---|
| 83 |     npos = len(pos) | 
|---|
| 84 |     nneg = len(neg) | 
|---|
| 85 |     acl = "%d\n%d\n" % (npos, nneg) | 
|---|
| 86 |     for p in pos.items(): | 
|---|
| 87 |         acl += "%s\t%d\n" % p | 
|---|
| 88 |     for n in neg.items(): | 
|---|
| 89 |         acl += "%s\t%d\n" % n | 
|---|
| 90 |     return acl | 
|---|
| 91 |  | 
|---|
| 92 | class ACL(object): | 
|---|
| 93 |     def __init__(self, pos, neg): | 
|---|
| 94 |         """ | 
|---|
| 95 |         ``pos`` | 
|---|
| 96 |             Dictionary of usernames to positive ACL bitmasks | 
|---|
| 97 |         ``neg`` | 
|---|
| 98 |             Dictionary of usernames to negative ACL bitmasks | 
|---|
| 99 |         """ | 
|---|
| 100 |         self.pos = pos | 
|---|
| 101 |         self.neg = neg | 
|---|
| 102 |     @staticmethod | 
|---|
| 103 |     def retrieve(dir, follow=True): | 
|---|
| 104 |         """Retrieve the ACL for an AFS directory""" | 
|---|
| 105 |         pos, neg = _parseAcl(_acl.getAcl(dir, follow)) | 
|---|
| 106 |         return ACL(pos, neg) | 
|---|
| 107 |     def apply(self, dir, follow=True): | 
|---|
| 108 |         """Apply the ACL to a directory""" | 
|---|
| 109 |         self._clean() | 
|---|
| 110 |         _acl.setAcl(dir, _unparseAcl(self.pos, self.neg), follow) | 
|---|
| 111 |     def _clean(self): | 
|---|
| 112 |         """Clean an ACL by removing any entries whose bitmask is 0""" | 
|---|
| 113 |         for n,a in self.pos.items(): | 
|---|
| 114 |             if a == 0: | 
|---|
| 115 |                 del self.pos[n] | 
|---|
| 116 |         for n,a in self.neg.items(): | 
|---|
| 117 |             if a == 0: | 
|---|
| 118 |                 del self.neg[n] | 
|---|
| 119 |     def set(self, user, bitmask, negative=False): | 
|---|
| 120 |         """Set the bitmask for a given user""" | 
|---|
| 121 |         if bitmask < 0 or bitmask > max(_char2bit.values()): | 
|---|
| 122 |             raise ValueError, "Invalid bitmask" | 
|---|
| 123 |         if negative: | 
|---|
| 124 |             self.neg[user] = bitmask | 
|---|
| 125 |         else: | 
|---|
| 126 |             self.pos[user] = bitmask | 
|---|
| 127 |     def remove(self, user, negative=False): | 
|---|
| 128 |         """Convenience function to removeSet the bitmask for a given user""" | 
|---|
| 129 |         self.set(user, 0, negative) | 
|---|
| 130 |          | 
|---|