commit e5532b4740cca87cca2d893fa76a8f2ee8d5d3ed Author: Benjamin Renard Date: Fri Jul 3 17:19:54 2020 +0200 Initial version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c5f88a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +.*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c8c99f --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# OpenLDAP tool to check CRC32 of LDIF files of slapd.d directory + +This script permit to check (and eventually fix) CRC32 value of the LDIF files of OpenLDAP slapd.d configuration directory. + +## Requirements + +This script only used common __python3__ modules _(no additionnal package to install on Debian based systems)_. + +## Usage + +``` +usage: check_slapdd_crc32 [-h] [-d] [-v] [-l LOGFILE] [-C] [-f] + [-p SLAPDD_PATH] + +optional arguments: + -h, --help show this help message and exit + -d, --debug Show debug messages + -v, --verbose Show verbose messages + -l LOGFILE, --log-file LOGFILE + Log file path + -C, --console Also log on console (even if log file is provided) + -f, --fix Fix CRC32 value in LDIF files + -p SLAPDD_PATH, --path SLAPDD_PATH + Default slapd.d directory path (default: + /etc/ldap/slapd.d) +``` + +## Copyright + +Copyright (c) 2014-2019 Benjamin Renard + +## License + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + diff --git a/check_slapdd_crc32 b/check_slapdd_crc32 new file mode 100755 index 0000000..8187b02 --- /dev/null +++ b/check_slapdd_crc32 @@ -0,0 +1,148 @@ +#!/usr/bin/python3 +""" +OpenLDAP tool to check CRC32 of LDIF files of slapd.d directory +""" + +import argparse +import binascii +import logging +import os +import re +import sys + +default_slapdd_path = '/etc/ldap/slapd.d' + +### MAIN #### +parser = argparse.ArgumentParser() + +parser.add_argument( + '-d', '--debug', + action='store_true', + help='Show debug messages' +) + +parser.add_argument( + '-v', '--verbose', + action='store_true', + help='Show verbose messages' +) + +parser.add_argument( + '-l', + '--log-file', + action="store", + type=str, + dest="logfile", + help="Log file path" +) + +parser.add_argument( + '-C', '--console', + action='store_true', + help='Also log on console (even if log file is provided)' +) + +parser.add_argument( + '-f', '--fix', + action='store_true', + help='Fix CRC32 value in LDIF files' +) + +parser.add_argument( + '-p', '--path', + action='store', + type=str, + dest='slapdd_path', + help='Default slapd.d directory path (default: %s)' % default_slapdd_path, + default=default_slapdd_path +) + + +options = parser.parse_args() + +# Initialize log +log = logging.getLogger() +logformat = logging.Formatter("%(asctime)s - " + os.path.basename(sys.argv[0]) + " - %(levelname)s - %(message)s") + +if options.debug: + log.setLevel(logging.DEBUG) +elif options.verbose: + log.setLevel(logging.INFO) +else: + log.setLevel(logging.WARNING) + +if options.logfile: + logfile = logging.FileHandler(options.logfile) + logfile.setFormatter(logformat) + log.addHandler(logfile) + +if not options.logfile or options.console: + logconsole = logging.StreamHandler() + logconsole.setFormatter(logformat) + log.addHandler(logconsole) + +def check_file(dir_path, file_name): + """ + Check CRC32 of an LDIF file + + :param dir_path: The directory path + :param file_name: The file name + """ + path = os.path.join(dir_path, file_name) + + lines = [] + current_crc32 = None + try: + with open(path, 'rb') as fd: + for line in fd.readlines(): + if line.startswith(b'# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.'): + logging.debug('%s: AUTO-GENERATED line detected, pass (%s)', path, line) + continue + if line.startswith(b'# CRC32 '): + logging.debug('%s: CRC32 line detected, retreive current CRC32 value (%s)', path, line) + current_crc32 = re.match('^# CRC32 (.*)$', line.decode()).group(1) + logging.debug('%s: current CRC32 found is "%s"', path, current_crc32) + continue + lines.append(line) + except IOError as err: + logging.error('%s: fail to read file content (%s)', path, err) + return False + + crc32 = ("%08X" % ((binascii.crc32(b"".join(lines)) & 0xFFFFFFFF) % (1<<32))).lower() + if current_crc32: + if current_crc32 == crc32: + log.info('%s: current CRC32 value is correct (%s)', path, crc32) + else: + log.warning('%s: invalid CRC32 value found (%s != %s)', path, current_crc32, crc32) + fix_crc32(path, crc32, lines) + else: + log.warning('%s: no CRC32 value found. Correct CRC32 value is "%s".', path, crc32) + fix_crc32(path, crc32, lines) + return True + +def fix_crc32(path, crc32, lines): + """ + Fix CRC32 value of an LDIF file + + :param path: The file path + :param crc32: The CRC32 value of the file + :param lines: Array of file lines without headers + """ + if not options.fix: + return True + try: + with open(path, 'wb') as fd: + lines = [b'# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n', b'# CRC32 %s\n' % crc32.encode()] + lines + for line in lines: + fd.write(line) + except IOError as err: + logging.error('%s: fail to write new file content (%s)', path, err) + return False + return True + +log.info('Checking CRC32 in slapd directory "%s"', options.slapdd_path) +for dirpath, dnames, fnames in os.walk(options.slapdd_path): + log.debug('%s: sub-dirs = "%s", files = "%s"', dirpath, '", "'.join(dnames), '", "'.join(fnames)) + for fname in fnames: + if fname.endswith('.ldif'): + check_file(dirpath, fname)