From 8fc6fa7b72270a2e69894530f06727492e412cfe Mon Sep 17 00:00:00 2001 From: Petr Spacek Date: Jun 29 2015 12:32:26 +0000 Subject: DNSSEC: Accept ipa-ods-exporter commands from command line. Previously only systemd socket activation was supported. Ability to call the command directly is handy in special cases, e.g. for debugging or moving key master role from one server to another. https://fedorahosted.org/freeipa/ticket/4657 Reviewed-By: Martin Basti --- diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter index dc78aae..b39e117 100755 --- a/daemons/dnssec/ipa-ods-exporter +++ b/daemons/dnssec/ipa-ods-exporter @@ -9,6 +9,9 @@ This program uses the same socket and protocol as original signerd and should be activated via systemd socket activation using "ods-signer" command line utility. +Alternativelly, it can be called directly and a command can be supplied as +first command line argument. + Purpose of this replacement is to upload keys generated by OpenDNSSEC to LDAP. """ @@ -334,7 +337,7 @@ def hex_set(s): out.add("0x%s" % hexlify(i)) return out -def receive_zone_name(log): +def receive_systemd_command(log): fds = systemd.daemon.listen_fds() if len(fds) != 1: raise KeyError('Exactly one socket is expected.') @@ -345,36 +348,40 @@ def receive_zone_name(log): log.debug('accepted new connection %s', repr(conn)) # this implements cmdhandler_handle_cmd() logic - cmd = conn.recv(ODS_SE_MAXLINE) - cmd = cmd.strip() - - try: - if cmd == 'ipa-hsm-update': - msg = 'HSM synchronization finished, exiting.' - conn.send('%s\n' % msg) - log.info(msg) - sys.exit(0) - - elif not cmd.startswith('update '): - conn.send('Command "%s" is not supported by IPA; ' \ - 'HSM synchronization was finished and the command ' \ - 'will be ignored.\n' % cmd) - log.info('Ignoring unsupported command "%s".', cmd) - sys.exit(0) - - else: - zone_name = cmd2ods_zone_name(cmd) - conn.send('Update request for zone "%s" queued.\n' % zone_name) - log.info('Processing command: "%s"', cmd) - - finally: + cmd = conn.recv(ODS_SE_MAXLINE).strip() + log.debug('received command "%s" from systemd socket', cmd) + return (cmd, conn) + +def parse_command(cmd): + """Parse command to (exit code, message, zone_name) tuple. + + Exit code None means that execution should continue. + """ + if cmd == 'ipa-hsm-update': + return (0, + 'HSM synchronization finished, exiting.', + None) + + elif not cmd.startswith('update '): + return (0, + 'Command "%s" is not supported by IPA; ' + 'HSM synchronization was finished and the command ' + 'will be ignored.\n' % cmd, + None) + + else: + zone_name = cmd2ods_zone_name(cmd) + return (None, + 'Update request for zone "%s" queued.\n' % zone_name, + zone_name) + +def send_systemd_reply(conn, reply): # Reply & close connection early. # This is necessary to let Enforcer to unlock the ODS DB. + conn.send(reply + '\n') conn.shutdown(socket.SHUT_RDWR) conn.close() - return zone_name - def cmd2ods_zone_name(cmd): # ODS stores zone name without trailing period zone_name = cmd[7:].strip() @@ -384,13 +391,17 @@ def cmd2ods_zone_name(cmd): return zone_name log = logging.getLogger('root') -# this service is socket-activated +# this service is usually socket-activated log.addHandler(systemd.journal.JournalHandler()) log.setLevel(level=logging.DEBUG) -if len(sys.argv) != 1: +if len(sys.argv) > 2: print __doc__ sys.exit(1) +# program was likely invoked from console, log to it +elif len(sys.argv) == 2: + console = logging.StreamHandler() + log.addHandler(console) # IPA framework initialization ipalib.api.bootstrap(in_server=True, log=None) # no logging to file @@ -429,16 +440,29 @@ master2ldap_zone_keys_sync(log, ldapkeydb, localhsm) # command receive is delayed so the command will stay in socket queue until # the problem with LDAP server or HSM is fixed try: - zone_name = receive_zone_name(log) - + cmd, conn = receive_systemd_command(log) + if len(sys.argv) != 1: + log.critical('No additional parameters are accepted when ' + 'socket activation is used.') + sys.exit(1) # Handle cases where somebody ran the program without systemd. except KeyError as e: - print 'HSM (key material) sychronization is finished but ' \ - 'this program should be socket-activated by OpenDNSSEC.' - print 'Use "ods-signer" command line utility to synchronize ' \ - 'DNS zone keys and metadata.' - print 'Error: %s' % e - sys.exit(0) + if len(sys.argv) != 2: + print(__doc__) + print('ERROR: Exactly one parameter or socket activation is required.') + sys.exit(1) + conn = None + cmd = sys.argv[1] + +exitcode, msg, zone_name = parse_command(cmd) + +if conn: + send_systemd_reply(conn, msg) +if exitcode is not None: + log.info(msg) + sys.exit(exitcode) +else: + log.debug(msg) ods_keys = get_ods_keys(zone_name) ods_keys_id = set(ods_keys.keys())