/usr/share/pyshared/rdiff_backup/user_group.py is in rdiff-backup 1.2.8-7.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | # Copyright 2002, 2003 Ben Escoto
#
# This file is part of rdiff-backup.
#
# rdiff-backup is free software; you can redistribute it and/or modify
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# rdiff-backup is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with rdiff-backup; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
"""This module deal with users and groups
On each connection we may need to map unames and gnames to uids and
gids, and possibly vice-versa. So maintain a separate dictionary for
this.
On the destination connection only, if necessary have a separate
dictionary of mappings, which specify how to map users/groups on one
connection to the users/groups on the other. The UserMap and GroupMap
objects should only be used on the destination.
"""
try:
import grp, pwd
except ImportError:
pass
import log, Globals
############ "Private" section - don't use outside user_group ###########
# This should be set to the user UserMap class object if using
# user-defined user mapping, and a Map class object otherwise.
UserMap = None
# This should be set to the group UserMap class object if using
# user-defined group mapping, and a Map class object otherwise.
GroupMap = None
# Used to cache by uid2uname and gid2gname below
uid2uname_dict = {}; gid2gname_dict = {}
uname2uid_dict = {}
def uname2uid(uname):
"""Given uname, return uid or None if cannot find"""
try: return uname2uid_dict[uname]
except KeyError:
try: uid = pwd.getpwnam(uname)[2]
except (KeyError, NameError): uid = None
uname2uid_dict[uname] = uid
return uid
gname2gid_dict = {}
def gname2gid(gname):
"""Given gname, return gid or None if cannot find"""
try: return gname2gid_dict[gname]
except KeyError:
try: gid = grp.getgrnam(gname)[2]
except (KeyError, NameError): gid = None
gname2gid_dict[gname] = gid
return gid
class Map:
"""Used for mapping names and id on source side to dest side"""
def __init__(self, is_user):
"""Initialize, user is true for users, false for groups"""
self.name2id = (is_user and uname2uid) or gname2gid
def __call__(self, id, name = None):
"""Return mapped id from id and, if available, name"""
if not name: return id
newid = self.name2id(name)
if newid is None: return id
else: return newid
def map_acl(self, id, name = None):
"""Like get_id, but use this for ACLs. Return id or None
Unlike ordinary user/group ownership, ACLs are not required
and can be dropped. If we cannot map the name over, return
None.
"""
if not name: return id
return self.name2id(name)
class DefinedMap(Map):
"""Map names and ids on source side to appropriate ids on dest side
Like map, but initialize with user-defined mapping string, which
supersedes Map.
"""
def __init__(self, is_user, mapping_string):
"""Initialize object with given mapping string
The mapping_string should consist of a number of lines, each which
should have the form "source_id_or_name:dest_id_or_name". Do user
mapping unless user is false, then do group.
"""
Map.__init__(self, is_user)
self.name_mapping_dict = {}; self.id_mapping_dict = {}
for line in mapping_string.split('\n'):
line = line.strip()
if not line: continue
comps = line.split(':')
if not len(comps) == 2:
log.Log.FatalError("Error parsing mapping file, bad line: "
+ line)
old, new = comps
try: self.id_mapping_dict[int(old)] = self.init_get_new_id(new)
except ValueError:
self.name_mapping_dict[old] = self.init_get_new_id(new)
def init_get_new_id(self, id_or_name):
"""Return id of id_or_name, failing if cannot. Used in __init__"""
try: return int(id_or_name)
except ValueError:
try: return self.name2id(id_or_name)
except KeyError:
log.Log.FatalError("Cannot get id for user or group name "
+ id_or_name)
def __call__(self, id, name = None):
"""Return new id given old id and name"""
newid = self.map_acl(id, name)
if newid is None: return id
else: return newid
def map_acl(self, id, name = None):
"""Return new id or None given old and name (used for ACLs)"""
if name:
try: return self.name_mapping_dict[name]
except KeyError: pass
newid = self.name2id(name)
if newid is not None: return newid
try: return self.id_mapping_dict[id]
except KeyError: return None
class NumericalMap:
"""Simple Map replacement that just keeps numerical uid or gid"""
def __call__(self, id, name = None): return id
def map_acl(self, id, name = None): return id
############ Public section - can use these outside user_group ###########
def uid2uname(uid):
"""Given uid, return uname from passwd file, or None if cannot find"""
try: return uid2uname_dict[uid]
except KeyError:
try: uname = pwd.getpwuid(uid)[0]
except (KeyError, OverflowError, NameError), e: uname = None
uid2uname_dict[uid] = uname
return uname
def gid2gname(gid):
"""Given gid, return group name from group file or None if cannot find"""
try: return gid2gname_dict[gid]
except KeyError:
try: gname = grp.getgrgid(gid)[0]
except (KeyError, OverflowError, NameError), e: gname = None
gid2gname_dict[gid] = gname
return gname
def init_user_mapping(mapping_string = None, numerical_ids = None):
"""Initialize user mapping with given mapping string
If numerical_ids is set, just keep the same uid. If either
argument is None, default to preserving uname where possible.
"""
global UserMap
if numerical_ids: UserMap = NumericalMap()
elif mapping_string: UserMap = DefinedMap(1, mapping_string)
else: UserMap = Map(1)
def init_group_mapping(mapping_string = None, numerical_ids = None):
"""Initialize group mapping with given mapping string
If numerical_ids is set, just keep the same gid. If either
argument is None, default to preserving gname where possible.
"""
global GroupMap
if numerical_ids: GroupMap = NumericalMap()
elif mapping_string: GroupMap = DefinedMap(0, mapping_string)
else: GroupMap = Map(0)
def map_rpath(rp):
"""Return mapped (newuid, newgid) from rpath's initial info
This is the main function exported by the user_group module. Note
that it is connection specific.
"""
uid, gid = rp.getuidgid()
uname, gname = rp.getuname(), rp.getgname()
return (UserMap(uid, uname), GroupMap(gid, gname))
def acl_user_map(uid, uname): return UserMap.map_acl(uid, uname)
def acl_group_map(gid, gname): return GroupMap.map_acl(gid, gname)
|