LIGHTY_SSL_CONF = "%s/lighttpd/conf.d/karesansui/ssl.conf" % VENDOR_SYSCONFDIR
LIGHTY_PORT_CONF = "%s/lighttpd/conf.d/karesansui/port.conf" % VENDOR_SYSCONFDIR
+PKI_DATA_PREFIX = VENDOR_SYSCONFDIR + "/pki"
+PKI_DATA_PREFIX = "/tmp/pki"
+PKI_CA_DIR = PKI_DATA_PREFIX + "/CA"
+PKI_CA_INFO = PKI_CA_DIR + "/ca.info"
+PKI_CA_PRIVATE_KEY = PKI_CA_DIR + "/cakey.pem"
+PKI_CA_SELFSIGNED_CRT = PKI_CA_DIR + "/cacert.pem"
+PKI_SERVER_INFO = PKI_DATA_PREFIX + "/libvirt/server.info"
+PKI_SERVER_PRIVATE_KEY = PKI_DATA_PREFIX + "/libvirt/private/serverkey.pem"
+PKI_SERVER_CRT = PKI_DATA_PREFIX + "/libvirt/servercert.pem"
+PKI_CLIENT_INFO = PKI_DATA_PREFIX + "/libvirt/client.info"
+PKI_CLIENT_PRIVATE_KEY = PKI_DATA_PREFIX + "/libvirt/private/clientkey.pem"
+PKI_CLIENT_CRT = PKI_DATA_PREFIX + "/libvirt/clientcert.pem"
+
COMMAND_CHKCONFIG = "/sbin/chkconfig"
COMMAND_SERVICE = "/sbin/service"
COMMAND_IPTABLES = "/sbin/iptables"
COMMAND_IPTABLES_SAVE = "/sbin/iptables-save"
+COMMAND_CERTTOOL = "certtool"
REQUIRE_SERVICES = [
"hde-libvirtd",
write_log(_("Leaving '%s'") % sys._getframe(0).f_code.co_name)
return True
+def process_init_certs(opts,p_callback=None):
+ write_log(_("Entering '%s'") % sys._getframe(0).f_code.co_name)
+
+ global logfile
+ from installer.utils import r_chmod, r_chgrp, generate_privkey, generate_ca_info, generate_ca_cert, generate_cert, generate_server_info, generate_client_info
+
+ title = _("Generating SSL Certificates...")
+
+ cert_opts = {
+ "country" :opts.country,
+ "state" :opts.state,
+ "locality" :opts.locality,
+ "organization" :opts.organization,
+ "cn" :opts.cn,
+ }
+
+ if p_callback: p_callback.start(text=title+"\n"+_("Creating a private key for your CA...")+"\n", size=100)
+ if p_callback: p_callback.update(10)
+ generate_privkey(PKI_CA_PRIVATE_KEY)
+ if p_callback: p_callback.update(20)
+ generate_ca_info(PKI_CA_INFO,cert_opts)
+ if p_callback: p_callback.update(30)
+ if os.path.exists(PKI_CA_PRIVATE_KEY) and os.path.exists(PKI_CA_INFO):
+ generate_ca_cert(PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY,PKI_CA_INFO)
+
+
+ if p_callback: p_callback.start(text=title+"\n"+_("Issuing server certificates...")+"\n", size=100)
+ if p_callback: p_callback.update(40)
+ generate_privkey(PKI_SERVER_PRIVATE_KEY)
+ if p_callback: p_callback.update(50)
+ generate_server_info(PKI_SERVER_INFO,cert_opts)
+ if p_callback: p_callback.update(60)
+ if os.path.exists(PKI_CA_SELFSIGNED_CRT) and os.path.exists(PKI_SERVER_PRIVATE_KEY) and os.path.exists(PKI_SERVER_INFO):
+ generate_cert(PKI_SERVER_CRT,PKI_SERVER_PRIVATE_KEY,PKI_SERVER_INFO,PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY)
+
+
+ if p_callback: p_callback.start(text=title+"\n"+_("Issuing client certificates...")+"\n", size=100)
+ if p_callback: p_callback.update(70)
+ generate_privkey(PKI_CLIENT_PRIVATE_KEY)
+ if p_callback: p_callback.update(80)
+ generate_client_info(PKI_CLIENT_INFO,cert_opts)
+ if p_callback: p_callback.update(90)
+ if os.path.exists(PKI_CA_SELFSIGNED_CRT) and os.path.exists(PKI_CLIENT_PRIVATE_KEY) and os.path.exists(PKI_CLIENT_INFO):
+ generate_cert(PKI_CLIENT_CRT,PKI_CLIENT_PRIVATE_KEY,PKI_CLIENT_INFO,PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY)
+
+ if p_callback: p_callback.end(100)
+
+ time.sleep(1)
+ write_log(_("Leaving '%s'") % sys._getframe(0).f_code.co_name)
+ return True
+
def process_create_admin(opts,p_callback=None):
write_log(_("Entering '%s'") % sys._getframe(0).f_code.co_name)
if p_callback: p_callback.update(cnt)
cnt = cnt + 1
- opts.dbinit = 0
+ opts.certinit = 0
+ opts.dbinit = 0
sh_config_write(opts.ini,opts)
if p_callback: p_callback.update(cnt)
def run(opts, **kwargs):
p_callback = kwargs.get('progress_callback', None)
- dbinit = opts.dbinit
+ certinit = opts.certinit
+ dbinit = opts.dbinit
+
+ if certinit is True:
+ process_init_certs(opts,p_callback)
if opts.action & FLAG_RPM_REBUILD:
process_rebuild_package(opts,p_callback)
self.wins = [
WelcomeWin,
AdminSettingWin,
+ TLSCertificatesSettingWin,
DatabaseSettingWin,
ConfirmWin,
FinishWin,
if size is None:
size = 1
- width = 55
+ width = 65
if (len(text) > width):
width = min(len(text), self.width)
return button
+class TLSCertificatesSettingWin(BaseWin):
+ def __init__(self, *kwargs):
+ BaseWin.__init__(self, *kwargs)
+ self.opts.fqdn = getattr(self.opts, 'fqdn', socket.gethostname())
+ self.opts.lang = getattr(self.opts, 'lang', os.environ["LANG"][0:5])
+
+ #import pdb; pdb.set_trace()
+ default_certinit = 0
+ infos = {}
+ if os.path.exists(PKI_CLIENT_INFO):
+ from installer.utils import sh_config_read
+ infos = sh_config_read(PKI_CLIENT_INFO," = ")
+ else:
+ default_certinit = 1
+
+ default_infos = {}
+ for opt_name in ["country","state","locality","organization","cn"]:
+ try:
+ default_infos[opt_name] = infos[opt_name]
+ except:
+ default_infos[opt_name] = ""
+ if opt_name == "country":
+ default_infos[opt_name] = "JP"
+ if opt_name == "organization":
+ default_infos[opt_name] = "Karesansui Project"
+
+ for opt_name in ["country","state","locality","organization","cn"]:
+ exec("self.opts.%s = getattr(self.opts, '%s', '%s')" % (opt_name, opt_name, default_infos[opt_name]))
+
+ self.opts.certinit = getattr(self.opts, 'certinit', default_certinit)
+
+ def __call__(self):
+ current_page = "[%d/%d]" % (self.ui.page+1, len(self.ui.wins))
+ width = 25
+
+ label_country = snack.Label(_("Country Name (ISO 2 letter code)"))
+ country = snack.Entry(3, text=self.opts.country, hidden=False)
+
+ label_state = snack.Label(_("State or Province Name (full name)"))
+ state = snack.Entry(width, text=self.opts.state, hidden=False)
+
+ label_locality = snack.Label(_("Locality Name (e.g. city)"))
+ locality = snack.Entry(width, text=self.opts.locality, hidden=False)
+
+ label_organization = snack.Label(_("Organization Name (eg, company)"))
+ organization = snack.Entry(width, text=self.opts.organization, hidden=False)
+
+ label_cn = snack.Label(_("Common Name (fully qualified domain name)"))
+ cn = snack.Entry(width, text=self.opts.fqdn, hidden=False)
+
+ cb = snack.Checkbox(_("Initialize SSL certificates settings?"), self.opts.certinit)
+
+ sub_g = snack.Grid(2, 5)
+ sub_g.setField(label_country, 0, 0, anchorLeft=1)
+ sub_g.setField(country, 1, 0, anchorLeft=1, padding=(1, 0, 0, 0))
+ sub_g.setField(label_state, 0, 1, anchorLeft=1, padding=(0, 0, 0, 0))
+ sub_g.setField(state, 1, 1, anchorLeft=1, padding=(1, 0, 0, 0))
+ sub_g.setField(label_locality, 0, 2, anchorLeft=1, padding=(0, 0, 0, 0))
+ sub_g.setField(locality, 1, 2, anchorLeft=1, padding=(1, 0, 0, 0))
+ sub_g.setField(label_organization, 0, 3, anchorLeft=1, padding=(0, 0, 0, 0))
+ sub_g.setField(organization, 1, 3, anchorLeft=1, padding=(1, 0, 0, 0))
+ sub_g.setField(label_cn, 0, 4, anchorLeft=1, padding=(0, 1, 0, 0))
+ sub_g.setField(cn, 1, 4, anchorLeft=1, padding=(1, 1, 0, 0))
+
+ buttons = snack.ButtonBar(self.screen, [OK_BUTTON, BACK_BUTTON, CANCEL_BUTTON], compact=BUTTON_COMPACT)
+
+ g = snack.GridFormHelp(self.screen, _("TLS certificates setting") + current_page, None, 1, 3)
+ g.add(sub_g, 0, 0, growx=1)
+ g.add(cb, 0, 1, growx=1, padding = (0, 1, 0, 0))
+ g.add(buttons, 0, 2, growx=1, padding = (0, 1, 0, 0))
+
+ button = buttons.buttonPressed(g.runOnce())
+
+ if button is None:
+ button = OK_VALUE
+
+ if button is OK_VALUE:
+
+ """ Check country code """
+ input_country = country.value()
+ self.opts.country = input_country
+
+ if input_country == '':
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is empty") % _('Country Name (ISO 2 letter code)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ regex = "^[A-Z]{2}$"
+ m = re.compile(regex).search(input_country)
+ if not m:
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is in an invalid format.") % _('Country Name (ISO 2 letter code)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ """ Check state name """
+ input_state = state.value()
+ self.opts.state = input_state
+
+ if input_state == '':
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is empty") % _('State or Province Name (full name)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ regex = "^[-a-zA-Z0-9 ]{1,128}$"
+ m = re.compile(regex).search(input_state)
+ if not m:
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is in an invalid format.") % _('State or Province Name (full name)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ """ Check locality name """
+ input_locality = locality.value()
+ self.opts.locality = input_locality
+
+ if input_locality == '':
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is empty") % _('Locality Name (e.g. city)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ regex = "^[-a-zA-Z0-9 ]{1,128}$"
+ m = re.compile(regex).search(input_locality)
+ if not m:
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is in an invalid format.") % _('Locality Name (e.g. city)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ """ Check organization name """
+ input_organization = organization.value()
+ self.opts.organization = input_organization
+
+ if input_organization == '':
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is empty") % _('Organization Name (eg, company)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ regex = "^[-a-zA-Z0-9 .,\(\)]{1,64}$"
+ m = re.compile(regex).search(input_locality)
+ if not m:
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is in an invalid format.") % _('Organization Name (eg, company)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ """ Check common name """
+ input_cn = cn.value()
+ self.opts.cn = input_cn
+
+ if input_cn == '':
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), _("%s is empty") % _('Common Name (fully qualified domain name)'), [OK_BUTTON], self.ui.width)
+ return -1
+
+ input_cn_error_msg = ""
+ if input_cn != "localhost" and not re.compile(r'.*\.').match(input_cn):
+ input_cn_error_msg = _('%s must include at least one dot . character.') % (_('Common Name (fully qualified domain name)'),)
+
+ if re.compile(r'(^\.|.*\.$|.*\.\.|.*-\.|.*\.-|^-|.*-$)', re.VERBOSE).match(input_cn):
+ input_cn_error_msg = _('%s must be specified like %s.') % (_('Common Name (fully qualified domain name)'), "host.example.com",)
+
+ invalid_input_cn_regex = "[^-a-zA-Z0-9\.]"
+ m = re.compile(invalid_input_cn_regex).search(input_cn)
+ if m:
+ input_cn_error_msg = _('%s\nAvailable characters are %s') % (_('Common Name (fully qualified domain name)'),_('a-z A-Z 0-9 . -'))
+ if input_cn_error_msg != "":
+ ret = snack.ButtonChoiceWindow(self.screen, _("ERROR"), input_cn_error_msg, [OK_BUTTON], self.ui.width)
+ return -1
+
+ self.opts.certinit = cb.selected()
+
+ return button
+
class DatabaseSettingWin(BaseWin):
def __init__(self, *kwargs):
BaseWin.__init__(self, *kwargs)
return True
-def sh_config_read(filename):
+def sh_config_read(filename,separator='='):
ret = {}
try:
fp = open(filename,"r")
line = line.strip()
if len(line) <= 0 or line[0] == "#":
continue
- key, value = line.split('=',1)
- ret[key] = value
+ try:
+ key, value = line.split(separator,1)
+ try:
+ ret[key]
+ if type(ret[key]) is not list:
+ old = ret[key]
+ ret[key] = [old]
+ ret[key].append(value)
+ except:
+ ret[key] = value
+ except:
+ pass
fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
fp.close()
except:
return ret
-def sh_config_write(filename,opts):
+def sh_config_write(filename,opts,separator='='):
ret = True
res = {}
fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
for k,v in res.iteritems():
if type(v) == str and k[0:2] != "__" and k[0:4] != "pass":
- fp.write("%s=%s\n" % (k, v,))
+ fp.write("%s%s%s\n" % (k, separator, v,))
+ if type(v) == list:
+ for v2 in v:
+ fp.write("%s%s%s\n" % (k, separator, v2,))
fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
fp.close()
- except:
+ except TypeError, e:
+ pass
+ except IOError, e:
+ raise "%s" % e
ret = False
return ret
return True
+def append_random_entropy(count=3000):
+ try:
+ import installer.extensions.random_entropy
+ return installer.extensions.random_entropy.appendEntropy(count)
+ except:
+ import extensions.random_entropy
+ return extensions.random_entropy.appendEntropy(count)
+
+import threading
+class Append_Random_Entropy_Child_t(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self)
+ def run(self):
+ import time
+ time.sleep(3)
+ append_random_entropy(3000)
+
+def execute_certtool(opts,outfile="/dev/stdout"):
+ retval = True
+
+ outdir = os.path.dirname(outfile)
+ if os.path.exists(outdir) is False:
+ os.makedirs(outdir)
+
+ child_t = Append_Random_Entropy_Child_t()
+ child_t.start()
+
+ command_args = opts
+ command_args.insert(0,COMMAND_CERTTOOL)
+ (ret,res) = execute_command(command_args)
+
+ child_t.join()
+
+ if ret == 0:
+ try:
+ fp = open(outfile,"w")
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+ for line in res:
+ fp.write(line+"\n")
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+ fp.close()
+ except:
+ retval = False
+ else:
+ retval = False
+
+ return retval
+
+def generate_privkey(outfile="/dev/stdout"):
+ opts = [ "--generate-privkey" ]
+ execute_certtool(opts,outfile)
+ return os.path.exists(outfile)
+
+def generate_ca_info(outfile,opts):
+ retval = True
+
+ outdir = os.path.dirname(outfile)
+ if os.path.exists(outdir) is False:
+ os.makedirs(outdir)
+
+ try:
+ fp = open(outfile,"w")
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+ fp.write("""
+cn = %s
+ca
+cert_signing_key
+""" % (opts["cn"],));
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+ fp.close()
+ except:
+ retval = False
+
+ return retval
+
+def generate_ca_cert(outfile,privkey,info):
+ opts = [ "--generate-self-signed",
+ "--load-privkey",
+ privkey,
+ "--template",
+ info,
+ ]
+ execute_certtool(opts,outfile)
+ return os.path.exists(outfile)
+
+def generate_server_info(outfile,opts):
+ retval = True
+
+ outdir = os.path.dirname(outfile)
+ if os.path.exists(outdir) is False:
+ os.makedirs(outdir)
+
+ try:
+ fp = open(outfile,"w")
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+ fp.write("""
+organization = %s
+cn = %s
+tls_www_server
+encryption_key
+signing_key
+""" % (opts["organization"], opts["cn"],));
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+ fp.close()
+ except:
+ retval = False
+
+ return retval
+
+def generate_cert(outfile,privkey,info,ca_cert,ca_privkey):
+ opts = [ "--generate-certificate",
+ "--load-privkey",
+ privkey,
+ "--load-ca-certificate",
+ ca_cert,
+ "--load-ca-privkey",
+ ca_privkey,
+ "--template",
+ info,
+ ]
+ execute_certtool(opts,outfile)
+ return os.path.exists(outfile)
+
+def generate_client_info(outfile,opts):
+ retval = True
+
+ outdir = os.path.dirname(outfile)
+ if os.path.exists(outdir) is False:
+ os.makedirs(outdir)
+
+ try:
+ fp = open(outfile,"w")
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+ fp.write("""
+country = %s
+state = %s
+locality = %s
+organization = %s
+cn = %s
+tls_www_client
+encryption_key
+signing_key
+""" % (opts["country"],opts["state"],opts["locality"],opts["organization"],opts["cn"],));
+ fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+ fp.close()
+ except:
+ retval = False
+
+ return retval
+
+def generate_ssl_certificates(opts):
+
+ # Setting up a Certificate Authority (CA)
+ generate_privkey(PKI_CA_PRIVATE_KEY)
+ generate_ca_info(PKI_CA_INFO,opts)
+ if os.path.exists(PKI_CA_PRIVATE_KEY) and os.path.exists(PKI_CA_INFO):
+ generate_ca_cert(PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY,PKI_CA_INFO)
+
+ # Issuing server certificates
+ generate_privkey(PKI_SERVER_PRIVATE_KEY)
+ generate_server_info(PKI_SERVER_INFO,opts)
+ if os.path.exists(PKI_CA_SELFSIGNED_CRT) and os.path.exists(PKI_SERVER_PRIVATE_KEY) and os.path.exists(PKI_SERVER_INFO):
+ generate_cert(PKI_SERVER_CRT,PKI_SERVER_PRIVATE_KEY,PKI_SERVER_INFO,PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY)
+
+ # Issuing client certificates
+ generate_privkey(PKI_CLIENT_PRIVATE_KEY)
+ generate_client_info(PKI_CLIENT_INFO,opts)
+ if os.path.exists(PKI_CA_SELFSIGNED_CRT) and os.path.exists(PKI_CLIENT_PRIVATE_KEY) and os.path.exists(PKI_CLIENT_INFO):
+ generate_cert(PKI_CLIENT_CRT,PKI_CLIENT_PRIVATE_KEY,PKI_CLIENT_INFO,PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY)
+