# Authors: # Endi S. Dewata # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # Copyright (C) 2016 Red Hat, Inc. # All rights reserved. # from __future__ import absolute_import from __future__ import print_function import getopt import io import ldap import ldap.modlist import ldif import os import shutil import sys import tempfile import time import pki.cli import pki.server.cli.audit KRA_VLVS = ['allKeys', 'kraAll', 'kraArchival', 'kraRecovery', 'kraCanceled', 'kraCanceledEnrollment', 'kraCanceledRecovery', 'kraRejected', 'kraRejectedEnrollment', 'kraRejectedRecovery', 'kraComplete', 'kraCompleteEnrollment', 'kraCompleteRecovery'] KRA_VLV_PATH = '/usr/share/pki/kra/conf/vlv.ldif' KRA_VLV_TASKS_PATH = '/usr/share/pki/kra/conf/vlvtasks.ldif' class KRACLI(pki.cli.CLI): def __init__(self): super(KRACLI, self).__init__( 'kra', 'KRA management commands') self.add_module(KRACloneCLI()) self.add_module(KRADBCLI()) self.add_module(pki.server.cli.audit.AuditCLI(self)) class KRACloneCLI(pki.cli.CLI): def __init__(self): super(KRACloneCLI, self).__init__( 'clone', 'KRA clone management commands') self.add_module(KRAClonePrepareCLI()) class KRAClonePrepareCLI(pki.cli.CLI): def __init__(self): super(KRAClonePrepareCLI, self).__init__( 'prepare', 'Prepare KRA clone') def print_help(self): print('Usage: pki-server kra-clone-prepare [OPTIONS]') print() print(' -i, --instance Instance ID (default: pki-tomcat).') print(' --pkcs12-file PKCS #12 file to store certificates and keys.') print(' --pkcs12-password Password for the PKCS #12 file.') print(' --pkcs12-password-file File containing the PKCS #12 password.') print(' -v, --verbose Run in verbose mode.') print(' --help Show help message.') print() def execute(self, argv): try: opts, _ = getopt.gnu_getopt(argv, 'i:v', [ 'instance=', 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=', 'verbose', 'help']) except getopt.GetoptError as e: print('ERROR: ' + str(e)) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' pkcs12_file = None pkcs12_password = None for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o == '--pkcs12-file': pkcs12_file = a elif o == '--pkcs12-password': pkcs12_password = a elif o == '--pkcs12-password-file': with io.open(a, 'rb') as f: pkcs12_password = f.read() elif o in ('-v', '--verbose'): self.set_verbose(True) elif o == '--help': self.print_help() sys.exit() else: print('ERROR: unknown option ' + o) self.print_help() sys.exit(1) if not pkcs12_file: print('ERROR: Missing PKCS #12 file') self.print_help() sys.exit(1) if not pkcs12_password: print('ERROR: Missing PKCS #12 password') self.print_help() sys.exit(1) instance = pki.server.PKIInstance(instance_name) if not instance.is_valid(): print('ERROR: Invalid instance %s.' % instance_name) sys.exit(1) instance.load() subsystem = instance.get_subsystem('kra') if not subsystem: print('ERROR: No KRA subsystem in instance %s.' % instance_name) sys.exit(1) tmpdir = tempfile.mkdtemp() try: pkcs12_password_file = os.path.join(tmpdir, 'pkcs12_password.txt') with open(pkcs12_password_file, 'w') as f: f.write(pkcs12_password) subsystem.export_system_cert( 'subsystem', pkcs12_file, pkcs12_password_file, new_file=True) subsystem.export_system_cert( 'transport', pkcs12_file, pkcs12_password_file) subsystem.export_system_cert( 'storage', pkcs12_file, pkcs12_password_file) subsystem.export_system_cert( 'audit_signing', pkcs12_file, pkcs12_password_file) instance.export_external_certs(pkcs12_file, pkcs12_password_file) finally: shutil.rmtree(tmpdir) class KRADBCLI(pki.cli.CLI): def __init__(self): super(KRADBCLI, self).__init__( 'db', 'KRA database management commands') self.add_module(KRADBVLVCLI()) class KRADBVLVCLI(pki.cli.CLI): def __init__(self): super(KRADBVLVCLI, self).__init__( 'vlv', 'KRA VLV management commands') self.add_module(KRADBVLVFindCLI()) self.add_module(KRADBVLVAddCLI()) self.add_module(KRADBVLVDeleteCLI()) self.add_module(KRADBVLVReindexCLI()) class KRADBVLVFindCLI(pki.cli.CLI): def __init__(self): super(KRADBVLVFindCLI, self).__init__( 'find', 'Find KRA VLVs') def print_help(self): print('Usage: pki-server kra-db-vlv-find [OPTIONS]') print() print(' -i, --instance Instance ID (default: pki-tomcat).') print(' -D, --bind-dn Connect DN (default: cn=Directory Manager).') print(' -w, --bind-password Password to connect to database.') print(' -v, --verbose Run in verbose mode.') print(' --help Show help message.') print() def execute(self, argv): try: opts, _ = getopt.gnu_getopt( argv, 'i:D:w:x:g:v', ['instance=', 'bind-dn=', 'bind-password=', 'generate-ldif=', 'verbose', 'help'] ) except getopt.GetoptError as e: print('ERROR: ' + str(e)) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' bind_dn = None bind_password = None for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o in ('-D', '--bind-dn'): bind_dn = a elif o in ('-w', '--bind-password'): bind_password = a elif o in ('-v', '--verbose'): self.set_verbose(True) elif o == '--help': self.print_help() sys.exit() else: print('ERROR: unknown option ' + o) self.print_help() sys.exit(1) instance = pki.server.PKIInstance(instance_name) if not instance.is_valid(): print('ERROR: Invalid instance %s.' % instance_name) sys.exit(1) instance.load() subsystem = instance.get_subsystem('kra') if not subsystem: print('ERROR: No KRA subsystem in instance %s.' % instance_name) sys.exit(1) self.find_vlv(subsystem, bind_dn, bind_password) def find_vlv(self, subsystem, bind_dn, bind_password): conn = subsystem.open_database(bind_dn=bind_dn, bind_password=bind_password) try: database = subsystem.config['internaldb.database'] base_dn = 'cn=' + database + ',cn=ldbm database, cn=plugins, cn=config' if self.verbose: print('Searching %s' % base_dn) entries = conn.ldap.search_s( base_dn, ldap.SCOPE_SUBTREE, '(|(objectClass=vlvSearch)(objectClass=vlvIndex))') self.print_message('%d entries found' % len(entries)) if not entries: return first = True for entry in entries: dn = entry[0] attrs = entry[1] if first: first = False else: print() print(' dn: %s' % dn) for key, values in attrs.items(): for value in values: print(' %s: %s' % (key, value)) finally: conn.close() class KRADBVLVAddCLI(pki.cli.CLI): def __init__(self): super(KRADBVLVAddCLI, self).__init__( 'add', 'Add KRA VLVs') self.out_file = None def print_help(self): print('Usage: pki-server kra-db-vlv-add [OPTIONS]') print() print(' -i, --instance Instance ID (default: pki-tomcat).') print(' -D, --bind-dn Connect DN (default: cn=Directory Manager).') print(' -w, --bind-password Password to connect to database.') print(' -v, --verbose Run in verbose mode.') print(' -g, --generate-ldif Generate LDIF of required changes.') print(' --help Show help message.') print() def execute(self, argv): try: opts, _ = getopt.gnu_getopt( argv, 'i:D:w:x:g:v', ['instance=', 'bind-dn=', 'bind-password=', 'generate-ldif=', 'verbose', 'help'] ) except getopt.GetoptError as e: print('ERROR: ' + str(e)) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' bind_dn = 'cn=Directory Manager' bind_password = None for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o in ('-D', '--bind-dn'): bind_dn = a elif o in ('-w', '--bind-password'): bind_password = a elif o in ('-g', '--generate-ldif'): self.out_file = a elif o in ('-v', '--verbose'): self.set_verbose(True) elif o == '--help': self.print_help() sys.exit() else: print('ERROR: unknown option ' + o) self.print_help() sys.exit(1) instance = pki.server.PKIInstance(instance_name) if not instance.is_valid(): print('ERROR: Invalid instance %s.' % instance_name) sys.exit(1) instance.load() subsystem = instance.get_subsystem('kra') if not subsystem: print('ERROR: No KRA subsystem in instance %s.' % instance_name) sys.exit(1) if self.out_file: subsystem.customize_file(KRA_VLV_PATH, self.out_file) print('KRA VLVs written to ' + self.out_file) return try: self.add_vlv(subsystem, bind_dn, bind_password) print('KRA VLVs added to the database for ' + instance_name) except ldap.LDAPError as e: print("ERROR: {}".format(e)) sys.exit(1) def add_vlv(self, subsystem, bind_dn, bind_password): ldif_file = tempfile.NamedTemporaryFile(delete=False) subsystem.customize_file(KRA_VLV_PATH, ldif_file.name) conn = subsystem.open_database(bind_dn=bind_dn, bind_password=bind_password) try: parser = ldif.LDIFRecordList(open(ldif_file.name, "rb")) parser.parse() for dn, entry in parser.all_records: add_modlist = ldap.modlist.addModlist(entry) conn.ldap.add_s(dn, add_modlist) finally: os.unlink(ldif_file.name) conn.close() class KRADBVLVDeleteCLI(pki.cli.CLI): def __init__(self): super(KRADBVLVDeleteCLI, self).__init__( 'del', 'Delete KRA VLVs') self.out_file = None def print_help(self): print('Usage: pki-server kra-db-vlv-del [OPTIONS]') print() print(' -i, --instance Instance ID (default: pki-tomcat).') print(' -D, --bind-dn Connect DN (default: cn=Directory Manager).') print(' -w, --bind-password Password to connect to database.') print(' -g, --generate-ldif Generate LDIF of required changes.') print(' -v, --verbose Run in verbose mode.') print(' --help Show help message.') print() def execute(self, argv): try: opts, _ = getopt.gnu_getopt( argv, 'i:D:w:x:g:v', ['instance=', 'bind-dn=', 'bind-password=', 'generate-ldif=', 'verbose', 'help'] ) except getopt.GetoptError as e: print('ERROR: ' + str(e)) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' bind_dn = None bind_password = None for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o in ('-D', '--bind-dn'): bind_dn = a elif o in ('-w', '--bind-password'): bind_password = a elif o in ('-g', '--generate-ldif'): self.out_file = a elif o in ('-v', '--verbose'): self.set_verbose(True) elif o == '--help': self.print_help() sys.exit() else: print('ERROR: unknown option ' + o) self.print_help() sys.exit(1) instance = pki.server.PKIInstance(instance_name) if not instance.is_valid(): print('ERROR: Invalid instance %s.' % instance_name) sys.exit(1) instance.load() subsystem = instance.get_subsystem('kra') if not subsystem: print('ERROR: No KRA subsystem in instance %s.' % instance_name) sys.exit(1) self.delete_vlv(subsystem, bind_dn, bind_password) print('KRA VLVs deleted from the database for ' + instance_name) def delete_vlv(self, subsystem, bind_dn, bind_password): database = subsystem.config['internaldb.database'] if self.out_file: with open(self.out_file, "w") as f: for vlv in KRA_VLVS: dn = ("cn=" + vlv + '-' + subsystem.instance.name + ',cn=' + database + ',cn=ldbm database, cn=plugins, cn=config') index_dn = ("cn=" + vlv + '-' + subsystem.instance.name + "Index," + dn) f.write('dn: ' + index_dn + '\n') f.write('changetype: delete' + '\n') f.write('\n') f.write('dn: ' + dn + '\n') f.write('changetype: delete' + '\n') f.write('\n') print('KRA VLV changes written to ' + self.out_file) return conn = subsystem.open_database(bind_dn=bind_dn, bind_password=bind_password) try: for vlv in KRA_VLVS: dn = ("cn=" + vlv + '-' + subsystem.instance.name + ',cn=' + database + ',cn=ldbm database, cn=plugins, cn=config') index_dn = "cn=" + vlv + '-' + subsystem.instance.name + "Index," + dn try: conn.ldap.delete_s(index_dn) except ldap.NO_SUCH_OBJECT: pass try: conn.ldap.delete_s(dn) except ldap.NO_SUCH_OBJECT: pass finally: conn.close() class KRADBVLVReindexCLI(pki.cli.CLI): def __init__(self): super(KRADBVLVReindexCLI, self).__init__( 'reindex', 'Re-index KRA VLVs') self.out_file = None def print_help(self): print('Usage: pki-server kra-db-vlv-reindex [OPTIONS]') print() print(' -i, --instance Instance ID (default: pki-tomcat).') print(' -D, --bind-dn Connect DN (default: cn=Directory Manager).') print(' -w, --bind-password Password to connect to database.') print(' -g, --generate-ldif Generate LDIF of required changes.') print(' -v, --verbose Run in verbose mode.') print(' --help Show help message.') print() def execute(self, argv): try: opts, _ = getopt.gnu_getopt( argv, 'i:D:w:x:g:v', ['instance=', 'bind-dn=', 'bind-password=', 'generate-ldif=', 'verbose', 'help'] ) except getopt.GetoptError as e: print('ERROR: ' + str(e)) self.print_help() sys.exit(1) instance_name = 'pki-tomcat' bind_dn = 'cn=Directory Manager' bind_password = None for o, a in opts: if o in ('-i', '--instance'): instance_name = a elif o in ('-D', '--bind-dn'): bind_dn = a elif o in ('-w', '--bind-password'): bind_password = a elif o in ('-g', '--generate-ldif'): self.out_file = a elif o in ('-v', '--verbose'): self.set_verbose(True) elif o == '--help': self.print_help() sys.exit() else: print('ERROR: unknown option ' + o) self.print_help() sys.exit(1) instance = pki.server.PKIInstance(instance_name) if not instance.is_valid(): print('ERROR: Invalid instance %s.' % instance_name) sys.exit(1) instance.load() subsystem = instance.get_subsystem('kra') if not subsystem: print('ERROR: No KRA subsystem in instance %s.' % instance_name) sys.exit(1) if self.out_file: subsystem.customize_file(KRA_VLV_TASKS_PATH, self.out_file) print('KRA VLV reindex task written to ' + self.out_file) return self.reindex_vlv(subsystem, bind_dn, bind_password) print('KRA VLV reindex completed for ' + instance_name) def reindex_vlv(self, subsystem, bind_dn, bind_password): ldif_file = tempfile.NamedTemporaryFile(delete=False) subsystem.customize_file(KRA_VLV_TASKS_PATH, ldif_file.name) conn = subsystem.open_database(bind_dn=bind_dn, bind_password=bind_password) print('Initiating KRA VLV reindex for ' + subsystem.instance.name) try: parser = ldif.LDIFRecordList(open(ldif_file.name, "rb")) parser.parse() for dn, entry in parser.all_records: if self.verbose: print('Adding %s' % dn) add_modlist = ldap.modlist.addModlist(entry) conn.ldap.add_s(dn, add_modlist) while True: time.sleep(1) try: if self.verbose: print('Checking %s' % dn) conn.ldap.search_s(dn, ldap.SCOPE_BASE) except ldap.NO_SUCH_OBJECT: break finally: os.unlink(ldif_file.name) conn.close()