1# Copyright 2007 Google Inc. 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software Foundation, 15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16"""NSS utility library.""" 17 18__author__ = 'vasilios@google.com (Vasilios Hoffman)' 19 20import pwd 21import grp 22import logging 23import subprocess 24 25from nss_cache import config 26from nss_cache import error 27from nss_cache.maps import group 28from nss_cache.maps import passwd 29from nss_cache.maps import shadow 30 31# TODO(v): this should be a config option someday, but it's as standard 32# as libc so at the moment we'll leave it be for simplicity. 33GETENT = '/usr/bin/getent' 34 35 36def GetMap(map_name): 37 """Retrieves a Map of type map_name via nss calls.""" 38 39 if map_name == config.MAP_PASSWORD: 40 return GetPasswdMap() 41 elif map_name == config.MAP_GROUP: 42 return GetGroupMap() 43 elif map_name == config.MAP_SHADOW: 44 return GetShadowMap() 45 46 raise error.UnsupportedMap 47 48 49def GetPasswdMap(): 50 """Returns a PasswdMap built from nss calls.""" 51 passwd_map = passwd.PasswdMap() 52 53 for nss_entry in pwd.getpwall(): 54 map_entry = passwd.PasswdMapEntry() 55 map_entry.name = nss_entry[0] 56 map_entry.passwd = nss_entry[1] 57 map_entry.uid = nss_entry[2] 58 map_entry.gid = nss_entry[3] 59 map_entry.gecos = nss_entry[4] 60 map_entry.dir = nss_entry[5] 61 map_entry.shell = nss_entry[6] 62 passwd_map.Add(map_entry) 63 64 return passwd_map 65 66 67def GetGroupMap(): 68 """Returns a GroupMap built from nss calls.""" 69 group_map = group.GroupMap() 70 71 for nss_entry in grp.getgrall(): 72 map_entry = group.GroupMapEntry() 73 map_entry.name = nss_entry[0] 74 map_entry.passwd = nss_entry[1] 75 map_entry.gid = nss_entry[2] 76 map_entry.members = nss_entry[3] 77 if not map_entry.members: 78 map_entry.members = [''] 79 group_map.Add(map_entry) 80 81 return group_map 82 83 84def GetShadowMap(): 85 """Returns a ShadowMap built from nss calls.""" 86 getent = _SpawnGetent(config.MAP_SHADOW) 87 (getent_stdout, getent_stderr) = getent.communicate() 88 89 # The following is going to be map-specific each time, so no point in 90 # making more methods. 91 shadow_map = shadow.ShadowMap() 92 93 for line in getent_stdout.split(): 94 line = line.decode('utf-8') 95 nss_entry = line.strip().split(':') 96 map_entry = shadow.ShadowMapEntry() 97 map_entry.name = nss_entry[0] 98 map_entry.passwd = nss_entry[1] 99 if nss_entry[2] != '': 100 map_entry.lstchg = int(nss_entry[2]) 101 if nss_entry[3] != '': 102 map_entry.min = int(nss_entry[3]) 103 if nss_entry[4] != '': 104 map_entry.max = int(nss_entry[4]) 105 if nss_entry[5] != '': 106 map_entry.warn = int(nss_entry[5]) 107 if nss_entry[6] != '': 108 map_entry.inact = int(nss_entry[6]) 109 if nss_entry[7] != '': 110 map_entry.expire = int(nss_entry[7]) 111 if nss_entry[8] != '': 112 map_entry.flag = int(nss_entry[8]) 113 shadow_map.Add(map_entry) 114 115 if getent_stderr: 116 logging.debug('captured error %s', getent_stderr) 117 118 retval = getent.returncode 119 120 if retval != 0: 121 logging.warning('%s returned error code: %d', GETENT, retval) 122 123 return shadow_map 124 125 126def _SpawnGetent(map_name): 127 """Run 'getent map' in a subprocess for reading NSS data.""" 128 getent = subprocess.Popen([GETENT, map_name], 129 stdout=subprocess.PIPE, 130 stderr=subprocess.PIPE) 131 132 return getent 133