summaryrefslogtreecommitdiffstats
path: root/ipa-client
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2014-06-27 12:31:50 +0200
committerPetr Viktorin <pviktori@redhat.com>2014-07-30 16:04:21 +0200
commit60e19b585cc12e5b4d51b2d18c504f253cc692ca (patch)
treef8025b1317df23938e74246538c7392a06d46329 /ipa-client
parent2b7a7c356cf8db6ccadae6a4c932eb2d23585095 (diff)
downloadfreeipa-60e19b585cc12e5b4d51b2d18c504f253cc692ca.tar.gz
freeipa-60e19b585cc12e5b4d51b2d18c504f253cc692ca.tar.xz
freeipa-60e19b585cc12e5b4d51b2d18c504f253cc692ca.zip
Add client certificate update tool ipa-certupdate.
Part of https://fedorahosted.org/freeipa/ticket/3259 Part of https://fedorahosted.org/freeipa/ticket/3520 Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Diffstat (limited to 'ipa-client')
-rw-r--r--ipa-client/ipa-install/Makefile.am1
-rwxr-xr-xipa-client/ipa-install/ipa-certupdate23
-rw-r--r--ipa-client/ipaclient/Makefile.am1
-rw-r--r--ipa-client/ipaclient/ipa_certupdate.py171
-rw-r--r--ipa-client/man/Makefile.am1
-rw-r--r--ipa-client/man/ipa-certupdate.139
6 files changed, 236 insertions, 0 deletions
diff --git a/ipa-client/ipa-install/Makefile.am b/ipa-client/ipa-install/Makefile.am
index 2e9a04d10..7abdbf12b 100644
--- a/ipa-client/ipa-install/Makefile.am
+++ b/ipa-client/ipa-install/Makefile.am
@@ -3,6 +3,7 @@ NULL =
sbin_SCRIPTS = \
ipa-client-install \
ipa-client-automount \
+ ipa-certupdate \
$(NULL)
EXTRA_DIST = \
diff --git a/ipa-client/ipa-install/ipa-certupdate b/ipa-client/ipa-install/ipa-certupdate
new file mode 100755
index 000000000..072c451bc
--- /dev/null
+++ b/ipa-client/ipa-install/ipa-certupdate
@@ -0,0 +1,23 @@
+#! /usr/bin/python2 -E
+# Authors: Jan Cholasta <jcholast@redhat.com>
+#
+# Copyright (C) 2014 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+from ipaclient.ipa_certupdate import CertUpdate
+
+CertUpdate.run_cli()
diff --git a/ipa-client/ipaclient/Makefile.am b/ipa-client/ipaclient/Makefile.am
index 1d7df5266..01824b865 100644
--- a/ipa-client/ipaclient/Makefile.am
+++ b/ipa-client/ipaclient/Makefile.am
@@ -6,6 +6,7 @@ app_PYTHON = \
ipachangeconf.py \
ipadiscovery.py \
ntpconf.py \
+ ipa_certupdate.py \
$(NULL)
EXTRA_DIST = \
diff --git a/ipa-client/ipaclient/ipa_certupdate.py b/ipa-client/ipaclient/ipa_certupdate.py
new file mode 100644
index 000000000..4199a293b
--- /dev/null
+++ b/ipa-client/ipaclient/ipa_certupdate.py
@@ -0,0 +1,171 @@
+# Authors: Jan Cholasta <jcholast@redhat.com>
+#
+# Copyright (C) 2014 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import tempfile
+import shutil
+
+from ipapython import (admintool, ipautil, ipaldap, sysrestore, dogtag,
+ certmonger)
+from ipaplatform import services
+from ipaplatform.paths import paths
+from ipaplatform.tasks import tasks
+from ipalib import api, x509, certstore
+
+
+class CertUpdate(admintool.AdminTool):
+ command_name = 'ipa-certupdate'
+
+ usage = "%prog [options]"
+
+ description = ("Update local IPA certificate databases with certificates "
+ "from the server.")
+
+ def validate_options(self):
+ super(CertUpdate, self).validate_options(needs_root=True)
+
+ def run(self):
+ api.bootstrap(context='cli_installer')
+ api.finalize()
+
+ try:
+ server = api.env.server
+ except AttributeError:
+ server = api.env.host
+ ldap = ipaldap.IPAdmin(server)
+
+ tmpdir = tempfile.mkdtemp(prefix="tmp-")
+ try:
+ principal = str('host/%s@%s' % (api.env.host, api.env.realm))
+ ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal)
+
+ ldap.do_sasl_gssapi_bind()
+
+ certs = certstore.get_ca_certs(ldap, api.env.basedn,
+ api.env.realm, api.env.enable_ra)
+ finally:
+ shutil.rmtree(tmpdir)
+
+ server_fstore = sysrestore.FileStore(paths.SYSRESTORE)
+ if server_fstore.has_files():
+ self.update_server(certs)
+
+ self.update_client(certs)
+
+ def update_client(self, certs):
+ self.update_file(paths.IPA_CA_CRT, certs)
+
+ self.update_db(paths.NSS_DB_DIR, certs)
+
+ new_nicknames = set(c[1] for c in certs)
+ old_nicknames = set()
+ if ipautil.file_exists(paths.NSSDB_IPA_TXT):
+ try:
+ list_file = open(paths.NSSDB_IPA_TXT, 'r')
+ except IOError, e:
+ self.log.error("failed to open %s: %s", paths.NSSDB_IPA_TXT, e)
+ else:
+ try:
+ lines = list_file.readlines()
+ except IOError, e:
+ self.log.error(
+ "failed to read %s: %s", paths.NSSDB_IPA_TXT, e)
+ else:
+ for line in lines:
+ nickname = line.strip()
+ if nickname:
+ old_nicknames.add(nickname)
+ list_file.close()
+ if new_nicknames != old_nicknames:
+ try:
+ list_file = open(paths.NSSDB_IPA_TXT, 'w')
+ except IOError, e:
+ self.log.error("failed to open %s: %s", paths.NSSDB_IPA_TXT, e)
+ else:
+ try:
+ for nickname in new_nicknames:
+ list_file.write(nickname + '\n')
+ except IOError, e:
+ self.log.error(
+ "failed to write %s: %s", paths.NSSDB_IPA_TXT, e)
+ list_file.close()
+
+ tasks.remove_ca_certs_from_systemwide_ca_store()
+ tasks.insert_ca_certs_into_systemwide_ca_store(certs)
+
+ def update_server(self, certs):
+ instance = '-'.join(api.env.realm.split('.'))
+ self.update_db(
+ paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs)
+ if services.knownservices.dirsrv.is_running():
+ services.knownservices.dirsrv.restart(instance)
+
+ self.update_db(paths.HTTPD_ALIAS_DIR, certs)
+ if services.knownservices.httpd.is_running():
+ services.knownservices.httpd.restart()
+
+ dogtag_constants = dogtag.configured_constants()
+ nickname = 'caSigningCert cert-pki-ca'
+ criteria = (
+ ('cert_storage_location', dogtag_constants.ALIAS_DIR,
+ certmonger.NPATH),
+ ('cert_nickname', nickname, None),
+ )
+ request_id = certmonger.get_request_id(criteria)
+ if request_id is not None:
+ timeout = api.env.startup_timeout + 60
+
+ self.log.debug("resubmitting certmonger request '%s'", request_id)
+ certmonger.resubmit_request(request_id, profile='ipaRetrieval')
+ try:
+ state = certmonger.wait_for_request(request_id, timeout)
+ except RuntimeError:
+ raise admintool.ScriptError(
+ "Resubmitting certmonger request '%s' timed out, "
+ "please check the request manually" % request_id)
+ if state != 'MONITORING':
+ raise admintool.ScriptError(
+ "Error resubmitting certmonger request '%s', "
+ "please check the request manually" % request_id)
+
+ self.log.debug("modifying certmonger request '%s'", request_id)
+ certmonger.modify(request_id, profile='ipaCACertRenewal')
+
+ self.update_file(paths.CA_CRT, certs)
+
+ def update_file(self, filename, certs, mode=0444):
+ certs = (c[0] for c in certs if c[2] is not False)
+ try:
+ x509.write_certificate_list(certs, filename)
+ except Exception, e:
+ self.log.error("failed to update %s: %s", filename, e)
+
+ def update_db(self, path, certs):
+ for cert, nickname, trusted, eku in certs:
+ trust_flags = certstore.key_policy_to_trust_flags(
+ trusted, True, eku)
+ try:
+ ipautil.run([paths.CERTUTIL, '-A',
+ '-d', path,
+ '-n', nickname,
+ '-t', trust_flags],
+ stdin=cert)
+ except ipautil.CalledProcessError, e:
+ self.log.error(
+ "failed to update %s in %s: %s", nickname, path, e)
diff --git a/ipa-client/man/Makefile.am b/ipa-client/man/Makefile.am
index 42772e43c..9d8a9c03d 100644
--- a/ipa-client/man/Makefile.am
+++ b/ipa-client/man/Makefile.am
@@ -9,6 +9,7 @@ man1_MANS = \
ipa-rmkeytab.1 \
ipa-client-install.1 \
ipa-client-automount.1 \
+ ipa-certupdate.1 \
ipa-join.1
man5_MANS = \
diff --git a/ipa-client/man/ipa-certupdate.1 b/ipa-client/man/ipa-certupdate.1
new file mode 100644
index 000000000..d95790a36
--- /dev/null
+++ b/ipa-client/man/ipa-certupdate.1
@@ -0,0 +1,39 @@
+.\" A man page for ipa-certupdate
+.\" Copyright (C) 2014 Red Hat, Inc.
+.\"
+.\" 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, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" 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, see <http://www.gnu.org/licenses/>.
+.\"
+.\" Author: Jan Cholasta <jcholast@redhat.com>
+.\"
+.TH "ipa-certupdate" "1" "Jul 2 2014" "FreeIPA" "FreeIPA Manual Pages"
+.SH "NAME"
+ipa\-certupdate \- Update local IPA certificate databases with certificates from the server
+.SH "SYNOPSIS"
+\fBipa\-certupdate\fR [\fIOPTIONS\fR...]
+.SH "DESCRIPTION"
+\fBipa\-certupdate\fR can be used to update local IPA certificate databases with certificates from the server.
+.SH "OPTIONS"
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+Print debugging information.
+.TP
+\fB\-q\fR, \fB\-\-quiet\fR
+Output only errors.
+.TP
+\fB\-\-log\-file\fR=\fIFILE\fR
+Log to the given file.
+.SH "EXIT STATUS"
+0 if the command was successful
+
+1 if an error occurred