nss-pam-ldapd commit: r1581 - in nss-pam-ldapd: . pynslcd
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
nss-pam-ldapd commit: r1581 - in nss-pam-ldapd: . pynslcd
- From: Commits of the nss-pam-ldapd project <nss-pam-ldapd-commits [at] lists.arthurdejong.org>
- To: nss-pam-ldapd-commits [at] lists.arthurdejong.org
- Reply-to: nss-pam-ldapd-users [at] lists.arthurdejong.org
- Subject: nss-pam-ldapd commit: r1581 - in nss-pam-ldapd: . pynslcd
- Date: Wed, 28 Dec 2011 23:52:28 +0100 (CET)
Author: arthur
Date: Wed Dec 28 23:52:26 2011
New Revision: 1581
URL: http://arthurdejong.org/viewvc/nss-pam-ldapd?revision=1581&view=revision
Log:
support for reading the configuration file (not all options are used though)
Modified:
nss-pam-ldapd/configure.ac
nss-pam-ldapd/pynslcd/cfg.py
nss-pam-ldapd/pynslcd/common.py
nss-pam-ldapd/pynslcd/config.py.in
nss-pam-ldapd/pynslcd/group.py
nss-pam-ldapd/pynslcd/pynslcd.py
Modified: nss-pam-ldapd/configure.ac
==============================================================================
--- nss-pam-ldapd/configure.ac Wed Dec 28 23:44:33 2011 (r1580)
+++ nss-pam-ldapd/configure.ac Wed Dec 28 23:52:26 2011 (r1581)
@@ -183,7 +183,6 @@
if test "x$configfile_checking" = "xyes"
then
AC_DEFINE(ENABLE_CONFIGFILE_CHECKING,1,[Whether to check configfile
options.])
- AC_SUBST(ENABLE_CONFIGFILE_CHECKING,1)
fi
# check the name of the configuration file
Modified: nss-pam-ldapd/pynslcd/cfg.py
==============================================================================
--- nss-pam-ldapd/pynslcd/cfg.py Wed Dec 28 23:44:33 2011 (r1580)
+++ nss-pam-ldapd/pynslcd/cfg.py Wed Dec 28 23:52:26 2011 (r1581)
@@ -18,6 +18,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
+import re
+import sys
+
import ldap
@@ -30,22 +33,254 @@
# the LDAP server to use
# FIXME: support multiple servers and have a fail-over mechanism
-ldap_uri = 'ldapi:///'
+uri = None
+# LDAP protocol version to use (perhaps fix at 3?)
+ldap_version = ldap.VERSION3
+# the DN to use when binding
+binddn = None
+bindpw = None
+# the DN to use to perform password modifications as root
+rootpwmoddn = None
+rootpwmodpw = None
+
+# SASL configuration
+sasl_mech = None
+sasl_realm = None
+sasl_authcid = None
+sasl_authzid = None
+sasl_secprops = None
+# LDAP bases to search
+bases = []
# default search scope for searches
scope = ldap.SCOPE_SUBTREE
-# LDAP search bases to search
-bases = ('dc=test, dc=tld', )
+deref = ldap.DEREF_NEVER
+referrals = True
-# the users for which no initgroups() searches should be done
-nss_initgroups_ignoreusers = []
+# timing configuration
+bind_timelimit = 10
+timelimit = ldap.NO_LIMIT
+idle_timelimit = 0
+reconnect_sleeptime = 1
+reconnect_retrytime = 10
-# the DN to use to perform password modifications as root
-rootpwmoddn = 'cn=admin, dc=test, dc=tld'
-rootpwmodpw = 'test'
+# SSL/TLS options
+ssl = None
+tls_reqcert = None
+tls_cacertdir = None
+tls_cacertfile = None
+tls_randfile = None
+tls_ciphers = None
+tls_cert = None
+tls_key = None
+
+
+# other options
+pagesize = 0
+nss_initgroups_ignoreusers = set()
+nss_min_uid = 0
+validnames = re.compile(r'^[a-z0-9._@$][a-z0-9._@$
\\~-]{0,98}[a-z0-9._@$~-]$', re.IGNORECASE)
+pam_authz_search = None
+
+
+# allowed boolean values
+_boolean_options = {'on': True, 'yes': True, 'true': True, '1': True,
+ 'off': False, 'no': False, 'false': False, '0': False}
+
+# allowed values for scope option
+_scope_options = dict(sub=ldap.SCOPE_SUBTREE, subtree=ldap.SCOPE_SUBTREE,
+ one=ldap.SCOPE_ONELEVEL, onelevel=ldap.SCOPE_ONELEVEL,
+ base=ldap.SCOPE_BASE)
+
+# allowed values for the deref option
+_deref_options = dict(never=ldap.DEREF_NEVER,
+ searching=ldap.DEREF_SEARCHING,
+ finding=ldap.DEREF_FINDING,
+ always=ldap.DEREF_ALWAYS)
+
+# allowed values for the ssl option
+_ssl_options = dict(start_tls='STARTTLS', starttls='STARTTLS',
+ on='LDAPS', off=None)
+
+# allowed values for the tls_reqcert option
+_tls_reqcert_options = {'never': ldap.OPT_X_TLS_NEVER,
+ 'no': ldap.OPT_X_TLS_NEVER,
+ 'allow': ldap.OPT_X_TLS_ALLOW,
+ 'try': ldap.OPT_X_TLS_TRY,
+ 'demand': ldap.OPT_X_TLS_DEMAND,
+ 'yes': ldap.OPT_X_TLS_DEMAND,
+ 'hard': ldap.OPT_X_TLS_HARD}
+
+
+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
+ return dict(alias=alias, aliases=alias,
+ ether=ether, ethers=ether,
+ group=group,
+ host=host, hosts=host,
+ netgroup=netgroup,
+ network=network, networks=network,
+ passwd=passwd,
+ protocol=protocol, protocols=protocol,
+ rpc=rpc,
+ service=service, services=service,
+ shadow=shadow,
+ none=sys.modules[__name__])
+
+
+class ParseError(Exception):
+
+ def __init__(self, filename, lineno, message):
+ self.message = '%s:%d: %s' % (filename, lineno, message)
+
+ def __repr__(self):
+ return self.message
+
+ __str__ = __repr__
-# FIXME: implement reading configuration from file
-def read(cfgfile):
- pass
+def read(filename):
+ maps = _get_maps()
+ lineno = 0
+ for line in open(filename, 'r'):
+ lineno += 1
+ line = line.strip()
+ # skip comments and blank lines
+ if re.match('(#.*)?$', line, re.IGNORECASE):
+ continue
+ # parse options with a single integer argument
+ m =
re.match('(?P<keyword>threads|ldap_version|bind_timelimit|timelimit|idle_timelimit|reconnect_sleeptime|reconnect_retrytime|pagesize|nss_min_uid)\s+(?P<value>\d+)',
+ line, re.IGNORECASE)
+ if m:
+ globals()[m.group('keyword').lower()] = int(m.group('value'))
+ continue
+ # parse options with a single boolean argument
+ m = re.match('(?P<keyword>referrals)\s+(?P<value>%s)' %
+ '|'.join(_boolean_options.keys()),
+ line, re.IGNORECASE)
+ if m:
+ globals()[m.group('keyword').lower()] =
_boolean_options[m.group('value').lower()]
+ continue
+ # parse options with a single no-space value
+ m =
re.match('(?P<keyword>uid|gid|bindpw|rootpwmodpw|sasl_mech)\s+(?P<value>\S+)',
+ line, re.IGNORECASE)
+ if m:
+ globals()[m.group('keyword').lower()] = m.group('value')
+ continue
+ # parse options with a single value that can contain spaces
+ m =
re.match('(?P<keyword>binddn|rootpwmoddn|sasl_realm|sasl_authcid|sasl_authzid|sasl_secprops|krb5_ccname|tls_cacertdir|tls_cacertfile|tls_randfile|tls_ciphers|tls_cert|tls_key)\s+(?P<value>\S.*)',
line, re.IGNORECASE)
+ if m:
+ globals()[m.group('keyword').lower()] = m.group('value')
+ continue
+ # uri <URI>
+ m = re.match('uri\s+(?P<uri>\S+)', line, re.IGNORECASE)
+ if m:
+ # FIXME: support multiple URI values
+ # FIXME: support special DNS and DNS:domain values
+ global uri
+ uri = m.group('uri')
+ continue
+ # base <MAP>? <BASEDN>
+ m = re.match('base\s+((?P<map>%s)\s+)?(?P<value>\S.*)' %
+ '|'.join(maps.keys()),
+ line, re.IGNORECASE)
+ if m:
+ mod = maps[str(m.group('map')).lower()]
+ if not hasattr(mod, 'bases'):
+ mod.bases = []
+ mod.bases.append(m.group('value'))
+ continue
+ # filter <MAP> <SEARCHFILTER>
+ m = re.match('filter\s+(?P<map>%s)\s+(?P<value>\S.*)' %
+ '|'.join(maps.keys()),
+ line, re.IGNORECASE)
+ if m:
+ mod = maps[m.group('map').lower()]
+ mod.filter = m.group('value')
+ continue
+ # scope <MAP>? <SCOPE>
+ m = re.match('scope\s+((?P<map>%s)\s+)?(?P<value>%s)' % (
+ '|'.join(maps.keys()),
+ '|'.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
+ # map <MAP> <ATTRIBUTE> <ATTMAPPING>
+ m =
re.match('map\s+(?P<map>%s)\s+(?P<attribute>\S+)\s+(?P<value>\S.*)' %
+ '|'.join(maps.keys()),
+ line, re.IGNORECASE)
+ if m:
+ mod = maps[m.group('map').lower()]
+ attribute = m.group('attribute')
+ if attribute not in mod.attmap:
+ raise ParseError(filename, lineno, 'attribute %s unknown' %
attribute)
+ mod.attmap[attribute] = m.group('value')
+ # TODO: filter out attributes that cannot be an expression
+ continue
+ # deref <DEREF>
+ m = re.match('deref\s+(?P<value>%s)' % '|'.join(_deref_options.keys()),
+ line, re.IGNORECASE)
+ if m:
+ global deref
+ deref = _deref_options[m.group('value').lower()]
+ continue
+ # nss_initgroups_ignoreusers <USER,USER>|<ALLLOCAL>
+ 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
+ # running, this should work)
+ import pwd
+ users = (x.pw_name for x in pwd.getpwall())
+ else:
+ users = users.split(',')
+ # TODO: warn about unknown users
+ nss_initgroups_ignoreusers.update(users)
+ continue
+ # pam_authz_search <FILTER>
+ m = re.match('pam_authz_search\s+(?P<value>\S.*)', line, re.IGNORECASE)
+ if m:
+ global pam_authz_search
+ from attmap import Expression
+ pam_authz_search = Expression(m.group('value'))
+ # TODO: check pam_authz_search expression to only contain
username, service, ruser, rhost, tty, hostname, fqdn, dn or uid variables
+ continue
+ # ssl <on|off|start_tls>
+ m = re.match('ssl\s+(?P<value>%s)' %
+ '|'.join(_ssl_options.keys()),
+ line, re.IGNORECASE)
+ if m:
+ global ssl
+ ssl = _ssl_options[m.group('value').lower()]
+ continue
+ # tls_reqcert <demand|hard|yes...>
+ m = re.match('tls_reqcert\s+(?P<value>%s)' %
+ '|'.join(_tls_reqcert_options.keys()),
+ line, re.IGNORECASE)
+ if m:
+ global tls_reqcert
+ tls_reqcert = _tls_reqcert_options[m.group('value').lower()]
+ continue
+ # validnames /REGEX/i?
+ m = re.match('validnames\s+/(?P<value>.*)/(?P<flags>[i]?)$',
+ line, re.IGNORECASE)
+ if m:
+ global validnames
+ flags = 0 | re.IGNORECASE if m.group('flags') == 'i' else 0
+ validnames = re.compile(m.group('value'), flags=flags)
+ continue
+ # unrecognised line
+ raise ParseError(filename, lineno, 'error parsing line %r' % line)
+ # dump config (debugging code)
+ for k, v in globals().items():
+ if not k.startswith('_'):
+ print '%s=%r' % (k, v)
Modified: nss-pam-ldapd/pynslcd/common.py
==============================================================================
--- nss-pam-ldapd/pynslcd/common.py Wed Dec 28 23:44:33 2011 (r1580)
+++ nss-pam-ldapd/pynslcd/common.py Wed Dec 28 23:52:26 2011 (r1581)
@@ -28,9 +28,6 @@
from attmap import Attributes
-_validname_re = re.compile(r'^[a-z0-9._@$][a-z0-9._@$
\\~-]{0,98}[a-z0-9._@$~-]$', re.IGNORECASE)
-
-
def isvalidname(name):
"""Checks to see if the specified name seems to be a valid user or group
name.
@@ -44,14 +41,14 @@
The standard defines user names valid if they contain characters from
the set [A-Za-z0-9._-] where the hyphen should not be used as first
character. As an extension this test allows some more characters."""
- return bool(_validname_re.match(name))
+ return bool(cfg.validnames.search(name))
def validate_name(name):
"""Checks to see if the specified name seems to be a valid user or group
name. See isvalidname()."""
- if not _validname_re.match(name):
- raise ValueError('%r: invalid user name' % name)
+ if not cfg.validnames.search(name):
+ raise ValueError('%r: denied by validnames option' % name)
class Search(object):
@@ -109,6 +106,7 @@
# get search results
filter = self.mk_filter()
for base in self.bases:
+ print 'SEARCHING %s' % base
# do the LDAP search
try:
for entry in self.conn.search_s(base, self.scope, filter,
self.attributes):
Modified: nss-pam-ldapd/pynslcd/config.py.in
==============================================================================
--- nss-pam-ldapd/pynslcd/config.py.in Wed Dec 28 23:44:33 2011 (r1580)
+++ nss-pam-ldapd/pynslcd/config.py.in Wed Dec 28 23:52:26 2011 (r1581)
@@ -42,9 +42,6 @@
# Version number of package
VERSION = '''@VERSION@'''
-# Whether to check configfile options.
-ENABLE_CONFIGFILE_CHECKING = '''@ENABLE_CONFIGFILE_CHECKING@'''
-
# Path to bindpw value.
NSLCD_BINDPW_PATH = '''@NSLCD_BINDPW_PATH@'''
Modified: nss-pam-ldapd/pynslcd/group.py
==============================================================================
--- nss-pam-ldapd/pynslcd/group.py Wed Dec 28 23:44:33 2011 (r1580)
+++ nss-pam-ldapd/pynslcd/group.py Wed Dec 28 23:52:26 2011 (r1581)
@@ -37,7 +37,7 @@
gidNumber='gidNumber',
memberUid='memberUid',
member='member')
-filter = '(|(objectClass=posixGroup)(objectClass=groupOfNames))'
+filter = '(objectClass=posixGroup)'
class Search(common.Search):
Modified: nss-pam-ldapd/pynslcd/pynslcd.py
==============================================================================
--- nss-pam-ldapd/pynslcd/pynslcd.py Wed Dec 28 23:44:33 2011 (r1580)
+++ nss-pam-ldapd/pynslcd/pynslcd.py Wed Dec 28 23:52:26 2011 (r1581)
@@ -216,7 +216,7 @@
def worker():
# create a new LDAP session
#session = myldap_create_session()
- session = ldap.initialize(cfg.ldap_uri)
+ session = ldap.initialize(cfg.uri)
# start waiting for incoming connections
while True:
# wait for a new connection
@@ -242,6 +242,7 @@
# sys.exit(1)
# read configuration file
cfg.read(config.NSLCD_CONF_PATH)
+ # FIXME: set tls_cacertdir, tls_cacertfile, tls_randfile, tls_ciphers,
tls_cert, tls_key options immediately after parsing config
# set a default umask for the pidfile and socket
os.umask(0022)
# see if someone already locked the pidfile
@@ -266,7 +267,7 @@
pidfile=pidfile,
signal_map={
signal.SIGTERM: 'terminate',
- signal.SIGINT: 'terminate',
+ signal.SIGINT: 'terminate',
signal.SIGPIPE: None,
})
# start daemon
--
To unsubscribe send an email to
nss-pam-ldapd-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/nss-pam-ldapd-commits/
- nss-pam-ldapd commit: r1581 - in nss-pam-ldapd: . pynslcd,
Commits of the nss-pam-ldapd project