1 2from __future__ import absolute_import, print_function 3import os, pwd, grp 4 5from bup import _helpers 6from bup.helpers import cache_key_value 7 8 9# Using __slots__ makes these much smaller (even than a namedtuple) 10 11class Passwd: 12 """Drop in replacement for pwd's structure with bytes instead of strings.""" 13 __slots__ = ('pw_name', 'pw_passwd', 'pw_uid', 'pw_gid', 'pw_gecos', 14 'pw_dir', 'pw_shell') 15 def __init__(self, name, passwd, uid, gid, gecos, dir, shell): 16 assert isinstance(name, bytes) 17 assert isinstance(passwd, bytes) 18 assert isinstance(gecos, bytes) 19 assert isinstance(dir, bytes) 20 assert isinstance(shell, bytes) 21 (self.pw_name, self.pw_passwd, self.pw_uid, self.pw_gid, 22 self.pw_gecos, self.pw_dir, self.pw_shell) = \ 23 name, passwd, uid, gid, gecos, dir, shell 24 25def getpwuid(uid): 26 r = _helpers.getpwuid(uid) 27 return Passwd(*r) if r else None 28 29def getpwnam(name): 30 assert isinstance(name, bytes) 31 r = _helpers.getpwnam(name) 32 return Passwd(*r) if r else None 33 34 35class Group: 36 """Drop in replacement for grp's structure with bytes instead of strings.""" 37 __slots__ = 'gr_name', 'gr_passwd', 'gr_gid', 'gr_mem' 38 def __init__(self, name, passwd, gid, mem): 39 assert isinstance(name, bytes) 40 assert isinstance(passwd, bytes) 41 for m in mem: 42 assert isinstance(m, bytes) 43 self.gr_name, self.gr_passwd, self.gr_gid, self.gr_mem = \ 44 name, passwd, gid, mem 45 46def getgrgid(uid): 47 r = _helpers.getgrgid(uid) 48 return Group(*r) if r else None 49 50def getgrnam(name): 51 assert isinstance(name, bytes) 52 r = _helpers.getgrnam(name) 53 return Group(*r) if r else None 54 55 56_uid_to_pwd_cache = {} 57_name_to_pwd_cache = {} 58 59def pwd_from_uid(uid): 60 """Return password database entry for uid (may be a cached value). 61 Return None if no entry is found. 62 """ 63 global _uid_to_pwd_cache, _name_to_pwd_cache 64 entry, cached = cache_key_value(getpwuid, uid, _uid_to_pwd_cache) 65 if entry and not cached: 66 _name_to_pwd_cache[entry.pw_name] = entry 67 return entry 68 69def pwd_from_name(name): 70 """Return password database entry for name (may be a cached value). 71 Return None if no entry is found. 72 """ 73 assert isinstance(name, bytes) 74 global _uid_to_pwd_cache, _name_to_pwd_cache 75 entry, cached = cache_key_value(getpwnam, name, _name_to_pwd_cache) 76 if entry and not cached: 77 _uid_to_pwd_cache[entry.pw_uid] = entry 78 return entry 79 80 81_gid_to_grp_cache = {} 82_name_to_grp_cache = {} 83 84def grp_from_gid(gid): 85 """Return password database entry for gid (may be a cached value). 86 Return None if no entry is found. 87 """ 88 global _gid_to_grp_cache, _name_to_grp_cache 89 entry, cached = cache_key_value(getgrgid, gid, _gid_to_grp_cache) 90 if entry and not cached: 91 _name_to_grp_cache[entry.gr_name] = entry 92 return entry 93 94 95def grp_from_name(name): 96 """Return password database entry for name (may be a cached value). 97 Return None if no entry is found. 98 """ 99 assert isinstance(name, bytes) 100 global _gid_to_grp_cache, _name_to_grp_cache 101 entry, cached = cache_key_value(getgrnam, name, _name_to_grp_cache) 102 if entry and not cached: 103 _gid_to_grp_cache[entry.gr_gid] = entry 104 return entry 105 106 107_username = None 108def username(): 109 """Get the user's login name.""" 110 global _username 111 if not _username: 112 uid = os.getuid() 113 _username = pwd_from_uid(uid).pw_name or b'user%d' % uid 114 return _username 115 116 117_userfullname = None 118def userfullname(): 119 """Get the user's full name.""" 120 global _userfullname 121 if not _userfullname: 122 uid = os.getuid() 123 entry = pwd_from_uid(uid) 124 if entry: 125 _userfullname = entry.pw_gecos.split(b',')[0] or entry.pw_name 126 if not _userfullname: 127 _userfullname = b'user%d' % uid 128 return _userfullname 129