Blame pynslcd/common.py

Packit 6bd9ab
Packit 6bd9ab
# common.py - functions that are used by different modules
Packit 6bd9ab
#
Packit 6bd9ab
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
Packit 6bd9ab
#
Packit 6bd9ab
# This library is free software; you can redistribute it and/or
Packit 6bd9ab
# modify it under the terms of the GNU Lesser General Public
Packit 6bd9ab
# License as published by the Free Software Foundation; either
Packit 6bd9ab
# version 2.1 of the License, or (at your option) any later version.
Packit 6bd9ab
#
Packit 6bd9ab
# This library is distributed in the hope that it will be useful,
Packit 6bd9ab
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6bd9ab
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6bd9ab
# Lesser General Public License for more details.
Packit 6bd9ab
#
Packit 6bd9ab
# You should have received a copy of the GNU Lesser General Public
Packit 6bd9ab
# License along with this library; if not, write to the Free Software
Packit 6bd9ab
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6bd9ab
# 02110-1301 USA
Packit 6bd9ab
Packit 6bd9ab
import logging
Packit 6bd9ab
import sys
Packit 6bd9ab
Packit 6bd9ab
import ldap
Packit 6bd9ab
Packit 6bd9ab
from attmap import Attributes
Packit 6bd9ab
#import cache
Packit 6bd9ab
import cfg
Packit 6bd9ab
import constants
Packit 6bd9ab
Packit 6bd9ab
Packit 6bd9ab
def is_valid_name(name):
Packit 6bd9ab
    """Checks to see if the specified name seems to be a valid user or group
Packit 6bd9ab
    name.
Packit 6bd9ab
Packit 6bd9ab
    This test is based on the definition from POSIX (IEEE Std 1003.1, 2004,
Packit 6bd9ab
    3.426 User Name, 3.189 Group Name and 3.276 Portable Filename Character Set):
Packit 6bd9ab
    http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_426
Packit 6bd9ab
    http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_189
Packit 6bd9ab
    http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
Packit 6bd9ab
Packit 6bd9ab
    The standard defines user names valid if they contain characters from
Packit 6bd9ab
    the set [A-Za-z0-9._-] where the hyphen should not be used as first
Packit 6bd9ab
    character. As an extension this test allows some more characters."""
Packit 6bd9ab
    return bool(cfg.validnames.search(name))
Packit 6bd9ab
Packit 6bd9ab
Packit 6bd9ab
def validate_name(name):
Packit 6bd9ab
    """Checks to see if the specified name seems to be a valid user or group
Packit 6bd9ab
    name. See is_valid_name()."""
Packit 6bd9ab
    if not cfg.validnames.search(name):
Packit 6bd9ab
        raise ValueError('%r: denied by validnames option' % name)
Packit 6bd9ab
Packit 6bd9ab
Packit 6bd9ab
class Request(object):
Packit 6bd9ab
    """
Packit 6bd9ab
    Request handler class. Subclasses are expected to handle actual requests
Packit 6bd9ab
    and should implement the following members:
Packit 6bd9ab
Packit 6bd9ab
      action - the NSLCD_ACTION_* action that should trigger this handler
Packit 6bd9ab
Packit 6bd9ab
      read_parameters() - a function that reads the request parameters of the
Packit 6bd9ab
                          request stream
Packit 6bd9ab
      write() - function that writes a single LDAP entry to the result stream
Packit 6bd9ab
Packit 6bd9ab
    """
Packit 6bd9ab
Packit 6bd9ab
    def __init__(self, fp, conn, calleruid):
Packit 6bd9ab
        self.fp = fp
Packit 6bd9ab
        self.conn = conn
Packit 6bd9ab
        self.calleruid = calleruid
Packit 6bd9ab
        module = sys.modules[self.__module__]
Packit 6bd9ab
        self.search = getattr(module, 'Search', None)
Packit 6bd9ab
        #if not hasattr(module, 'cache_obj'):
Packit 6bd9ab
        #    cache_cls = getattr(module, 'Cache', None)
Packit 6bd9ab
        #    module.cache_obj = cache_cls() if cache_cls else None
Packit 6bd9ab
        #self.cache = module.cache_obj
Packit 6bd9ab
        self.cache = None
Packit 6bd9ab
Packit 6bd9ab
    def read_parameters(self, fp):
Packit 6bd9ab
        """This method should read and return the parameters from the
Packit 6bd9ab
        stream."""
Packit 6bd9ab
        pass
Packit 6bd9ab
Packit 6bd9ab
    def get_results(self, parameters):
Packit 6bd9ab
        """Provide the result entries by performing a search."""
Packit 6bd9ab
        for dn, attributes in self.search(self.conn, parameters=parameters):
Packit 6bd9ab
            for values in self.convert(dn, attributes, parameters):
Packit 6bd9ab
                yield values
Packit 6bd9ab
Packit 6bd9ab
    def handle_request(self, parameters):
Packit 6bd9ab
        """This method handles the request based on the parameters read
Packit 6bd9ab
        with read_parameters()."""
Packit 6bd9ab
        try:
Packit 6bd9ab
            #with cache.con:
Packit 6bd9ab
            if True:
Packit 6bd9ab
                for values in self.get_results(parameters):
Packit 6bd9ab
                    self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
Packit 6bd9ab
                    self.write(*values)
Packit 6bd9ab
                    if self.cache:
Packit 6bd9ab
                        self.cache.store(*values)
Packit 6bd9ab
        except ldap.SERVER_DOWN:
Packit 6bd9ab
            if self.cache:
Packit 6bd9ab
                logging.debug('read from cache')
Packit 6bd9ab
                # we assume server went down before writing any entries
Packit 6bd9ab
                for values in self.cache.retrieve(parameters):
Packit 6bd9ab
                    self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
Packit 6bd9ab
                    self.write(*values)
Packit 6bd9ab
            else:
Packit 6bd9ab
                raise
Packit 6bd9ab
        # write the final result code
Packit 6bd9ab
        self.fp.write_int32(constants.NSLCD_RESULT_END)
Packit 6bd9ab
Packit 6bd9ab
    def log(self, parameters):
Packit 6bd9ab
        parameters = dict(parameters)
Packit 6bd9ab
        for param in ('password', 'oldpassword', 'newpassword'):
Packit 6bd9ab
            if parameters.get(param):
Packit 6bd9ab
                parameters[param] = '***'
Packit 6bd9ab
        logging.debug('%s(%r)', self.__class__.__name__, parameters)
Packit 6bd9ab
Packit 6bd9ab
    def __call__(self):
Packit 6bd9ab
        parameters = self.read_parameters(self.fp) or {}
Packit 6bd9ab
        self.log(parameters)
Packit 6bd9ab
        self.fp.write_int32(constants.NSLCD_VERSION)
Packit 6bd9ab
        self.fp.write_int32(self.action)
Packit 6bd9ab
        self.handle_request(parameters)
Packit 6bd9ab
Packit 6bd9ab
Packit 6bd9ab
def get_handlers(module):
Packit 6bd9ab
    """Return a dictionary mapping actions to Request classes."""
Packit 6bd9ab
    import inspect
Packit 6bd9ab
    res = {}
Packit 6bd9ab
    if isinstance(module, basestring):
Packit 6bd9ab
        module = __import__(module, globals())
Packit 6bd9ab
    for name, cls in inspect.getmembers(module, inspect.isclass):
Packit 6bd9ab
        if issubclass(cls, Request) and hasattr(cls, 'action'):
Packit 6bd9ab
            res[cls.action] = cls
Packit 6bd9ab
    return res