check_slapdd_crc32 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/python3
  2. """
  3. OpenLDAP tool to check CRC32 of LDIF files of slapd.d directory
  4. """
  5. import argparse
  6. import binascii
  7. import logging
  8. import os
  9. import re
  10. import sys
  11. default_slapdd_path = '/etc/ldap/slapd.d'
  12. ### MAIN ####
  13. parser = argparse.ArgumentParser()
  14. parser.add_argument(
  15. '-d', '--debug',
  16. action='store_true',
  17. help='Show debug messages'
  18. )
  19. parser.add_argument(
  20. '-v', '--verbose',
  21. action='store_true',
  22. help='Show verbose messages'
  23. )
  24. parser.add_argument(
  25. '-l',
  26. '--log-file',
  27. action="store",
  28. type=str,
  29. dest="logfile",
  30. help="Log file path"
  31. )
  32. parser.add_argument(
  33. '-C', '--console',
  34. action='store_true',
  35. help='Also log on console (even if log file is provided)'
  36. )
  37. parser.add_argument(
  38. '-f', '--fix',
  39. action='store_true',
  40. help='Fix CRC32 value in LDIF files'
  41. )
  42. parser.add_argument(
  43. '-p', '--path',
  44. action='store',
  45. type=str,
  46. dest='slapdd_path',
  47. help='Default slapd.d directory path (default: %s)' % default_slapdd_path,
  48. default=default_slapdd_path
  49. )
  50. options = parser.parse_args()
  51. # Initialize log
  52. log = logging.getLogger()
  53. logformat = logging.Formatter("%(asctime)s - " + os.path.basename(sys.argv[0]) + " - %(levelname)s - %(message)s")
  54. if options.debug:
  55. log.setLevel(logging.DEBUG)
  56. elif options.verbose:
  57. log.setLevel(logging.INFO)
  58. else:
  59. log.setLevel(logging.WARNING)
  60. if options.logfile:
  61. logfile = logging.FileHandler(options.logfile)
  62. logfile.setFormatter(logformat)
  63. log.addHandler(logfile)
  64. if not options.logfile or options.console:
  65. logconsole = logging.StreamHandler()
  66. logconsole.setFormatter(logformat)
  67. log.addHandler(logconsole)
  68. def check_file(dir_path, file_name):
  69. """
  70. Check CRC32 of an LDIF file
  71. :param dir_path: The directory path
  72. :param file_name: The file name
  73. """
  74. path = os.path.join(dir_path, file_name)
  75. lines = []
  76. current_crc32 = None
  77. try:
  78. with open(path, 'rb') as fd:
  79. for line in fd.readlines():
  80. if line.startswith(b'# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.'):
  81. logging.debug('%s: AUTO-GENERATED line detected, pass (%s)', path, line)
  82. continue
  83. if line.startswith(b'# CRC32 '):
  84. logging.debug('%s: CRC32 line detected, retreive current CRC32 value (%s)', path, line)
  85. current_crc32 = re.match('^# CRC32 (.*)$', line.decode()).group(1)
  86. logging.debug('%s: current CRC32 found is "%s"', path, current_crc32)
  87. continue
  88. lines.append(line)
  89. except IOError as err:
  90. logging.error('%s: fail to read file content (%s)', path, err)
  91. return False
  92. crc32 = ("%08X" % ((binascii.crc32(b"".join(lines)) & 0xFFFFFFFF) % (1<<32))).lower()
  93. if current_crc32:
  94. if current_crc32 == crc32:
  95. log.info('%s: current CRC32 value is correct (%s)', path, crc32)
  96. else:
  97. log.warning('%s: invalid CRC32 value found (%s != %s)', path, current_crc32, crc32)
  98. fix_crc32(path, crc32, lines)
  99. else:
  100. log.warning('%s: no CRC32 value found. Correct CRC32 value is "%s".', path, crc32)
  101. fix_crc32(path, crc32, lines)
  102. return True
  103. def fix_crc32(path, crc32, lines):
  104. """
  105. Fix CRC32 value of an LDIF file
  106. :param path: The file path
  107. :param crc32: The CRC32 value of the file
  108. :param lines: Array of file lines without headers
  109. """
  110. if not options.fix:
  111. return True
  112. try:
  113. with open(path, 'wb') as fd:
  114. lines = [b'# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n', b'# CRC32 %s\n' % crc32.encode()] + lines
  115. for line in lines:
  116. fd.write(line)
  117. except IOError as err:
  118. logging.error('%s: fail to write new file content (%s)', path, err)
  119. return False
  120. return True
  121. log.info('Checking CRC32 in slapd directory "%s"', options.slapdd_path)
  122. for dirpath, dnames, fnames in os.walk(options.slapdd_path):
  123. log.debug('%s: sub-dirs = "%s", files = "%s"', dirpath, '", "'.join(dnames), '", "'.join(fnames))
  124. for fname in fnames:
  125. if fname.endswith('.ldif'):
  126. check_file(dirpath, fname)