diff options
-rw-r--r-- | pynslcd/cache.py | 4 | ||||
-rw-r--r-- | pynslcd/cfg.py | 5 | ||||
-rw-r--r-- | pynslcd/group.py | 8 | ||||
-rw-r--r-- | pynslcd/nscd.py | 4 | ||||
-rwxr-xr-x | pynslcd/pynslcd.py | 32 | ||||
-rw-r--r-- | pynslcd/search.py | 2 | ||||
-rw-r--r-- | pynslcd/shadow.py | 2 | ||||
-rw-r--r-- | pynslcd/tio.py | 8 | ||||
-rw-r--r-- | pynslcd/usermod.py | 10 | ||||
-rwxr-xr-x | utils/chsh.py | 51 | ||||
-rwxr-xr-x | utils/getent.py | 68 | ||||
-rw-r--r-- | utils/nslcd.py | 12 | ||||
-rw-r--r-- | utils/users.py | 4 |
13 files changed, 104 insertions, 106 deletions
diff --git a/pynslcd/cache.py b/pynslcd/cache.py index ce706be..7089d41 100644 --- a/pynslcd/cache.py +++ b/pynslcd/cache.py @@ -1,7 +1,7 @@ # cache.py - caching layer for pynslcd # -# Copyright (C) 2012 Arthur de Jong +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -29,8 +29,6 @@ import sqlite3 # TODO: probably create a config table - - # FIXME: store the cache in the right place and make it configurable filename = '/tmp/cache.sqlite' dirname = os.path.dirname(filename) diff --git a/pynslcd/cfg.py b/pynslcd/cfg.py index baa29ec..a9f1d89 100644 --- a/pynslcd/cfg.py +++ b/pynslcd/cfg.py @@ -20,12 +20,9 @@ import logging import re -import sys import ldap -from expr import Expression - # the number of threads to start threads = 5 @@ -134,6 +131,7 @@ def _get_maps(): # separate function as not to pollute the namespace and avoid import loops import alias, ether, group, host, netgroup, network, passwd import protocol, rpc, service, shadow + import sys return dict( alias=alias, aliases=alias, ether=ether, ethers=ether, @@ -274,6 +272,7 @@ def read(filename): # pam_authz_search <FILTER> m = re.match('pam_authz_search\s+(?P<value>\S.*)', line, re.IGNORECASE) if m: + from expr import Expression pam_authz_searches.append(Expression(m.group('value'))) # TODO: check pam_authz_search expression to only contain # username, service, ruser, rhost, tty, hostname, fqdn, dn or diff --git a/pynslcd/group.py b/pynslcd/group.py index 71a1173..a72c57d 100644 --- a/pynslcd/group.py +++ b/pynslcd/group.py @@ -65,9 +65,11 @@ class Search(search.LDAPSearch): memberuid = self.parameters['memberUid'] dn = uid2dn(self.conn, memberuid) if dn: - return '(&%s(|(%s=%s)(%s=%s)))' % (self.filter, - attmap['memberUid'], escape_filter_chars(memberuid), - attmap['member'], escape_filter_chars(dn)) + return '(&%s(|(%s=%s)(%s=%s)))' % ( + self.filter, + attmap['memberUid'], escape_filter_chars(memberuid), + attmap['member'], escape_filter_chars(dn) + ) return super(Search, self).mk_filter() diff --git a/pynslcd/nscd.py b/pynslcd/nscd.py index 19e5ceb..e71bd04 100644 --- a/pynslcd/nscd.py +++ b/pynslcd/nscd.py @@ -22,7 +22,6 @@ import fcntl import logging import os import subprocess -import struct import cfg @@ -74,9 +73,8 @@ def loop(fd): os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin' while True: db = os.read(fd, 1) - # FIXME: define the characters and maps somewhere if db == '': - break + break # close process down db = _char_to_db.get(db, None) if db: exec_invalidate(db) diff --git a/pynslcd/pynslcd.py b/pynslcd/pynslcd.py index 35ecb08..99bfda8 100755 --- a/pynslcd/pynslcd.py +++ b/pynslcd/pynslcd.py @@ -73,8 +73,8 @@ class MySysLogHandler(logging.Handler): def emit(self, record): priority = self.mapping.get(record.levelno, syslog.LOG_WARNING) msg = self.format(record) - for l in msg.splitlines(): - syslog.syslog(priority, l) + for line in msg.splitlines(): + syslog.syslog(priority, line) # configure logging @@ -113,8 +113,9 @@ def parse_cmdline(): global program_name program_name = sys.argv[0] or program_name try: - optlist, args = getopt.gnu_getopt(sys.argv[1:], - 'cdhV', ('check', 'debug', 'help', 'version', )) + optlist, args = getopt.gnu_getopt( + sys.argv[1:], 'cdhV', + ('check', 'debug', 'help', 'version')) for flag, arg in optlist: if flag in ('-c', '--check'): global checkonly @@ -131,10 +132,12 @@ def parse_cmdline(): if len(args): raise getopt.GetoptError('unrecognized option \'%s\'' % args[0], args[0]) except getopt.GetoptError, reason: - sys.stderr.write("%(program_name)s: %(reason)s\n" - "Try '%(program_name)s --help' for more information.\n" - % {'program_name': program_name, - 'reason': reason, }) + sys.stderr.write( + "%(program_name)s: %(reason)s\n" + "Try '%(program_name)s --help' for more information.\n" % { + 'program_name': program_name, + 'reason': reason, + }) sys.exit(1) @@ -168,7 +171,7 @@ def getpeercred(fd): """Return uid, gid and pid of calling application.""" import struct import socket - SO_PEERCRED = 17 + SO_PEERCRED = getattr(socket, 'SO_PEERCRED', 17) creds = fd.getsockopt(socket.SOL_SOCKET, SO_PEERCRED, struct.calcsize('3i')) pid, uid, gid = struct.unpack('3i', creds) return uid, gid, pid @@ -181,12 +184,12 @@ handlers.update(common.get_handlers('group')) handlers.update(common.get_handlers('host')) handlers.update(common.get_handlers('netgroup')) handlers.update(common.get_handlers('network')) -handlers.update(common.get_handlers('pam')) handlers.update(common.get_handlers('passwd')) handlers.update(common.get_handlers('protocol')) handlers.update(common.get_handlers('rpc')) handlers.update(common.get_handlers('service')) handlers.update(common.get_handlers('shadow')) +handlers.update(common.get_handlers('pam')) handlers.update(common.get_handlers('usermod')) @@ -196,8 +199,7 @@ def acceptconnection(session): # See: http://docs.python.org/library/socket.html#socket.socket.settimeout fp = None try: - # probably use finally - # indicate new connection to logging module (genrates unique id) + # indicate new connection to logging module (generates unique id) log_newsession() # log connection try: @@ -292,9 +294,9 @@ if __name__ == '__main__': sys.exit(1) # daemonize if debugging: - daemon = pidfile + ctx = pidfile else: - daemon = daemon.DaemonContext( + ctx = daemon.DaemonContext( pidfile=pidfile, signal_map={ signal.SIGTERM: 'terminate', @@ -302,7 +304,7 @@ if __name__ == '__main__': signal.SIGPIPE: None, }) # start daemon - with daemon: + with ctx: try: # start normal logging as configured if not debugging: diff --git a/pynslcd/search.py b/pynslcd/search.py index 219929b..3db6e9d 100644 --- a/pynslcd/search.py +++ b/pynslcd/search.py @@ -25,7 +25,6 @@ import ldap import ldap.ldapobject import cfg -import nscd # global indicator that there was some error connection to an LDAP server @@ -56,6 +55,7 @@ class Connection(ldap.ldapobject.ReconnectLDAPObject): self.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_HARD) def reconnect_after_fail(self): + import nscd logging.info('connected to LDAP server %s', cfg.uri) nscd.invalidate() diff --git a/pynslcd/shadow.py b/pynslcd/shadow.py index 6f7df10..bedac50 100644 --- a/pynslcd/shadow.py +++ b/pynslcd/shadow.py @@ -95,7 +95,7 @@ class ShadowRequest(common.Request): # return results for name in names: yield (name, passwd, lastchangedate, mindays, maxdays, warndays, - inactdays, expiredate, flag) + inactdays, expiredate, flag) class ShadowByNameRequest(ShadowRequest): diff --git a/pynslcd/tio.py b/pynslcd/tio.py index 9e7f99b..02b7ec6 100644 --- a/pynslcd/tio.py +++ b/pynslcd/tio.py @@ -1,7 +1,7 @@ # tio.py - I/O functions # -# Copyright (C) 2010, 2011 Arthur de Jong +# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -51,10 +51,10 @@ class TIOStream(object): return _int32.unpack(self.read(_int32.size))[0] def read_string(self, maxsize=None): - len = self.read_int32() - if maxsize and len >= maxsize: + num = self.read_int32() + if maxsize and num >= maxsize: raise TIOStreamError() - return self.read(len) + return self.read(num) def read_address(self): """Read an address (usually IPv4 or IPv6) from the stream and return diff --git a/pynslcd/usermod.py b/pynslcd/usermod.py index c957b97..9622fb2 100644 --- a/pynslcd/usermod.py +++ b/pynslcd/usermod.py @@ -26,9 +26,7 @@ import os.path import ldap -import cache import cfg -import common import constants import pam import passwd @@ -94,10 +92,10 @@ class UserModRequest(pam.PAMRequest): mods.append((ldap.MOD_REPLACE, passwd.attmap['homeDirectory'], [homedir])) elif not os.path.isabs(homedir): self.write_result(constants.NSLCD_USERMOD_HOMEDIR, - 'should be an absolute path') + 'should be an absolute path') elif not os.path.isdir(homedir): self.write_result(constants.NSLCD_USERMOD_HOMEDIR, - 'not a directory') + 'not a directory') else: mods.append((ldap.MOD_REPLACE, passwd.attmap['homeDirectory'], [homedir])) # check login shell modification @@ -107,10 +105,10 @@ class UserModRequest(pam.PAMRequest): mods.append((ldap.MOD_REPLACE, passwd.attmap['loginShell'], [shell])) elif shell not in list_shells(): self.write_result(constants.NSLCD_USERMOD_SHELL, - 'unlisted shell') + 'unlisted shell') elif not os.path.isfile(shell) or not os.access(shell, os.X_OK): self.write_result(constants.NSLCD_USERMOD_SHELL, - 'not an executable') + 'not an executable') else: mods.append((ldap.MOD_REPLACE, passwd.attmap['loginShell'], [shell])) # get a connection and perform the modification diff --git a/utils/chsh.py b/utils/chsh.py index 30c5c12..2f81f13 100755 --- a/utils/chsh.py +++ b/utils/chsh.py @@ -31,14 +31,13 @@ import users # set up command line parser parser = argparse.ArgumentParser( - description='Change the user login shell in LDAP.', - epilog='Report bugs to <%s>.' % constants.PACKAGE_BUGREPORT - ) + description='Change the user login shell in LDAP.', + epilog='Report bugs to <%s>.' % constants.PACKAGE_BUGREPORT) parser.add_argument('-V', '--version', action=VersionAction) parser.add_argument('-s', '--shell', help='login shell for the user account') parser.add_argument('-l', '--list-shells', action=ListShellsAction) parser.add_argument('username', metavar='USER', nargs='?', - help="the user who's shell to change") + help="the user who's shell to change") def ask_shell(oldshell): @@ -47,24 +46,26 @@ def ask_shell(oldshell): return shell or oldshell -# parse arguments -args = parser.parse_args() -# check username part -user = users.User(args.username) -user.check() -# check the command line shell if one was provided (to fail early) -shell = args.shell -if shell is not None: - shells.check(shell, user.asroot) -# prompt for a password if required -password = user.get_passwd() -# prompt for a shell if it was not specified on the command line -if shell is None: - print 'Enter the new value, or press ENTER for the default' - shell = ask_shell(user.shell) - shells.check(shell, user.asroot) -# perform the modification -result = nslcd.usermod(user.username, user.asroot, password, { - constants.NSLCD_USERMOD_SHELL: shell, - }) -# TODO: print proper response +if __name__ == '__main__': + # parse arguments + args = parser.parse_args() + # check username part + user = users.User(args.username) + user.check() + # check the command line shell if one was provided (to fail early) + shell = args.shell + if shell is not None: + shells.check(shell, user.asroot) + # prompt for a password if required + password = user.get_passwd() + # prompt for a shell if it was not specified on the command line + if shell is None: + print 'Enter the new value, or press ENTER for the default' + shell = ask_shell(user.shell) + shells.check(shell, user.asroot) + # perform the modification + result = nslcd.usermod( + user.username, user.asroot, password, { + constants.NSLCD_USERMOD_SHELL: shell, + }) + # TODO: print proper response diff --git a/utils/getent.py b/utils/getent.py index 07cc670..d662272 100755 --- a/utils/getent.py +++ b/utils/getent.py @@ -33,14 +33,13 @@ from nslcd import NslcdClient # set up command line parser parser = argparse.ArgumentParser( - description='Query information in LDAP.', - epilog='Report bugs to <%s>.' % constants.PACKAGE_BUGREPORT - ) + description='Query information in LDAP.', + epilog='Report bugs to <%s>.' % constants.PACKAGE_BUGREPORT) parser.add_argument('-V', '--version', action=VersionAction) parser.add_argument('database', metavar='DATABASE', - help='any of those supported by nslcd') + help='any of those supported by nslcd') parser.add_argument('key', metavar='KEY', nargs='?', - help='information to lookup') + help='information to lookup') def getent_aliases(database, key=None): @@ -312,32 +311,33 @@ def getent_shadow(database, key=None): ) -args = parser.parse_args() -try: - if args.database == 'aliases': - getent_aliases(args.database, args.key) - elif args.database == 'ethers': - getent_ethers(args.database, args.key) - elif args.database in ('group', 'group.bymember'): - getent_group(args.database, args.key) - elif args.database in ('hosts', 'hostsv4', 'hostsv6'): - getent_hosts(args.database, args.key) - elif args.database in ('netgroup', 'netgroup.norec'): - getent_netgroup(args.database, args.key) - elif args.database in ('networks', 'networksv4', 'networksv6'): - getent_networks(args.database, args.key) - elif args.database == 'passwd': - getent_passwd(args.database, args.key) - elif args.database == 'protocols': - getent_protocols(args.database, args.key) - elif args.database == 'rpc': - getent_rpc(args.database, args.key) - elif args.database == 'services': - getent_services(args.database, args.key) - elif args.database == 'shadow': - getent_shadow(args.database, args.key) - else: - parser.error('Unknown database: %s' % args.database) -except struct.error: - print 'Problem contacting nslcd' - sys.exit(1) +if __name__ == '__main__': + args = parser.parse_args() + try: + if args.database == 'aliases': + getent_aliases(args.database, args.key) + elif args.database == 'ethers': + getent_ethers(args.database, args.key) + elif args.database in ('group', 'group.bymember'): + getent_group(args.database, args.key) + elif args.database in ('hosts', 'hostsv4', 'hostsv6'): + getent_hosts(args.database, args.key) + elif args.database in ('netgroup', 'netgroup.norec'): + getent_netgroup(args.database, args.key) + elif args.database in ('networks', 'networksv4', 'networksv6'): + getent_networks(args.database, args.key) + elif args.database == 'passwd': + getent_passwd(args.database, args.key) + elif args.database == 'protocols': + getent_protocols(args.database, args.key) + elif args.database == 'rpc': + getent_rpc(args.database, args.key) + elif args.database == 'services': + getent_services(args.database, args.key) + elif args.database == 'shadow': + getent_shadow(args.database, args.key) + else: + parser.error('Unknown database: %s' % args.database) + except struct.error: + print 'Problem contacting nslcd' + sys.exit(1) diff --git a/utils/nslcd.py b/utils/nslcd.py index 389b194..031319c 100644 --- a/utils/nslcd.py +++ b/utils/nslcd.py @@ -71,12 +71,12 @@ class NslcdClient(object): return _int32.unpack(self.read(_int32.size))[0] def read_string(self): - len = self.read_int32() - return self.read(len) + num = self.read_int32() + return self.read(num) def read_stringlist(self): - len = self.read_int32() - return [self.read_string() for x in xrange(len)] + num = self.read_int32() + return [self.read_string() for x in xrange(num)] def read_ether(self): value = self.fp.read(6) @@ -87,8 +87,8 @@ class NslcdClient(object): return af, socket.inet_ntop(af, self.read_string()) def read_addresslist(self): - len = self.read_int32() - return [self.read_address() for x in xrange(len)] + num = self.read_int32() + return [self.read_address() for x in xrange(num)] def get_response(self): # complete the request if required and check response header diff --git a/utils/users.py b/utils/users.py index 02216d6..3387318 100644 --- a/utils/users.py +++ b/utils/users.py @@ -34,8 +34,8 @@ class User(object): else: self.asroot = False userinfo = pwd.getpwuid(self.myuid) - (self.username, ignore, self.uid, self.gid, self.gecos, self.homedir, - self.shell) = userinfo + (self.username, self.password, self.uid, self.gid, self.gecos, + self.homedir, self.shell) = userinfo # if we are trying to modify another user we should be root self.asroot = self.myuid != self.uid |