diff --git a/ipalib/plugins/join.py b/ipalib/plugins/join.py index d75043fdd..5f0d9974f 100644 --- a/ipalib/plugins/join.py +++ b/ipalib/plugins/join.py @@ -26,6 +26,15 @@ from ipalib import Command, Str, Int from ipalib import errors import krbV import os, subprocess +from ipapython import ipautil +from ipapython import certdb +from ipapython import dogtag +import tempfile +import sha +import httplib +import xml.dom.minidom +import stat +import shutil def get_realm(): krbctx = krbV.default_context() @@ -103,14 +112,43 @@ class join(Command): def __get_keytab(self, principal, stdin=None): args = ["/usr/sbin/ipa-getkeytab", "-s", self.env.host, "-p", principal,"-k", "/tmp/kt"] - return self.__run(args, stdin) + return ipautil.run(args, stdin) - def __run(self, args, stdin=None): - if stdin: - p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) - stdout,stderr = p.communicate(stdin) + def _generate_server_cert(self, hostname): + subject = "CN=%s,OU=pki-ipa,O=IPA" % hostname + cdb = certdb.CertDB(secdir=None, temporary=True) + + csr = cdb.generate_csr(subject, keysize=1024) + + # Request a cert + try: + result = api.Command['cert_request'](unicode(csr), **{}) + except KeyError: + return "Certificates are not supported" + + # Load the cert into our temporary database + if result.get('certificate', False): + cert_file = cdb.secdir + "/cert.txt" + f = open(cert_file, "w") + f.write(result.get('certificate')) + f.close() + + cdb.add_certificate(cert_file, "Server-Cert", is_ca=False) + + ca_chain = dogtag.get_ca_certchain() + + ca_file = cdb.secdir + "/ca.txt" + f = open(ca_file, "w") + f.write(ca_chain) + f.close() + + cdb.add_certificate(ca_file, "caCert", is_ca=True) + + result = cdb.create_pkcs12("/tmp/server.p12", "Server-Cert") else: - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) - stdout,stderr = p.communicate() + # Raise some error? + pass + + return result api.register(join) diff --git a/ipapython/certdb.py b/ipapython/certdb.py new file mode 100644 index 000000000..15f6c16aa --- /dev/null +++ b/ipapython/certdb.py @@ -0,0 +1,150 @@ +# Authors: Rob Crittenden +# +# Copyright (C) 2009 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; version 2 only +# +# 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 +# + +from ipapython import ipautil +from ipapython import nsslib +import tempfile +import sha +import shutil +import os + +class CertDB(): + """ + To be used for temporary NSS databases only. If temporary is set then + this willcompletely remove the database it is working on when the + class is destroyed. + """ + def __init__(self, secdir, password=None, temporary=False): + if secdir is None: + secdir = tempfile.mkdtemp(prefix = "certdb-") + if password is None: + password = self.generate_random() + self.secdir = secdir + self.password = password + self.temporary = temporary + self.noise_file = secdir + "/noise" + self.pwd_file = secdir + "/pwd" + self.csr_file = secdir + "/csr.txt" + + f = open(self.pwd_file, "w") + f.write(self.password) + f.close() + + if not ipautil.file_exists(secdir + "/secmod.db"): + self.run_certutil(["-N", "-f", self.pwd_file]) + + def __del__(self): + if self.temporary: + shutil.rmtree(self.secdir) + else: + # clean up + if ipautil.file_exists(self.noise_file): + os.remove(self.noise_file) + + def run_certutil(self, args, stdin=None): + new_args = ["/usr/bin/certutil", "-d", self.secdir] + new_args = new_args + args + return ipautil.run(new_args, stdin) + + def generate_random(self): + return sha.sha(ipautil.ipa_generate_password()).hexdigest() + + def create_noise_file(self): + """ + Generate a noise file to be used when creating a key + """ + if ipautil.file_exists(self.noise_file): + os.remove(self.noise_file) + + f = open(self.noise_file, "w") + f.write(self.generate_random()) + f.close() + + return + + def generate_csr(self, subject, keysize=2048, keytype="rsa"): + """ + Generate a Certificate Signing Request (CSR) and return as a + string the base-64 result with the BEGIN/END block. + """ + self.create_noise_file() + args = ["-R", "-s", subject, + "-o", self.csr_file, + "-k", keytype, + "-g", str(keysize), + "-z", self.noise_file, + "-f", self.pwd_file, + "-a"] + self.run_certutil(args) + + # read in the CSR + f = open(self.csr_file, "r") + csr = f.readlines() + f.close() + csr = "".join(csr) + + # We just want the CSR bits, make sure there is nothing else + s = csr.find("-----BEGIN NEW CERTIFICATE REQUEST-----") + e = csr.find("-----END NEW CERTIFICATE REQUEST-----") + if e > 0: + e = e + 37 + if s >= 0: + csr = csr[s:] + + return csr + + def add_certificate(self, cert_file, nickname="Server-Cert", is_ca=False): + """ + Add a certificate to our NSS database. + + Only supports base64-encoded certificates, not DER-encoded. + """ + if is_ca: + trust_flag="CT,C,C" + else: + trust_flag="u,u,u" + + # Generate a CSR + args = ["-A", + "-n", nickname, + "-t", trust_flag, + "-i", cert_file, + "-f", self.pwd_file, + "-a"] + + self.run_certutil(args) + + def create_pkcs12(self, pkcs12_file, nickname="Server-Cert", password=None): + if password is None: + password = self.password + + p12pwd_file = self.secdir + "/pkcs12_pwd" + f = open(p12pwd_file, "w") + f.write(password) + f.close() + + args = ["/usr/bin/pk12util", + "-d", self.secdir, + "-o", pkcs12_file, + "-n", nickname, + "-k", self.pwd_file, + "-w", p12pwd_file] + ipautil.run(args) + + return password