Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2012-01-06 14:59:50 +0100
committerArthur de Jong <arthur@arthurdejong.org>2012-01-06 14:59:50 +0100
commite5f552c0fb274c1a02fce51267c563a06c55d334 (patch)
tree6ac770ff8eace971fd81d1eec7d02c953292afbc
parentfea96fdbbc3e01a60fcb0d7e5ec7907987f72345 (diff)
user the logging framework, handle exceptions properly and some cleanups
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-pam-ldapd@1588 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r--pynslcd/alias.py6
-rw-r--r--pynslcd/cfg.py7
-rw-r--r--pynslcd/common.py26
-rw-r--r--pynslcd/ether.py4
-rw-r--r--pynslcd/group.py13
-rw-r--r--pynslcd/host.py6
-rw-r--r--pynslcd/mypidfile.py4
-rw-r--r--pynslcd/netgroup.py6
-rw-r--r--pynslcd/network.py6
-rw-r--r--pynslcd/pam.py11
-rw-r--r--pynslcd/passwd.py9
-rw-r--r--pynslcd/protocol.py6
-rwxr-xr-xpynslcd/pynslcd.py143
-rw-r--r--pynslcd/rpc.py4
14 files changed, 130 insertions, 121 deletions
diff --git a/pynslcd/alias.py b/pynslcd/alias.py
index a19382e..84dbf97 100644
--- a/pynslcd/alias.py
+++ b/pynslcd/alias.py
@@ -1,7 +1,7 @@
# alias.py - lookup functions for aliasnet addresses
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -18,10 +18,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import logging
-
-import constants
import common
+import constants
attmap = common.Attributes(cn='cn', rfc822MailMember='rfc822MailMember')
diff --git a/pynslcd/cfg.py b/pynslcd/cfg.py
index 42aa2fd..9386716 100644
--- a/pynslcd/cfg.py
+++ b/pynslcd/cfg.py
@@ -1,7 +1,7 @@
# cfg.py - module for accessing configuration information
#
-# Copyright (C) 2010 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
+import logging
import re
import sys
@@ -207,7 +208,6 @@ def read(filename):
'|'.join(_scope_options.keys())),
line, re.IGNORECASE)
if m:
- keyword = m.group('keyword').lower()
mod = maps[str(m.group('map')).lower()]
mod.scope = _scope_options[m.group('keyword').lower()]
continue
@@ -234,7 +234,6 @@ def read(filename):
m = re.match('nss_initgroups_ignoreusers\s+(?P<value>\S.*)',
line, re.IGNORECASE)
if m:
- global nss_initgroups_ignoreusers
users = m.group('value')
if users.lower() == 'alllocal':
# get all users known to the system currently (since nslcd isn't yet
@@ -283,4 +282,4 @@ def read(filename):
# dump config (debugging code)
for k, v in globals().items():
if not k.startswith('_'):
- print '%s=%r' % (k, v)
+ logging.debug('%s=%r', k, v)
diff --git a/pynslcd/common.py b/pynslcd/common.py
index ed5bb4e..375afed 100644
--- a/pynslcd/common.py
+++ b/pynslcd/common.py
@@ -1,7 +1,7 @@
# common.py - functions that are used by different modules
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -18,14 +18,15 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import re
+import logging
+import sys
+
import ldap
import ldap.dn
-import sys
+from attmap import Attributes
import cfg
import constants
-from attmap import Attributes
def isvalidname(name):
@@ -106,7 +107,7 @@ class Search(object):
# get search results
filter = self.mk_filter()
for base in self.bases:
- print 'SEARCHING %s' % base
+ logging.debug('SEARCHING %s', base)
# do the LDAP search
try:
for entry in self.conn.search_s(base, self.scope, filter, self.attributes):
@@ -118,12 +119,15 @@ class Search(object):
# FIXME: log message
pass
+ def escape(self, value):
+ """Escape the provided value so it may be used in a search filter."""
+ return ldap.filter.escape_filter_chars(str(value))
+
def mk_filter(self):
"""Return the active search filter (based on the read parameters)."""
if self.parameters:
return '(&%s(%s))' % (self.filter,
- ')('.join('%s=%s' % (self.attmap[attribute],
- ldap.filter.escape_filter_chars(str(value)))
+ ')('.join('%s=%s' % (self.attmap[attribute], self.escape(value))
for attribute, value in self.parameters.items()))
return self.filter
@@ -143,21 +147,19 @@ class Search(object):
# check that these attributes have at least one value
for attr in self.required:
if not attributes.get(attr, None):
- print '%s: %s: missing' % (dn, self.attmap[attr])
+ logging.warning('%s: %s: missing', dn, self.attmap[attr])
return
# check that requested attribute is present (case sensitive)
for attr in self.case_sensitive:
value = self.parameters.get(attr, None)
if value and str(value) not in attributes[attr]:
- # TODO: log at debug level, this can happen in normal cases
- print '%s: %s: does not contain %r value' % (dn, self.attmap[attr], value)
+ logging.debug('%s: %s: does not contain %r value', dn, self.attmap[attr], value)
return # not found, skip entry
# check that requested attribute is present (case insensitive)
for attr in self.case_insensitive:
value = self.parameters.get(attr, None)
if value and str(value).lower() not in (x.lower() for x in attributes[attr]):
- # TODO: log at debug level, this can happen in normal cases
- print '%s: %s: does not contain %r value' % (dn, self.attmap[attr], value)
+ logging.debug('%s: %s: does not contain %r value', dn, self.attmap[attr], value)
return # not found, skip entry
# limit attribute values to requested value
for attr in self.limit_attributes:
diff --git a/pynslcd/ether.py b/pynslcd/ether.py
index 42fa77e..4d6ae03 100644
--- a/pynslcd/ether.py
+++ b/pynslcd/ether.py
@@ -1,7 +1,7 @@
# ether.py - lookup functions for ethernet addresses
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -20,8 +20,8 @@
import struct
-import constants
import common
+import constants
def ether_aton(ether):
diff --git a/pynslcd/group.py b/pynslcd/group.py
index 0e4e96f..29a6fda 100644
--- a/pynslcd/group.py
+++ b/pynslcd/group.py
@@ -1,7 +1,7 @@
# group.py - group entry lookup routines
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -19,11 +19,10 @@
# 02110-1301 USA
import logging
-import ldap.filter
-import constants
-import common
from passwd import dn2uid, uid2dn
+import common
+import constants
def clean(lst):
@@ -60,8 +59,8 @@ class Search(common.Search):
dn = uid2dn(self.conn, memberuid)
if dn:
return '(&%s(|(%s=%s)(%s=%s)))' % (self.filter,
- attmap['memberUid'], ldap.filter.escape_filter_chars(memberuid),
- attmap['member'], ldap.filter.escape_filter_chars(dn))
+ attmap['memberUid'], self.escape(memberuid),
+ attmap['member'], self.escape(dn))
return super(Search, self).mk_filter()
@@ -91,7 +90,7 @@ class GroupRequest(common.Request):
# actually return the results
for name in names:
if not common.isvalidname(name):
- print '%s: %s: denied by validnames option' % (dn, attmap['cn'])
+ logging.warning('%s: %s: denied by validnames option', dn, attmap['cn'])
else:
for gid in gids:
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
diff --git a/pynslcd/host.py b/pynslcd/host.py
index e81d8dc..fa15b58 100644
--- a/pynslcd/host.py
+++ b/pynslcd/host.py
@@ -1,7 +1,7 @@
# host.py - lookup functions for host names and addresses
#
-# Copyright (C) 2011 Arthur de Jong
+# Copyright (C) 2011, 2012 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
@@ -18,10 +18,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import logging
-
-import constants
import common
+import constants
attmap = common.Attributes(cn='cn', ipHostNumber='ipHostNumber')
diff --git a/pynslcd/mypidfile.py b/pynslcd/mypidfile.py
index e179e16..e386f3e 100644
--- a/pynslcd/mypidfile.py
+++ b/pynslcd/mypidfile.py
@@ -1,7 +1,7 @@
# mypidfile.py - functions for properly locking a PIDFile
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -18,8 +18,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import fcntl
import errno
+import fcntl
import os
diff --git a/pynslcd/netgroup.py b/pynslcd/netgroup.py
index 7deba01..9ddba7a 100644
--- a/pynslcd/netgroup.py
+++ b/pynslcd/netgroup.py
@@ -1,7 +1,7 @@
# netgroup.py - lookup functions for netgroups
#
-# Copyright (C) 2011 Arthur de Jong
+# Copyright (C) 2011, 2012 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
@@ -21,8 +21,8 @@
import logging
import re
-import constants
import common
+import constants
_netgroup_triple_re = re.compile(r'^\s*\(\s*(?P<host>.*)\s*,\s*(?P<user>.*)\s*,\s*(?P<domain>.*)\s*\)\s*$')
@@ -47,7 +47,7 @@ class NetgroupRequest(common.Request):
for triple in attributes['nisNetgroupTriple']:
m = _netgroup_triple_re.match(triple)
if not m:
- print '%s: %s: invalid value: %r' % (dn, attmap['nisNetgroupTriple'], triple)
+ logging.warning('%s: %s: invalid value: %r', dn, attmap['nisNetgroupTriple'], triple)
else:
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
self.fp.write_int32(constants.NSLCD_NETGROUP_TYPE_TRIPLE)
diff --git a/pynslcd/network.py b/pynslcd/network.py
index 2887a61..d0778c0 100644
--- a/pynslcd/network.py
+++ b/pynslcd/network.py
@@ -1,7 +1,7 @@
# network.py - lookup functions for network names and addresses
#
-# Copyright (C) 2011 Arthur de Jong
+# Copyright (C) 2011, 2012 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
@@ -18,10 +18,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import logging
-
-import constants
import common
+import constants
attmap = common.Attributes(cn='cn',
diff --git a/pynslcd/pam.py b/pynslcd/pam.py
index 8bbbe48..8e4f76f 100644
--- a/pynslcd/pam.py
+++ b/pynslcd/pam.py
@@ -1,7 +1,7 @@
# pam.py - functions authentication, authorisation and session handling
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -19,17 +19,18 @@
# 02110-1301 USA
import logging
+
import ldap
-import constants
-import common
import cfg
+import common
+import constants
import passwd
def try_bind(userdn, password):
# open a new connection
- conn = ldap.initialize(cfg.ldap_uri)
+ conn = ldap.initialize(cfg.uri)
# bind using the specified credentials
conn.simple_bind_s(userdn, password)
# perform search for own object (just to do any kind of search)
@@ -60,7 +61,7 @@ class PAMRequest(common.Request):
# get the username from the uid attribute
values = myldap_get_values(entry, passwd.attmap['uid'])
if not values or not values[0]:
- logging.warn('%s: is missing a %s attribute', dn, passwd.attmap['uid'])
+ logging.warning('%s: is missing a %s attribute', dn, passwd.attmap['uid'])
value = values[0]
# check the username
if value and not common.isvalidname(value):
diff --git a/pynslcd/passwd.py b/pynslcd/passwd.py
index fff752e..6dce2ce 100644
--- a/pynslcd/passwd.py
+++ b/pynslcd/passwd.py
@@ -1,7 +1,7 @@
# passwd.py - lookup functions for user account information
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -18,11 +18,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import ldap
-import ldap.filter
+import logging
-import constants
import common
+import constants
attmap = common.Attributes(uid='uid',
@@ -61,7 +60,7 @@ class PasswdRequest(common.Request):
# write results
for name in names:
if not common.isvalidname(name):
- print '%s: %s: denied by validnames option' % (dn, attmap['uid'])
+ logging.warning('%s: %s: denied by validnames option', dn, attmap['uid'])
else:
for uid in uids:
self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
diff --git a/pynslcd/protocol.py b/pynslcd/protocol.py
index 0f358cb..3c91a7e 100644
--- a/pynslcd/protocol.py
+++ b/pynslcd/protocol.py
@@ -1,7 +1,7 @@
# protocol.py - protocol name and number lookup routines
#
-# Copyright (C) 2011 Arthur de Jong
+# Copyright (C) 2011, 2012 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
@@ -18,10 +18,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import logging
-
-import constants
import common
+import constants
attmap = common.Attributes(cn='cn', ipProtocolNumber='ipProtocolNumber')
diff --git a/pynslcd/pynslcd.py b/pynslcd/pynslcd.py
index 64e4a80..1c75cbb 100755
--- a/pynslcd/pynslcd.py
+++ b/pynslcd/pynslcd.py
@@ -2,7 +2,7 @@
# pynslcd.py - main daemon module
#
-# Copyright (C) 2010, 2011 Arthur de Jong
+# Copyright (C) 2010, 2011, 2012 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
@@ -19,22 +19,23 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import os
-import sys
import daemon
-import mypidfile
-import threading
import logging
import logging.handlers
+import os
import signal
+import sys
+import syslog
+import threading
+
import ldap
-import constants # from nslcd.h
-import config # from configure
+from tio import TIOStream
import cfg # from nslcd.conf
import common
-
-from tio import TIOStream
+import config # from configure
+import constants # from nslcd.h
+import mypidfile
# the name of the program
@@ -47,36 +48,51 @@ debugging = 0
checkonly = False
-# configure logging
class MyFormatter(logging.Formatter):
+
def format(self, record):
- msg = logging.Formatter.format(self, record)
+ msg = super(MyFormatter, self).format(record)
if record.levelno == logging.DEBUG:
msg = 'DEBUG: %s' % msg
return msg
-#logging.basicConfig(level=logging.INFO)
-# , format='%(message)s'
+
+
+class MySysLogHandler(logging.Handler):
+
+ mapping = {
+ logging.DEBUG: syslog.LOG_DEBUG,
+ logging.INFO: syslog.LOG_INFO,
+ logging.WARNING: syslog.LOG_WARNING,
+ logging.ERROR: syslog.LOG_ERR,
+ logging.CRITICAL: syslog.LOG_CRIT,
+ }
+
+ def __init__(self):
+ super(MySysLogHandler, self).__init__()
+ syslog.openlog(program_name, syslog.LOG_PID, syslog.LOG_DAEMON)
+
+ 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)
+
+
+# configure logging
formatter = MyFormatter('%(message)s')
stderrhandler = logging.StreamHandler(sys.stderr)
stderrhandler.setFormatter(formatter)
-##sysloghandler = logging.handlers.SysLogHandler(address='/dev/log')
-##sysloghandler.setFormatter(formatter)
-#logging.getLogger().setFormatter(MyFormatter())
+sysloghandler = MySysLogHandler()
+sysloghandler.setFormatter(formatter)
logging.getLogger().addHandler(stderrhandler)
-
-#logger = logging.getLogger()
-#logger.setLevel(logging.INFO)
-#syslog = logging.handlers.SysLogHandler(address='/dev/log')
-#formatter = logging.Formatter('%(name)s: %(levelname)s %(message)s')
-#syslog.setFormatter(formatter)
-#logger.addHandler(syslog)
+logging.getLogger().setLevel(logging.INFO)
def display_version(fp):
fp.write('%(PACKAGE_STRING)s\n'
'Written by Arthur de Jong.\n'
'\n'
- 'Copyright (C) 2010, 2011 Arthur de Jong\n'
+ 'Copyright (C) 2010-2012 Arthur de Jong\n'
'This is free software; see the source for copying conditions. There is NO\n'
'warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n'
% {'PACKAGE_STRING': config.PACKAGE_STRING, })
@@ -198,7 +214,7 @@ def acceptconnection(session):
try:
handler = handlers[action]
except KeyError:
- logging.warn('invalid action id: %r', action)
+ logging.warning('invalid action id: %r', action)
return
handler(fp, session, uid)()
finally:
@@ -214,14 +230,13 @@ def disable_nss_ldap():
def worker():
- # create a new LDAP session
- #session = myldap_create_session()
session = ldap.initialize(cfg.uri)
- # start waiting for incoming connections
while True:
- # wait for a new connection
- acceptconnection(session)
- # FIXME: handle exceptions
+ try:
+ acceptconnection(session)
+ except:
+ logging.exception('exception in worker')
+ # ignore all exceptions, just keep going
if __name__ == '__main__':
@@ -237,7 +252,7 @@ if __name__ == '__main__':
# set log level
if debugging:
logging.getLogger().setLevel(logging.DEBUG)
- # FIXME: implement
+ # TODO: implement
#if myldap_set_debuglevel(cfg.debug) != LDAP_SUCCESS:
# sys.exit(1)
# read configuration file
@@ -272,36 +287,40 @@ if __name__ == '__main__':
})
# start daemon
with daemon:
- # start normal logging
+ # start normal logging to syslog
if not debugging:
- log_startlogging()
+ logging.getLogger().addHandler(sysloghandler)
logging.info('version %s starting', config.VERSION)
- # create socket
- nslcd_serversocket = create_socket()
- # drop all supplemental groups
try:
- os.setgroups(())
- except OSError, e:
- logging.warn('cannot setgroups(()) (ignored): %s', e)
- # change to nslcd gid
- if cfg.gid is not None:
- import grp
- os.setgid(grp.getgrnam(cfg.gid).gr_gid)
- # change to nslcd uid
- if cfg.uid is not None:
- import pwd
- u = pwd.getpwnam(cfg.uid)
- os.setuid(u.pw_uid)
- os.environ['HOME'] = u.pw_dir
- logging.info('accepting connections')
- # start worker threads
- threads = []
- for i in range(cfg.threads):
- thread = threading.Thread(target=worker, name='thread%d' % i)
- thread.setDaemon(True)
- thread.start()
- logging.debug('started thread %s', thread.getName())
- threads.append(thread)
- # wait for all threads to die
- for thread in threads:
- thread.join(10000)
+ # create socket
+ nslcd_serversocket = create_socket()
+ # drop all supplemental groups
+ try:
+ os.setgroups(())
+ except OSError, e:
+ logging.warning('cannot setgroups(()) (ignored): %s', e)
+ # change to nslcd gid
+ if cfg.gid is not None:
+ import grp
+ os.setgid(grp.getgrnam(cfg.gid).gr_gid)
+ # change to nslcd uid
+ if cfg.uid is not None:
+ import pwd
+ u = pwd.getpwnam(cfg.uid)
+ os.setuid(u.pw_uid)
+ os.environ['HOME'] = u.pw_dir
+ logging.info('accepting connections')
+ # start worker threads
+ threads = []
+ for i in range(cfg.threads):
+ thread = threading.Thread(target=worker, name='thread%d' % i)
+ thread.setDaemon(True)
+ thread.start()
+ logging.debug('started thread %s', thread.getName())
+ threads.append(thread)
+ # wait for all threads to die
+ for thread in threads:
+ thread.join(10000)
+ except:
+ logging.exception('main loop exit')
+ # no need to re-raise since we are exiting anyway
diff --git a/pynslcd/rpc.py b/pynslcd/rpc.py
index 2c7aa85..5676b27 100644
--- a/pynslcd/rpc.py
+++ b/pynslcd/rpc.py
@@ -1,7 +1,7 @@
# rpc.py - rpc name lookup routines
#
-# Copyright (C) 2011 Arthur de Jong
+# Copyright (C) 2011, 2012 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
@@ -18,8 +18,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-import logging
-
import constants
import common