diff --git a/debian/alternc-ssl.postinst b/debian/alternc-ssl.postinst index 763c4b76..f2eb00d5 100755 --- a/debian/alternc-ssl.postinst +++ b/debian/alternc-ssl.postinst @@ -14,9 +14,6 @@ case "$1" in echo "Installing mysql table" mysql --defaults-file=/etc/alternc/my.cnf -f < /usr/share/alternc/install/ssl.sql || true - # Create default quota "ssl" with value 0 - mysql --defaults-file=/etc/alternc/my.cnf -fBse "INSERT INTO defquotas VALUES ('ssl', 0, 'default')" || true - echo "installing required apache modules" a2enmod ssl diff --git a/debian/alternc-ssl.postrm b/debian/alternc-ssl.postrm index 3a8bf899..f12f38e0 100755 --- a/debian/alternc-ssl.postrm +++ b/debian/alternc-ssl.postrm @@ -5,19 +5,28 @@ MENUFILE="/etc/alternc/menulist.txt" case "$1" in remove) - alternc.install || true # don't fail removal if alternc.install bails out # TODO : we don't purge *-ssl vhosts or *-ssl templates, they may break the hosting ... if [ -e "$CONFIGFILE" -a -x "/usr/bin/mysql" ]; then mysql --defaults-file=${CONFIGFILE} -f -e "DELETE FROM domaines_type WHERE name IN ('vhost-ssl','vhost-mixssl','roundcube-ssl','squirrelmail-ssl','panel-ssl','php52-ssl','php52-mixssl');" mysql --defaults-file=${CONFIGFILE} -f -e "UPDATE sub_domaines SET web_action='DELETE' WHERE type IN ('vhost-ssl','vhost-mixssl','roundcube-ssl','squirrelmail-ssl','panel-ssl','php52-ssl','php52-mixssl');" fi + echo -e "\033[31m**********************************************" + echo "* *" + echo "* ALTERNC-SSL ACTION REQUESTED *" + echo "* *" + echo "* Please run alternc.install to fully remove *" + echo "* *" + echo "**********************************************" + echo -e "\033[0m" + ;; purge) # Purge the certificate and alias table: if [ -e "$CONFIGFILE" -a -x "/usr/bin/mysql" ]; then mysql --defaults-file=${CONFIGFILE} -f -e "DROP TABLE IF EXISTS certificate;" mysql --defaults-file=${CONFIGFILE} -f -e "DROP TABLE IF EXISTS certif_alias;" + mysql --defaults-file=${CONFIGFILE} -f -e "DROP TABLE IF EXISTS certif_hosts;" fi ;; esac diff --git a/ssl/Makefile b/ssl/Makefile index aa8a8cc9..45a3883b 100755 --- a/ssl/Makefile +++ b/ssl/Makefile @@ -19,6 +19,7 @@ install: install -m 0644 -g root -o root ssl.sql $(DESTDIR)/usr/share/alternc/install/ install -m 0755 -g root -o root alternc-ssl.install.php $(DESTDIR)/usr/lib/alternc/install.d/alternc-ssl + install -m 0644 -g root -o root README.txt $(DESTDIR)/var/lib/alternc/ssl/private/ # incron install -m 0755 -g root -o root ssl_alias_manager.sh $(DESTDIR)/usr/lib/alternc/ diff --git a/ssl/README.txt b/ssl/README.txt new file mode 100644 index 00000000..fdcd94bb --- /dev/null +++ b/ssl/README.txt @@ -0,0 +1,4 @@ + +This folder will contains the SSL certificates, +chained certificates and private keys of VHOSTS +used by Apache to serve HTTPS pages. diff --git a/ssl/alternc-ssl.install.php b/ssl/alternc-ssl.install.php index f43c6cca..cde0ae8b 100644 --- a/ssl/alternc-ssl.install.php +++ b/ssl/alternc-ssl.install.php @@ -63,7 +63,7 @@ if ($argv[1] == "before-reload") { } else { $found = false; while ($s = fgets($f, 1024)) { - if (preg_match("#NameVirtualHost.*443#", $s)) { + if (preg_match(":[^#]*NameVirtualHost.*443:", $s)) { $found = true; break; } diff --git a/ssl/hosting_vhost-ssl.sh b/ssl/hosting_vhost-ssl.sh index 29e0562a..9680d90d 100755 --- a/ssl/hosting_vhost-ssl.sh +++ b/ssl/hosting_vhost-ssl.sh @@ -20,6 +20,11 @@ // Bootstrap require_once("/usr/share/alternc/panel/class/config_nochk.php"); +if (!isset($ssl)) { + echo "OUPS: hosting_vhost-ssl.sh launched, but ssl module not installed, exiting\n"; + exit(); +} + if (!isset($argv[1])) { echo "FATAL: must be launched from functions_hosting.sh !\n"; exit(); diff --git a/ssl/panel/admin/ssl_delete.php b/ssl/panel/admin/ssl_delete.php new file mode 100644 index 00000000..5a040ab3 --- /dev/null +++ b/ssl/panel/admin/ssl_delete.php @@ -0,0 +1,48 @@ + array("post", "integer", ""), + "delete" => array("post", "string", ""), + "confirm" => array("post", "string", ""), +); +getFields($fields); + +if (!isset($delete)) { + require_once("ssl_list.php"); + exit(); +} + +$ok = $ssl->del_certificate($id); + +if ($ok) $info=_("Your SSL Certificate has been deleted"); + +$error = $err->errstr(); + +require_once("ssl_list.php"); + diff --git a/ssl/panel/admin/ssl_finalize.php b/ssl/panel/admin/ssl_finalize.php index 8683577e..33471983 100644 --- a/ssl/panel/admin/ssl_finalize.php +++ b/ssl/panel/admin/ssl_finalize.php @@ -30,9 +30,15 @@ $fields = array( "id" => array("post", "integer", ""), "crt" => array("post", "string", ""), "chain" => array("post", "string", ""), + "delete" => array("post","string",""), ); getFields($fields); +if ($delete!="") { + require_once("ssl_delete.php"); + exit(); +} + $cert = $ssl->finalize($id, $crt, $chain); $error = $err->errstr(); diff --git a/ssl/panel/admin/ssl_list.php b/ssl/panel/admin/ssl_list.php index f0d97bda..b88f736a 100644 --- a/ssl/panel/admin/ssl_list.php +++ b/ssl/panel/admin/ssl_list.php @@ -50,9 +50,15 @@ if (!$error) $astatus = array( $ssl::STATUS_PENDING => _("Pending Certificate"), $ssl::STATUS_OK => _("Valid"), - $ssl::STATUS_EXPIRED => ("Expired"), + $ssl::STATUS_EXPIRED => "" . _("Expired") . "", ); +$vhosts = $ssl->get_vhosts(); +foreach ($vhosts as $v) { + if ($v["certif"] == 0) { + $info=_("Some of your hosting are using a self-signed certificate.
Your browser will not let you surf those domains properly
To fix this, buy a properly signed certificate")."
".$info; + } +} include_once("head.php"); if ($error) { @@ -76,7 +82,7 @@ if ($info) { "/> - +
">
- + - - - - - - + + + + + - + "; + echo ""; + echo ""; + echo ""; + } + } + ?> +
" . _("(shared)") . ""; - ?>" . _("(shared)") . ""; + ?>
+ "; + echo format_date(_('%3$d-%2$d-%1$d %4$d:%5$d'), date("Y-m-d H:i:s", $val["validendts"])); + if ($val["validendts"] < (time() + 86400 * 31)) + echo ""; + ?>

+
" . $v["fqdn"] . "
\n"; + } + } + ?>
" . _("This hosting has no valid certificate
a self-signed one has been created") . "
" . $v["fqdn"] . "
+

 

+ diff --git a/ssl/panel/admin/ssl_view.php b/ssl/panel/admin/ssl_view.php index 519944ce..3e19be60 100644 --- a/ssl/panel/admin/ssl_view.php +++ b/ssl/panel/admin/ssl_view.php @@ -81,6 +81,10 @@ if ($cert["status"] == $ssl::STATUS_PENDING) {

"/>   " onclick="document.location = 'ssl_list.php'"/> +

+ " onclick="return confirm('');"/>

@@ -103,7 +107,9 @@ if ($cert["status"] == $ssl::STATUS_PENDING) { -

+

+ "/> +

@@ -201,8 +207,20 @@ if ($cert["status"] == $ssl::STATUS_PENDING) { } } } + if ($cert["uid"] == $cuid) { ?> +

+ " onclick="return confirm('');"/> + +

+ + + diff --git a/ssl/panel/class/m_ssl.php b/ssl/panel/class/m_ssl.php index 01187857..8076c1f8 100644 --- a/ssl/panel/class/m_ssl.php +++ b/ssl/panel/class/m_ssl.php @@ -44,7 +44,7 @@ class m_ssl { const FILTER_SHARED = 8; const SSL_INCRON_FILE = "/var/run/alternc/ssl/generate_certif_alias"; - var $myDomainesTypes = array("vhost-ssl", "vhost-mixssl", "panel-ssl", "roundcube-ssl", "squirrelmail-ssl","php52-ssl","php52-mixssl"); + var $myDomainesTypes = array("vhost-ssl", "vhost-mixssl", "panel-ssl", "roundcube-ssl", "squirrelmail-ssl", "php52-ssl", "php52-mixssl"); const KEY_REPOSITORY = "/var/lib/alternc/ssl/private"; @@ -109,6 +109,8 @@ class m_ssl { function get_list(&$filter = null) { global $db, $err, $cuid; $err->log("ssl", "get_list"); + // Expire expired certificates: + $db->query("UPDATE certificates SET status=".self::STATUS_EXPIRED." WHERE status=".self::STATUS_OK." AND validendlog("ssl", "get_vhosts"); + $r=array(); + $db->query("SELECT ch.*, UNIX_TIMESTAMP(c.validstart) AS validstartts, UNIX_TIMESTAMP(c.validend) AS validendts, sd.domaine, sd.sub " + . "FROM certif_hosts ch LEFT JOIN certificates c ON ch.certif=c.id " + . ", sub_domaines sd WHERE sd.id=ch.sub AND ch.uid=$cuid " + . "ORDER BY sd.domaine, sd.sub;"); + if ($db->num_rows()) { + while ($db->next_record()) { + $r[] = $db->Record; + } + return $r; + } else { + $err->raise("ssl", _("You currently have no hosting using SSL certificate")); + return array(); + } + } + // ----------------------------------------------------------------- /** Generate a new CSR, a new Private RSA Key, for FQDN. * @param $fqdn string the FQDN of the domain name for which we want a CSR. @@ -212,6 +237,27 @@ class m_ssl { return $db->Record; } + // ----------------------------------------------------------------- + /** Delete a Certificate for the current user. + * @return boolean TRUE if the certificate has been deleted successfully. + */ + function del_certificate($id) { + global $db, $err, $cuid; + $err->log("ssl", "del_certificate"); + $id = intval($id); + $db->query("SELECT * FROM certificates WHERE uid='$cuid' AND id='$id';"); + if (!$db->next_record()) { + $err->raise("ssl", _("Can't find this Certifcate")); + return false; + } + $fqdn = $db->Record["fqdn"]; + $altnames = $db->Record["altnames"]; + $db->query("DELETE FROM certificates WHERE uid='$cuid' AND id='$id';"); + // Update any existing VHOST using this cert/key + $this->updateTrigger($fqdn, $altnames); + return true; + } + // ----------------------------------------------------------------- /** Share (or unshare) an ssl certificate * @param $id integer the id of the certificate in the table. @@ -229,7 +275,7 @@ class m_ssl { } if ($action) { $action = 1; - $this->updateTrigger($db->Record["fqdn"],$db->Record["altnames"]); + $this->updateTrigger($db->Record["fqdn"], $db->Record["altnames"]); } else { $action = 0; } @@ -307,7 +353,7 @@ class m_ssl { $err->raise("ssl", _("Can't save the Key/Crt/Chain now. Please try later.")); return false; } - $this->updateTrigger($fqdn,$altnames); + $this->updateTrigger($fqdn, $altnames); return $id; } @@ -344,7 +390,7 @@ class m_ssl { $err->raise("ssl", _("Can't save the Crt/Chain now. Please try later.")); return false; } - $this->updateTrigger($fqdn,$altnames); + $this->updateTrigger($fqdn, $altnames); return $certid; } @@ -434,10 +480,17 @@ class m_ssl { // Save crt/key/chain into KEY_REPOSITORY $CRTDIR = self::KEY_REPOSITORY . "/" . $subdom["compte"]; @mkdir($CRTDIR); - file_put_contents($CRTDIR . "/" . $fqdn . ".crt", $cert["sslcrt"]); - file_put_contents($CRTDIR . "/" . $fqdn . ".key", $cert["sslkey"]); - if (isset($cert["sslchain"]) && $cert["sslchain"]) { - file_put_contents($CRTDIR . "/" . $fqdn . ".chain", $cert["sslchain"]); + // Don't *overwrite* existing self-signed certificates in KEY_REPOSITORY + if (isset($cert["selfsigned"]) && + file_exists($CRTDIR . "/" . $fqdn . ".crt") && + file_exists($CRTDIR . "/" . $fqdn . ".key")) { + echo "Self-Signed certificate reused...\n"; + } else { + file_put_contents($CRTDIR . "/" . $fqdn . ".crt", $cert["sslcrt"]); + file_put_contents($CRTDIR . "/" . $fqdn . ".key", $cert["sslkey"]); + if (isset($cert["sslchain"]) && $cert["sslchain"]) { + file_put_contents($CRTDIR . "/" . $fqdn . ".chain", $cert["sslchain"]); + } } // edit apache conf file to set the certificate: $s = file_get_contents($TARGET_FILE); @@ -449,7 +502,35 @@ class m_ssl { $s = str_replace("%%CHAINLINE%%", "", $s); } file_put_contents($TARGET_FILE, $s); + // Edit certif_hosts: + $db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";"); + $db->query("INSERT INTO certif_hosts SET " + . "sub=" . intval($subdom["id"]) . ", " + . "certif=" . intval($cert["id"]) . ", " + . "uid=" . intval($subdom["compte"]) . ";"); } // action==create + if ($action == "delete") { + $err->log("ssl", "update_domain:DELETE($action,$type,$fqdn)"); + $offset = 0; + $found = false; + do { // try each subdomain (strtok-style) and search them in sub_domaines table: + $db->query("SELECT * FROM sub_domaines WHERE " + . "sub='" . substr($fqdn, 0, $offset) . "' AND domaine='" . substr($fqdn, $offset + ($offset != 0)) . "' " + . "AND web_action NOT IN ('','OK') AND type='" . $type . "';"); + if ($db->next_record()) { + $found = true; + break; + } + $offset = strpos($fqdn, ".", $offset); + } while (true); + if (!$found) { + echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n"; + return; + } + // found and $db point to it: + $subdom = $db->Record; + $db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";"); + } } // ---------------------------------------------------------------- @@ -709,7 +790,8 @@ class m_ssl { openssl_x509_export($crt, $crtout); return array("id" => 0, "status" => 1, "shared" => 0, "fqdn" => $fqdn, "altnames" => "", "validstart" => date("Y-m-d H:i:s"), "validend" => date("Y-m-d H:i:s", time() + 86400 * 10 * 365.249), - "sslcsr" => $csrout, "sslcrt" => $crtout, "sslkey" => $privKey, "sslchain" => "" + "sslcsr" => $csrout, "sslcrt" => $crtout, "sslkey" => $privKey, "sslchain" => "", + "selfsigned" => true, ); } diff --git a/ssl/ssl.sql b/ssl/ssl.sql index 7bdca3d7..285d39b8 100644 --- a/ssl/ssl.sql +++ b/ssl/ssl.sql @@ -19,7 +19,6 @@ CREATE TABLE `certificates` ( KEY `ssl_action` (`ssl_action`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE TABLE IF NOT EXISTS `certif_alias` ( `name` varchar(255) NOT NULL, `content` text NOT NULL, @@ -28,3 +27,13 @@ CREATE TABLE IF NOT EXISTS `certif_alias` ( PRIMARY KEY (`name`), KEY `uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Global aliases defined for SSL certificates FILE validation processes'; + +CREATE TABLE IF NOT EXISTS `certif_hosts` ( + `certif` int(10) unsigned NOT NULL, + `sub` int(10) unsigned NOT NULL, + `uid` int(10) unsigned NOT NULL, + PRIMARY KEY (`certif`,`sub`), + KEY `uid` (`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='VHosts of a user using defined or self-signed certificates'; + +INSERT IGNORE INTO defquotas VALUES ('ssl', 0, 'default');