#! /usr/bin/python -E
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
#
# Copyright (C) 2007  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
#

import sys
import os
import pwd
import tempfile

import traceback

import krbV, ldap, getpass

from ipa.ipautil import user_input
from ipaserver import certs, dsinstance, httpinstance, ipaldap, installutils

def get_realm_name():
    c = krbV.default_context()
    return c.default_realm

def parse_options():
    from optparse import OptionParser
    parser = OptionParser()

    parser.add_option("-d", "--dirsrv", dest="dirsrv", action="store_true",
                      default=False, help="install certificate for the directory server")
    parser.add_option("-w", "--http", dest="http", action="store_true",
                      default=False, help="install certificate for the http server")
    parser.add_option("--dirsrv_pin", dest="dirsrv_pin",
                      help="The password of the Directory Server PKCS#12 file")
    parser.add_option("--http_pin", dest="http_pin",
                      help="The password of the Apache Server PKCS#12 file")

    options, args = parser.parse_args()

    if not options.dirsrv and not options.http:
        parser.error("you must specify dirsrv and/or http")
    if ((options.dirsrv and not options.dirsrv_pin) or
            (options.http and not options.http_pin)):
        parser.error("you must provide the password for the PKCS#12 file")

    if len(args) != 1:
        parser.error("you must provide a pkcs12 filename")

    return options, args[0]

def set_ds_cert_name(cert_name, dm_password):
    conn = ipaldap.IPAdmin("127.0.0.1")
    conn.simple_bind_s("cn=directory manager", dm_password)

    mod = [(ldap.MOD_REPLACE, "nsSSLPersonalitySSL", cert_name)]

    conn.modify_s("cn=RSA,cn=encryption,cn=config", mod)

    conn.unbind()

def choose_server_cert(server_certs):
    print "Please select the certificate to use:"
    num = 1
    for cert in server_certs:
        print "%d. %s" % (num, cert[0])
        num += 1

    while 1:
        num = user_input("Certificate number", 1)
        print ""
        if num < 1 or num > len(server_certs):
            print "number out of range"
        else:
            break

    return server_certs[num - 1]

def import_cert(dirname, pkcs12_fname, pkcs12_passwd, db_password):
    cdb = certs.CertDB(dirname)
    cdb.create_passwd_file(db_password)
    cdb.create_certdbs()
    [pw_fd, pw_name] = tempfile.mkstemp()
    os.write(pw_fd, pkcs12_passwd)
    os.close(pw_fd)

    try:
        try:
            cdb.import_pkcs12(pkcs12_fname, pw_name)
        except RuntimeError, e:
            print str(e)
            sys.exit(1)
    finally:
        os.remove(pw_name)

    server_certs = cdb.find_server_certs()
    if len(server_certs) == 0:
        print "could not find a suitable server cert in import"
        sys.exit(1)
    elif len(server_certs) == 1:
        server_cert = server_certs[0]
    else:
        server_cert = choose_server_cert(server_certs)

    cdb.trust_root_cert(server_cert[0])

    return server_cert

def main():
    options, pkcs12_fname = parse_options()

    try:
        if options.dirsrv:
            dm_password = getpass.getpass("Directory Manager password: ")
            realm = get_realm_name()
            dirname = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm))
            fd = open(dirname + "/pwdfile.txt")
            passwd = fd.read()
            fd.close()

            server_cert = import_cert(dirname, pkcs12_fname, options.dirsrv_pin, passwd)
            set_ds_cert_name(server_cert[0], dm_password)

        if options.http:
            dirname = httpinstance.NSS_DIR
            server_cert = import_cert(dirname, pkcs12_fname, options.http_pin, "")
            installutils.set_directive(httpinstance.NSS_CONF, 'NSSNickname', server_cert[0])

            # Fix the database permissions
            os.chmod(dirname + "/cert8.db", 0640)
            os.chmod(dirname + "/key3.db", 0640)
            os.chmod(dirname + "/secmod.db", 0640)

            pent = pwd.getpwnam("apache")
            os.chown(dirname + "/cert8.db", 0, pent.pw_gid )
            os.chown(dirname + "/key3.db", 0, pent.pw_gid )
            os.chown(dirname + "/secmod.db", 0, pent.pw_gid )

    except Exception, e:
        print "an unexpected error occurred: %s" % str(e)
        traceback.print_exc()
        return 1

    return 0

sys.exit(main())
