25 |
|
|
26 |
On the destination connection only, if necessary have a separate |
On the destination connection only, if necessary have a separate |
27 |
dictionary of mappings, which specify how to map users/groups on one |
dictionary of mappings, which specify how to map users/groups on one |
28 |
connection to the users/groups on the other. |
connection to the users/groups on the other. The UserMap and GroupMap |
29 |
|
objects should only be used on the destination. |
30 |
|
|
31 |
""" |
""" |
32 |
|
|
33 |
import grp, pwd |
import grp, pwd |
34 |
import log, Globals |
import log, Globals |
35 |
|
|
36 |
|
############ "Private" section - don't use outside user_group ########### |
37 |
|
|
38 |
# This should be set to the user UserMap class object if using |
# This should be set to the user UserMap class object if using |
39 |
# user-defined user mapping, and a Map class object otherwise. |
# user-defined user mapping, and a Map class object otherwise. |
40 |
UserMap = None |
UserMap = None |
43 |
# user-defined group mapping, and a Map class object otherwise. |
# user-defined group mapping, and a Map class object otherwise. |
44 |
GroupMap = None |
GroupMap = None |
45 |
|
|
46 |
|
# Used to cache by uid2uname and gid2gname below |
47 |
uid2uname_dict = {}; gid2gname_dict = {} |
uid2uname_dict = {}; gid2gname_dict = {} |
|
def uid2uname(uid): |
|
|
"""Given uid, return uname or None if cannot find""" |
|
|
try: return uid2uname_dict[uid] |
|
|
except KeyError: |
|
|
try: uname = pwd.getpwuid(uid)[0] |
|
|
except (KeyError, OverflowError), e: uname = None |
|
|
uid2uname_dict[uid] = uname |
|
|
return uname |
|
|
|
|
|
def gid2gname(gid): |
|
|
"""Given gid, return group name or None if cannot find""" |
|
|
try: return gid2gname_dict[gid] |
|
|
except KeyError: |
|
|
try: gname = grp.getgrgid(gid)[0] |
|
|
except (KeyError, OverflowError), e: gname = None |
|
|
gid2gname_dict[gid] = gname |
|
|
return gname |
|
48 |
|
|
49 |
|
uname2uid_dict = {} |
50 |
def uname2uid(uname): |
def uname2uid(uname): |
51 |
"""Given uname, return uid or None if cannot find""" |
"""Given uname, return uid or None if cannot find""" |
52 |
try: uname = pwd.getpwnam(uname)[2] |
try: return uname2uid_dict[uname] |
53 |
except KeyError: return None |
except KeyError: |
54 |
|
try: uid = pwd.getpwnam(uname)[2] |
55 |
|
except KeyError: uid = None |
56 |
|
uname2uid_dict[uname] = uid |
57 |
|
return uid |
58 |
|
|
59 |
|
gname2gid_dict = {} |
60 |
def gname2gid(gname): |
def gname2gid(gname): |
61 |
"""Given gname, return gid or None if cannot find""" |
"""Given gname, return gid or None if cannot find""" |
62 |
try: gname = grp.getgrnam(gname)[2] |
try: return gname2gid_dict[gname] |
63 |
except KeyError: return None |
except KeyError: |
64 |
|
try: gid = grp.getgrnam(gname)[2] |
65 |
|
except KeyError: gid = None |
66 |
|
gname2gid_dict[gname] = gid |
67 |
|
return gid |
68 |
|
|
69 |
|
|
70 |
class Map: |
class Map: |
71 |
"""Used for mapping names and id on source side to dest side""" |
"""Used for mapping names and id on source side to dest side""" |
72 |
def __init__(self, name2id_func): |
def __init__(self, is_user): |
73 |
"""Map initializer, set dictionaries""" |
"""Initialize, user is true for users, false for groups""" |
74 |
self.name2id_dict = {} |
self.name2id = (is_user and uname2uid) or gname2gid |
|
self.name2id_func = name2id_func |
|
75 |
|
|
76 |
def get_id(self, id, name = None): |
def __call__(self, id, name = None): |
77 |
"""Return mapped id from id and, if available, name""" |
"""Return mapped id from id and, if available, name""" |
78 |
if not name: return self.get_id_from_id(id) |
if not name: return id |
79 |
try: return self.name2id_dict[name] |
newid = self.name2id(name) |
80 |
except KeyError: |
if newid is None: return id |
81 |
out_id = self.find_id(id, name) |
else: return newid |
82 |
self.name2id_dict[name] = out_id |
|
83 |
return out_id |
def map_acl(self, id, name = None): |
84 |
|
"""Like get_id, but use this for ACLs. Return id or None |
85 |
def get_id_from_name(self, name): |
|
86 |
"""Return mapped id from name only, or None if cannot""" |
Unlike ordinary user/group ownership, ACLs are not required |
87 |
try: return self.name2id_dict[name] |
and can be dropped. If we cannot map the name over, return |
88 |
except KeyError: |
None. |
89 |
out_id = self.find_id_from_name(name) |
|
90 |
self.name2id_dict[name] = out_id |
""" |
91 |
return out_id |
if not name: return id |
92 |
|
return self.name2id(name) |
93 |
def get_id_from_id(self, id): return id |
|
94 |
|
|
|
def find_id(self, id, name): |
|
|
"""Find the proper id to use with given id and name""" |
|
|
try: return self.name2id_func(name) |
|
|
except KeyError: return id |
|
|
|
|
|
def find_id_from_name(self, name): |
|
|
"""Look up proper id to use with name, or None""" |
|
|
try: return self.name2id_func(name) |
|
|
except KeyError: return None |
|
|
|
|
95 |
class DefinedMap(Map): |
class DefinedMap(Map): |
96 |
"""Map names and ids on source side to appropriate ids on dest side |
"""Map names and ids on source side to appropriate ids on dest side |
97 |
|
|
99 |
supersedes Map. |
supersedes Map. |
100 |
|
|
101 |
""" |
""" |
102 |
def __init__(self, name2id_func, mapping_string): |
def __init__(self, is_user, mapping_string): |
103 |
"""Initialize object with given mapping string |
"""Initialize object with given mapping string |
104 |
|
|
105 |
The mapping_string should consist of a number of lines, each which |
The mapping_string should consist of a number of lines, each which |
107 |
mapping unless user is false, then do group. |
mapping unless user is false, then do group. |
108 |
|
|
109 |
""" |
""" |
110 |
Map.__init__(self, name2id_func) |
Map.__init__(self, is_user) |
111 |
self.name_mapping_dict = {}; self.id_mapping_dict = {} |
self.name_mapping_dict = {}; self.id_mapping_dict = {} |
112 |
|
|
113 |
for line in mapping_string.split('\n'): |
for line in mapping_string.split('\n'): |
127 |
"""Return id of id_or_name, failing if cannot. Used in __init__""" |
"""Return id of id_or_name, failing if cannot. Used in __init__""" |
128 |
try: return int(id_or_name) |
try: return int(id_or_name) |
129 |
except ValueError: |
except ValueError: |
130 |
try: id = self.name2id_func(id_or_name) |
try: return self.name2id(id_or_name) |
131 |
except KeyError: |
except KeyError: |
132 |
log.Log.FatalError("Cannot get id for user or group name " |
log.Log.FatalError("Cannot get id for user or group name " |
133 |
+ id_or_name) |
+ id_or_name) |
|
return id |
|
134 |
|
|
135 |
def get_id_from_id(self, id): return self.id_mapping_dict.get(id, id) |
def __call__(self, id, name = None): |
136 |
|
"""Return new id given old id and name""" |
137 |
|
newid = self.map_acl(id, name) |
138 |
|
if newid is None: return id |
139 |
|
else: return newid |
140 |
|
|
141 |
|
def map_acl(self, id, name = None): |
142 |
|
"""Return new id or None given old and name (used for ACLs)""" |
143 |
|
if name: |
144 |
|
try: return self.name_mapping_dict[name] |
145 |
|
except KeyError: pass |
146 |
|
newid = self.name2id(name) |
147 |
|
if newid is not None: return newid |
148 |
|
try: return self.id_mapping_dict[id] |
149 |
|
except KeyError: return None |
150 |
|
|
151 |
|
|
152 |
|
class NumericalMap: |
153 |
|
"""Simple Map replacement that just keeps numerical uid or gid""" |
154 |
|
def __call__(self, id, name = None): return id |
155 |
|
def map_acl(self, id, name = None): return id |
156 |
|
|
157 |
|
|
158 |
|
############ Public section - don't use outside user_group ########### |
159 |
|
|
|
def find_id(self, id, name): |
|
|
"""Find proper id to use when source file has give id and name""" |
|
|
try: return self.name_mapping_dict[name] |
|
|
except KeyError: |
|
|
try: return self.id_mapping_dict[id] |
|
|
except KeyError: return Map.find_id(self, id, name) |
|
|
|
|
|
def find_id_from_name(self, name): |
|
|
"""Find id to map name to, or None if we can't""" |
|
|
try: return self.name_mapping_dict[name] |
|
|
except KeyError: return Map.find_id_from_name(name) |
|
160 |
|
|
161 |
def init_user_mapping(mapping_string = None): |
def uid2uname(uid): |
162 |
"""Initialize user mapping with given mapping string or None""" |
"""Given uid, return uname from passwd file, or None if cannot find""" |
163 |
|
try: return uid2uname_dict[uid] |
164 |
|
except KeyError: |
165 |
|
try: uname = pwd.getpwuid(uid)[0] |
166 |
|
except (KeyError, OverflowError), e: uname = None |
167 |
|
uid2uname_dict[uid] = uname |
168 |
|
return uname |
169 |
|
|
170 |
|
def gid2gname(gid): |
171 |
|
"""Given gid, return group name from group file or None if cannot find""" |
172 |
|
try: return gid2gname_dict[gid] |
173 |
|
except KeyError: |
174 |
|
try: gname = grp.getgrgid(gid)[0] |
175 |
|
except (KeyError, OverflowError), e: gname = None |
176 |
|
gid2gname_dict[gid] = gname |
177 |
|
return gname |
178 |
|
|
179 |
|
|
180 |
|
def init_user_mapping(mapping_string = None, numerical_ids = None): |
181 |
|
"""Initialize user mapping with given mapping string |
182 |
|
|
183 |
|
If numerical_ids is set, just keep the same uid. If either |
184 |
|
argument is None, default to preserving uname where possible. |
185 |
|
|
186 |
|
""" |
187 |
global UserMap |
global UserMap |
188 |
name2id_func = lambda name: pwd.getpwnam(name)[2] |
if numerical_ids: UserMap = NumericalMap() |
189 |
if mapping_string: UserMap = DefinedMap(name2id_func, mapping_string) |
elif mapping_string: UserMap = DefinedMap(1, mapping_string) |
190 |
else: UserMap = Map(name2id_func) |
else: UserMap = Map(1) |
191 |
|
|
192 |
|
def init_group_mapping(mapping_string = None, numerical_ids = None): |
193 |
|
"""Initialize group mapping with given mapping string |
194 |
|
|
195 |
def init_group_mapping(mapping_string = None): |
If numerical_ids is set, just keep the same gid. If either |
196 |
"""Initialize the group mapping dictionary with given mapping string""" |
argument is None, default to preserving gname where possible. |
197 |
|
|
198 |
|
""" |
199 |
global GroupMap |
global GroupMap |
200 |
name2id_func = lambda name: grp.getgrnam(name)[2] |
if numerical_ids: GroupMap = NumericalMap() |
201 |
if mapping_string: GroupMap = DefinedMap(name2id_func, mapping_string) |
elif mapping_string: GroupMap = DefinedMap(0, mapping_string) |
202 |
else: GroupMap = Map(name2id_func) |
else: GroupMap = Map(0) |
203 |
|
|
204 |
|
|
|
|
|
205 |
def map_rpath(rp): |
def map_rpath(rp): |
206 |
"""Return (uid, gid) of mapped ownership of given rpath""" |
"""Return mapped (newuid, newgid) from rpath's initial info |
207 |
old_uid, old_gid = rp.getuidgid() |
|
208 |
new_uid = UserMap.get_id(old_uid, rp.getuname()) |
This is the main function exported by the user_group module. Note |
209 |
new_gid = GroupMap.get_id(old_gid, rp.getgname()) |
that it is connection specific. |
210 |
return (new_uid, new_gid) |
|
211 |
|
""" |
212 |
|
uid, gid = rp.getuidgid() |
213 |
|
uname, gname = rp.getuname(), rp.getgname() |
214 |
|
return (UserMap(uid, uname), GroupMap(gid, gname)) |
215 |
|
|