From 6fa0545d440ec2d0f66354eefc38286cbf3047c7 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Mon, 20 Mar 2017 11:22:27 +0100 Subject: [PATCH] Adding and using pp_lib/mk_home_app.py --- etc/mk-home.ini.default | 4 + mk-home | 4 +- pp_lib/ldap_app.py | 44 +++------ pp_lib/mk_home_app.py | 211 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 230 insertions(+), 33 deletions(-) create mode 100644 pp_lib/mk_home_app.py diff --git a/etc/mk-home.ini.default b/etc/mk-home.ini.default index 214abeb..e87570a 100644 --- a/etc/mk-home.ini.default +++ b/etc/mk-home.ini.default @@ -9,4 +9,8 @@ bind_dn = cn=admin #bind_pw = +[mk-home] +initial_uid = 999999999 +chroot_homedir = '/mnt/nfs/home' + # vim: filetype=dosini diff --git a/mk-home b/mk-home index fe02a25..dec4def 100755 --- a/mk-home +++ b/mk-home @@ -17,7 +17,7 @@ if os.path.exists(os.path.join(cur_dir, 'pp_lib')): from pp_lib.common import pp -from pp_lib.ldap_app import PpLdapApplication +from pp_lib.mk_home_app import PpMkHomeApp log = logging.getLogger(__name__) @@ -28,7 +28,7 @@ appname = os.path.basename(sys.argv[0]) locale.setlocale(locale.LC_ALL, '') -app = PpLdapApplication(appname=appname, cfg_stems='mk-home') +app = PpMkHomeApp(appname=appname) app.initialized = True if app.verbose > 2: diff --git a/pp_lib/ldap_app.py b/pp_lib/ldap_app.py index e14aac1..22d2df2 100644 --- a/pp_lib/ldap_app.py +++ b/pp_lib/ldap_app.py @@ -36,7 +36,7 @@ from .merge import merge_structure from .cfg_app import PpCfgAppError, PpConfigApplication -__version__ = '0.3.2' +__version__ = '0.3.4' LOG = logging.getLogger(__name__) @@ -51,7 +51,7 @@ class PpLdapAppError(PpCfgAppError): # ============================================================================= class PpLdapApplication(PpConfigApplication): """ - Class for configured application objects. + Class for a LDAP based configured application objects. """ default_ldap_hosts = [ @@ -118,11 +118,8 @@ class PpLdapApplication(PpConfigApplication): cfg_encoding=cfg_encoding, need_config_file=need_config_file, ) - pass - # ------------------------------------------------------------------------- def perform_config(self): - """ Execute some actions after reading the configuration. @@ -131,11 +128,15 @@ class PpLdapApplication(PpConfigApplication): """ got_host = False - for section in self.cfg.keys(): + for section_name in self.cfg.keys(): - if not section.lower() == 'ldap': + if not section_name.lower() == 'ldap': continue - ldap_section = self.cfg[section] + ldap_section = self.cfg[section_name] + if self.verbose > 2: + LOG.debug("Evaluating config section {n!r}:\n{s}".format( + n=section_name, s=pp(ldap_section))) + if 'host' in ldap_section: hosts = self.fs_re.split(ldap_section['host']) @@ -155,11 +156,11 @@ class PpLdapApplication(PpConfigApplication): port = int(ldap_section['port']) except (ValueError, TypeError) as e: msg = "Invalid LDAP port ({s}/port => {v!r}) found in configuration.".format( - s=section, v=ldap_section['port']) + s=section_name, v=ldap_section['port']) raise PpLdapAppError(msg) if port <= 0 or port >= 2 ** 16: msg = "Invalid LDAP port ({s}/port => {v!r}) found in configuration.".format( - s=section, v=port) + s=section_name, v=port) raise PpLdapAppError(msg) self.ldap_port = port @@ -180,7 +181,7 @@ class PpLdapApplication(PpConfigApplication): timeout = int(ldap_section['timeout']) except (ValueError, TypeError) as e: msg = "Invalid LDAP timeout ({s}/port => {v!r}) found in configuration.".format( - s=section, v=ldap_section['timeout']) + s=section_name, v=ldap_section['timeout']) LOG.error(msg) if timeout > 0: self.ldap_timeout = timeout @@ -236,26 +237,7 @@ class PpLdapApplication(PpConfigApplication): MUST be overwritten by descendant classes. """ - - LOG.debug("Executing something ...") - - query_filter = ( - '(&' - '(objectclass=posixAccount)' - '(objectclass=shadowAccount)' - '(uid=frank.brehm)' - ')' - ) - - entries = self.ldap_search(query_filter) - - print("Found {} LDAP entries.".format(len(entries))) - i = 0 - for entry in entries: - i += 1 - print("\n{}".format(entry)) - if i >= 5: - break + LOG.debug("Executing nothing ...") # ------------------------------------------------------------------------- def ldap_search( diff --git a/pp_lib/mk_home_app.py b/pp_lib/mk_home_app.py new file mode 100644 index 0000000..f24a6cf --- /dev/null +++ b/pp_lib/mk_home_app.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@author: Frank Brehm +@contact: frank.brehm@pixelpark.com +@copyright: © 2017 by Frank Brehm, Berlin +@summary: The module for the mk-home application object. +""" +from __future__ import absolute_import + +# Standard modules +import sys +import os +import logging +import logging.config +import re +import traceback +import textwrap +import copy + +# Third party modules +import six + +import ldap3 + +# Own modules +from .global_version import __version__ as __global_version__ + +from .errors import FunctionNotImplementedError, PpAppError + +from .common import pp, terminal_can_colors, to_bytes, to_bool + +from .merge import merge_structure + +from .ldap_app import PpLdapAppError, PpLdapApplication + +__version__ = '0.1.2' +LOG = logging.getLogger(__name__) + + +# ============================================================================= +class PpMkHomeError(PpLdapAppError): + pass + + +# ============================================================================= +class PpMkHomeApp(PpLdapApplication): + """Class for the 'mk-home' application to ensure: + * existence of HOME directories for all users in LDAP + * all LDAP users having a valid numeric UID (different to 999999999) + """ + + default_initial_uid = 999999999 + default_chroot_homedir = os.sep + os.path.join('mnt', 'nfs', 'home') + + # ------------------------------------------------------------------------- + def __init__(self, appname=None, version=__version__): + + self.initial_uid = self.default_initial_uid + self.chroot_homedir = self.default_chroot_homedir + self.simulate = False + + description = textwrap.dedent('''\ + Home Directory and UIDNumber generation - this script will search for + Unix Accounts in LDAP and generate the HomeDirectory for Users if it + dosen't exists. Also it looks for accounts with the special + UIDNumber {} and generate an new for them. + ''').strip().format(self.default_initial_uid) + + super(PpMkHomeApp, self).__init__( + appname=appname, version=version, description=description, + cfg_stems='mk-home' + ) + + self.initialized = True + + # ------------------------------------------------------------------------- + def init_arg_parser(self): + """ + Method to initiate the argument parser. + + This method should be explicitely called by all init_arg_parser() + methods in descendant classes. + """ + + super(PpMkHomeApp, self).init_arg_parser() + + self.arg_parser.add_argument( + "-s", "--simulate", + action='store_true', + dest='simulate', + help="Simulation af all actions, nothing is really done." + ) + + # ------------------------------------------------------------------------- + def perform_arg_parser(self): + """ + Public available method to execute some actions after parsing + the command line parameters. + + Descendant classes may override this method. + """ + + super(PpMkHomeApp, self).perform_arg_parser() + + if self.args.simulate: + self.simulate = True + + # ------------------------------------------------------------------------- + def perform_config(self): + + super(PpMkHomeApp, self).perform_config() + + for section_name in self.cfg.keys(): + + if self.verbose > 2: + LOG.debug("Checking config section {!r} ...".format(section_name)) + + if section_name.lower() not in ('mk-home', 'mk_home', 'mkhome') : + continue + + section = self.cfg[section_name] + if self.verbose > 2: + LOG.debug("Evaluating config section {n!r}:\n{s}".format( + n=section_name, s=pp(section))) + + if 'initial_uid' in section: + v = section['initial_uid'] + try: + uid = int(v) + except (ValueError, TypeError) as e: + msg = ( + "Invalid initial numeric user Id ([{s}]/initial_uid " + "=> {v!r}) found in configuration.").format(s=section_name, v=v) + raise PpMkHomeError(msg) + if uid <= 0: + msg = ( + "Invalid initial numeric user Id ([{s}]/initial_uid " + "=> {v!r}) found in configuration.").format(s=section_name, v=v) + raise PpMkHomeError(msg) + self.initial_uid = uid + + if 'chroot_homedir' in section: + v = section['chroot_homedir'] + if not os.path.isabs(v): + msg = ( + "The chrooted path of the home directories must be an " + "absolute pathname (found [{s}]/chroot_homedir " + "=> {v!r} in configuration.").format(s=section_name, v=v) + raise PpMkHomeError(msg) + self.chroot_homedir = v + + # ------------------------------------------------------------------------- + def pre_run(self): + """ + Dummy function to run before the main routine. + Could be overwritten by descendant classes. + + """ + + super(PpMkHomeApp, self).pre_run() + if os.geteuid(): + msg = "Only root may execute this application." + LOG.error(msg) + self.exit(1) + + if not os.path.exists(self.chroot_homedir): + msg = "The chrooted path of the home directories {!r} does not exists.".format( + self.chroot_homedir) + LOG.error(msg) + self.exit(1) + + if not os.path.isdir(self.chroot_homedir): + msg = "The chrooted path of the home directories {!r} is not a directory.".format( + self.chroot_homedir) + LOG.error(msg) + self.exit(1) + + # ------------------------------------------------------------------------- + def _run(self): + + LOG.debug("Executing something ...") + + query_filter = ( + '(&' + '(objectclass=posixAccount)' + '(objectclass=shadowAccount)' + '(uid=frank.brehm)' + ')' + ) + + entries = self.ldap_search(query_filter) + + print("Found {} LDAP entries.".format(len(entries))) + i = 0 + for entry in entries: + i += 1 + print("\n{}".format(entry)) + if i >= 5: + break + + +# ============================================================================= + +if __name__ == "__main__": + + pass + +# ============================================================================= + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list -- 2.39.5