1#!/usr/bin/env python 2# coding: utf-8 3 4# getent.py - program for querying nslcd 5# 6# Copyright (C) 2013-2019 Arthur de Jong 7# 8# This library is free software; you can redistribute it and/or 9# modify it under the terms of the GNU Lesser General Public 10# License as published by the Free Software Foundation; either 11# version 2.1 of the License, or (at your option) any later version. 12# 13# This library is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16# Lesser General Public License for more details. 17# 18# You should have received a copy of the GNU Lesser General Public 19# License along with this library; if not, write to the Free Software 20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21# 02110-1301 USA 22 23import argparse 24import re 25import socket 26import struct 27import sys 28 29import constants 30from cmdline import VersionAction 31from nslcd import NslcdClient 32 33 34epilog = ''' 35supported databases: 36 aliases, ethers, group, group.bymember, hosts, hostsv4, hostsv6, 37 netgroup, netgroup.norec, networks, networksv4, networksv6, passwd, 38 protocols, rpc, services, shadow 39 40Report bugs to <%s>. 41'''.strip() % constants.PACKAGE_BUGREPORT 42 43# set up command line parser 44parser = argparse.ArgumentParser( 45 formatter_class=argparse.RawDescriptionHelpFormatter, 46 description='Query information in %s via nslcd.' % 47 constants.MODULE_NAME.upper(), 48 epilog=epilog) 49parser.add_argument('-V', '--version', action=VersionAction) 50parser.add_argument('database', metavar='DATABASE', 51 help='any database supported by nslcd') 52parser.add_argument('keys', metavar='KEY', nargs='*', 53 help='filter returned database values by key') 54 55 56def write_aliases(con): 57 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 58 print('%-16s%s' % ( 59 con.read_string() + ': ', 60 ', '.join(con.read_stringlist()))) 61 62 63def getent_aliases(database, keys=None): 64 if not keys: 65 write_aliases(NslcdClient(constants.NSLCD_ACTION_ALIAS_ALL)) 66 return 67 for key in keys: 68 con = NslcdClient(constants.NSLCD_ACTION_ALIAS_BYNAME) 69 con.write_string(key) 70 write_aliases(con) 71 72 73def write_ethers(con): 74 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 75 name = con.read_string() 76 ether = con.read_ether() 77 print('%s %s' % (ether, name)) 78 79 80def getent_ethers(database, keys=None): 81 if not keys: 82 write_ethers(NslcdClient(constants.NSLCD_ACTION_ETHER_ALL)) 83 return 84 for key in keys: 85 if re.match('^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$', key): 86 con = NslcdClient(constants.NSLCD_ACTION_ETHER_BYETHER) 87 con.write_ether(key) 88 else: 89 con = NslcdClient(constants.NSLCD_ACTION_ETHER_BYNAME) 90 con.write_string(key) 91 write_ethers(con) 92 93 94def write_group(con): 95 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 96 print('%s:%s:%d:%s' % ( 97 con.read_string(), 98 con.read_string(), 99 con.read_int32(), 100 ','.join(con.read_stringlist()))) 101 102 103def getent_group(database, keys=None): 104 if not keys: 105 write_group(NslcdClient(constants.NSLCD_ACTION_GROUP_ALL)) 106 return 107 for key in keys: 108 if database == 'group.bymember': 109 con = NslcdClient(constants.NSLCD_ACTION_GROUP_BYMEMBER) 110 con.write_string(key) 111 elif re.match(r'^\d+$', key): 112 con = NslcdClient(constants.NSLCD_ACTION_GROUP_BYGID) 113 con.write_int32(int(key)) 114 else: 115 con = NslcdClient(constants.NSLCD_ACTION_GROUP_BYNAME) 116 con.write_string(key) 117 write_group(con) 118 119 120def _get_ipv4(value): 121 try: 122 return socket.inet_pton(socket.AF_INET, value) 123 except socket.error: 124 return None 125 126 127def _get_ipv6(value): 128 try: 129 return socket.inet_pton(socket.AF_INET6, value) 130 except socket.error: 131 return None 132 133 134def _get_af(database): 135 if database.endswith('v4'): 136 return socket.AF_INET 137 elif database.endswith('v6'): 138 return socket.AF_INET6 139 else: 140 return None 141 142 143def write_hosts(con, db_af): 144 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 145 names = ' '.join([con.read_string()] + con.read_stringlist()) 146 for af, address in con.read_addresslist(): 147 if db_af in (af, None): 148 print('%-15s %s' % (address, names)) 149 150 151def getent_hosts(database, keys=None): 152 db_af = _get_af(database) 153 if not keys: 154 write_hosts(NslcdClient(constants.NSLCD_ACTION_HOST_ALL), db_af) 155 return 156 for key in keys: 157 ipv4_addr = _get_ipv4(key) 158 ipv6_addr = _get_ipv6(key) 159 if ipv4_addr and db_af in (socket.AF_INET, None): 160 con = NslcdClient(constants.NSLCD_ACTION_HOST_BYADDR) 161 con.write_address(socket.AF_INET, ipv4_addr) 162 elif ipv6_addr and db_af in (socket.AF_INET6, None): 163 con = NslcdClient(constants.NSLCD_ACTION_HOST_BYADDR) 164 con.write_address(socket.AF_INET6, ipv6_addr) 165 else: 166 con = NslcdClient(constants.NSLCD_ACTION_HOST_BYNAME) 167 con.write_string(key) 168 write_hosts(con, db_af) 169 170 171def _read_netgroup(con): 172 """Read netgroup name, members and triples from stream.""" 173 name = con.read_string() 174 members = [] 175 tripples = [] 176 while True: 177 member_type = con.read_int32() 178 if member_type == constants.NSLCD_NETGROUP_TYPE_NETGROUP: 179 members.append(con.read_string()) 180 elif member_type == constants.NSLCD_NETGROUP_TYPE_TRIPLE: 181 tripples.append(( 182 con.read_string(), con.read_string(), con.read_string())) 183 else: 184 break 185 return name, members, tripples 186 187 188def _get_getgroups(con, recurse, netgroups=None): 189 if netgroups is None: 190 netgroups = {} 191 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 192 name, members, tripples = _read_netgroup(con) 193 if not recurse: 194 yield (name, members, tripples) 195 else: 196 netgroups[name] = None 197 for netgroup in members: 198 if netgroup not in netgroups: 199 con2 = NslcdClient(constants.NSLCD_ACTION_NETGROUP_BYNAME) 200 con2.write_string(netgroup) 201 all(_get_getgroups(con2, recurse, netgroups)) 202 if netgroups.get(netgroup, None) is not None: 203 tripples += netgroups[netgroup][1] 204 netgroups[name] = (members, tripples) 205 yield (name, [], tripples) 206 207 208def write_netgroup(con, recurse): 209 for name, members, tripples in _get_getgroups(con, recurse): 210 print('%-15s %s' % (name, ' '.join( 211 members + 212 ['(%s, %s, %s)' % (host, user, domain) 213 for host, user, domain in tripples]))) 214 215 216def getent_netgroup(database, keys=None): 217 recurse = database == 'netgroup' 218 if not keys: 219 write_netgroup( 220 NslcdClient(constants.NSLCD_ACTION_NETGROUP_ALL), recurse) 221 return 222 for key in keys: 223 con = NslcdClient(constants.NSLCD_ACTION_NETGROUP_BYNAME) 224 con.write_string(key) 225 write_netgroup(con, recurse) 226 227 228def write_networks(con, db_af): 229 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 230 names = ' '.join([con.read_string()] + con.read_stringlist()) 231 for af, address in con.read_addresslist(): 232 if db_af in (af, None): 233 print('%-22s %s' % (names, address)) 234 235 236def getent_networks(database, keys=None): 237 db_af = _get_af(database) 238 if not keys: 239 write_networks(NslcdClient(constants.NSLCD_ACTION_NETWORK_ALL), db_af) 240 return 241 for key in keys: 242 ipv4_addr = _get_ipv4(key) 243 ipv6_addr = _get_ipv6(key) 244 if ipv4_addr and db_af in (socket.AF_INET, None): 245 con = NslcdClient(constants.NSLCD_ACTION_NETWORK_BYADDR) 246 con.write_address(socket.AF_INET, ipv4_addr) 247 elif ipv6_addr and db_af in (socket.AF_INET6, None): 248 con = NslcdClient(constants.NSLCD_ACTION_NETWORK_BYADDR) 249 con.write_address(socket.AF_INET6, ipv6_addr) 250 else: 251 con = NslcdClient(constants.NSLCD_ACTION_NETWORK_BYNAME) 252 con.write_string(key) 253 write_networks(con, db_af) 254 255 256def write_passwd(con): 257 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 258 print('%s:%s:%d:%d:%s:%s:%s' % ( 259 con.read_string(), 260 con.read_string(), 261 con.read_int32(), 262 con.read_int32(), 263 con.read_string(), 264 con.read_string(), 265 con.read_string())) 266 267 268def getent_passwd(database, keys=None): 269 if not keys: 270 write_passwd(NslcdClient(constants.NSLCD_ACTION_PASSWD_ALL)) 271 return 272 for key in keys: 273 if re.match(r'^\d+$', key): 274 con = NslcdClient(constants.NSLCD_ACTION_PASSWD_BYUID) 275 con.write_int32(int(key)) 276 else: 277 con = NslcdClient(constants.NSLCD_ACTION_PASSWD_BYNAME) 278 con.write_string(key) 279 write_passwd(con) 280 281 282def write_protocols(con): 283 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 284 name = con.read_string() 285 aliases = con.read_stringlist() 286 number = con.read_int32() 287 print('%-21s %d %s' % (name, number, ' '.join(aliases))) 288 289 290def getent_protocols(database, keys=None): 291 if not keys: 292 write_protocols(NslcdClient(constants.NSLCD_ACTION_PROTOCOL_ALL)) 293 return 294 for key in keys: 295 if re.match(r'^\d+$', key): 296 con = NslcdClient(constants.NSLCD_ACTION_PROTOCOL_BYNUMBER) 297 con.write_int32(int(key)) 298 else: 299 con = NslcdClient(constants.NSLCD_ACTION_PROTOCOL_BYNAME) 300 con.write_string(key) 301 write_protocols(con) 302 303 304def write_rpc(con): 305 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 306 name = con.read_string() 307 aliases = con.read_stringlist() 308 number = con.read_int32() 309 print('%-15s %d %s' % (name, number, ' '.join(aliases))) 310 311 312def getent_rpc(database, keys=None): 313 if not keys: 314 write_rpc(NslcdClient(constants.NSLCD_ACTION_RPC_ALL)) 315 return 316 for key in keys: 317 if re.match(r'^\d+$', key): 318 con = NslcdClient(constants.NSLCD_ACTION_RPC_BYNUMBER) 319 con.write_int32(int(key)) 320 else: 321 con = NslcdClient(constants.NSLCD_ACTION_RPC_BYNAME) 322 con.write_string(key) 323 write_rpc(con) 324 325 326def write_services(con): 327 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 328 name = con.read_string() 329 aliases = con.read_stringlist() 330 number = con.read_int32() 331 protocol = con.read_string() 332 print('%-21s %d/%s %s' % (name, number, protocol, ' '.join(aliases))) 333 334 335def getent_services(database, keys=None): 336 if not keys: 337 write_services(NslcdClient(constants.NSLCD_ACTION_SERVICE_ALL)) 338 return 339 for key in keys: 340 value = key 341 protocol = '' 342 if '/' in value: 343 value, protocol = value.split('/', 1) 344 if re.match(r'^\d+$', value): 345 con = NslcdClient(constants.NSLCD_ACTION_SERVICE_BYNUMBER) 346 con.write_int32(int(value)) 347 con.write_string(protocol) 348 else: 349 con = NslcdClient(constants.NSLCD_ACTION_SERVICE_BYNAME) 350 con.write_string(value) 351 con.write_string(protocol) 352 write_services(con) 353 354 355def _shadow_value2str(number): 356 return str(number) if number != -1 else '' 357 358 359def write_shadow(con): 360 while con.get_response() == constants.NSLCD_RESULT_BEGIN: 361 print('%s:%s:%s:%s:%s:%s:%s:%s:%s' % ( 362 con.read_string(), 363 con.read_string(), 364 _shadow_value2str(con.read_int32()), 365 _shadow_value2str(con.read_int32()), 366 _shadow_value2str(con.read_int32()), 367 _shadow_value2str(con.read_int32()), 368 _shadow_value2str(con.read_int32()), 369 _shadow_value2str(con.read_int32()), 370 _shadow_value2str(con.read_int32()))) 371 372 373def getent_shadow(database, keys=None): 374 if not keys: 375 write_shadow(NslcdClient(constants.NSLCD_ACTION_SHADOW_ALL)) 376 return 377 for key in keys: 378 con = NslcdClient(constants.NSLCD_ACTION_SHADOW_BYNAME) 379 con.write_string(key) 380 write_shadow(con) 381 382 383def main(): # noqa: C901 384 args = parser.parse_args() 385 try: 386 if args.database == 'aliases': 387 getent_aliases(args.database, args.keys) 388 elif args.database == 'ethers': 389 getent_ethers(args.database, args.keys) 390 elif args.database in ('group', 'group.bymember'): 391 getent_group(args.database, args.keys) 392 elif args.database in ('hosts', 'hostsv4', 'hostsv6'): 393 getent_hosts(args.database, args.keys) 394 elif args.database in ('netgroup', 'netgroup.norec'): 395 getent_netgroup(args.database, args.keys) 396 elif args.database in ('networks', 'networksv4', 'networksv6'): 397 getent_networks(args.database, args.keys) 398 elif args.database == 'passwd': 399 getent_passwd(args.database, args.keys) 400 elif args.database == 'protocols': 401 getent_protocols(args.database, args.keys) 402 elif args.database == 'rpc': 403 getent_rpc(args.database, args.keys) 404 elif args.database == 'services': 405 getent_services(args.database, args.keys) 406 elif args.database == 'shadow': 407 getent_shadow(args.database, args.keys) 408 else: 409 parser.error('Unknown database: %s' % args.database) 410 except struct.error: 411 print('Problem communicating with nslcd') 412 sys.exit(1) 413 414 415if __name__ == '__main__': 416 main() 417