Sure, here is my first version (still coding the second version which has flags to enable-disable features), it shows you the base idea and works with pure-ftpd, courier-pop3 and courier-imap, I'll post the code for exim by hand.
Code:
<?php
/*
Software.....: updatecerts.php
License......: Public Domain
Version......: 1.0
Description..: Generate certificates for courier-imap/pop3
Coded by.....: sehh
*/
// == Configuration options ==
// Enable debug output (true/false)
$debug = true;
// Don't make any changes, just print output only (true/false)
$nochanges = true;
// Default cPanel/WHM files & paths (strings, paths end with /)
$ssldomains = "/etc/ssldomains";
$keydir = "/usr/share/ssl/private/";
$certdir = "/usr/share/ssl/certs/";
$imapcfg = "/usr/lib/courier-imap/etc/imapd-ssl";
$pop3cfg = "/usr/lib/courier-imap/etc/pop3d-ssl";
// == No need to change anything below this point!
// Load domains with SSL certificates
if(file_exists($ssldomains)===true) {
$domains = file_get_contents($ssldomains);
$domains = str_replace("\r", "", $domains);
$domains = str_replace("\n\n", "\n", $domains);
$domains = preg_replace("/\n$/", "", $domains);
$domains = explode("\n", $domains);
if(sizeof($domains)==0) {
echo "[ERROR] No SSL domains found\n";
exit(2);
}
if($debug==true)
echo "[DEBUG] Loaded ".sizeof($domains)." lines from ".$ssldomains."\n";
} else {
echo "[ERROR] SSL domains file not found\n";
exit(2);
}
// Find the existing system-wide IMAP certificate
$rc = exec('/bin/grep "^TLS_CERTFILE" '.$imapcfg);
if(strpos($rc, "TLS_CERTFILE=")===false) {
echo "[ERROR] IMAP TLS certificate not found\n";
exit(2);
}
$certimap = substr($rc, strpos($rc, "TLS_CERTFILE=")+13);
$certimappath = dirname($certimap)."/";
if($debug==true) {
echo "[DEBUG] System-wide IMAP certificate: ".$certimap."\n";
echo "[DEBUG] IMAP certificate path: ".$certimappath."\n";
}
// Find the existing system-wide POP3 certificate
$rc = exec('/bin/grep "^TLS_CERTFILE" '.$pop3cfg);
if(strpos($rc, "TLS_CERTFILE=")===false) {
echo "[ERROR] POP3 TLS certificate not found\n";
exit(2);
}
$certpop3 = substr($rc, strpos($rc, "TLS_CERTFILE=")+13);
$certpop3path = dirname($certpop3)."/";
if($debug==true) {
echo "[DEBUG] System-wide POP3 certificate: ".$certpop3."\n";
echo "[DEBUG] POP3 certificate path: ".$certpop3path."\n";
}
// Start the conversion for each SSL domain
$convertedips = array();
for($i=0;$i<sizeof($domains);$i++) {
$pos = strpos($domains[$i], ":");
if($domains[$i]=="" || $pos===false)
continue;
// Load domain and the equivalent IP address
$domain = substr($domains[$i], 0, $pos);
$ipaddress = trim(substr($domains[$i], $pos+1));
if($debug==true)
echo "\t[DEBUG] Converting certificates for domain: ".$domain." with IP address: ".$ipaddress."\n";
// Load existing private key
$key = $keydir.$domain.".key";
if(file_exists($key)===false) {
echo "\t[ERROR] Private key file for domain ".$domain." not found (".$key.") - Domain skipped!\n";
continue;
} elseif($debug==true) {
echo "\t[DEBUG] Private key file found for domain ".$domain."\n";
}
// Load existing certificate
$cert = $certdir.$domain.".crt";
if(file_exists($cert)===false) {
echo "\t[ERROR] Certificate file for domain ".$domain." not found (".$cert.") - Domain skipped!\n";
continue;
} elseif($debug==true) {
echo "\t[DEBUG] Certificate key file found for domain ".$domain."\n";
}
// Generate the final PEM files (courier IMAP/POP3)
$pemimap = $certimap.".".$ipaddress;
if($debug==true)
echo "\t[DEBUG] IMAP PEM file for domain ".$domain.": ".$pemimap."\n";
$pempop3 = $certpop3.".".$ipaddress;
if($debug==true)
echo "\t[DEBUG] POP3 PEM file for domain ".$domain.": ".$pempop3."\n";
if($nochanges==false) {
// Generate IMAP PEM file
exec("rm -rf ".$pemimap);
exec("touch ".$pemimap);
exec("chown root:wheel ".$pemimap);
exec("chmod u+rw-x,g+wr-x,o-wrx ".$pemimap);
exec("cat ".$key." > ".$pemimap);
exec("cat ".$cert." >> ".$pemimap);
// Generate POP PEM file
exec("rm -rf ".$pempop3);
exec("touch ".$pempop3);
exec("chown root:wheel ".$pempop3);
exec("chmod u+rw-x,g+wr-x,o-wrx ".$pempop3);
exec("cat ".$key." > ".$pempop3);
exec("cat ".$cert." >> ".$pempop3);
}
if($debug==true)
echo "\t[DEBUG] Combine ".$key." and ".$cert." into ".$pemimap." and ".$pempop3."\n";
// Store the processed IP address
$convertedips[] = $ipaddress;
echo "\t\n";
}
if($debug==true)
echo "[DEBUG] Converted a total of ".sizeof($convertedips)." domains\n";
// Scanning for stale IMAP PEM files
if($handle = opendir($certimappath)) {
while(false!==($file = readdir($handle))) {
$pos = strpos($file, "imapd.pem.");
if($pos!==false && $pos===0) {
$ip = substr($file, 10);
if(strlen($ip)>0 && in_array($ip, $convertedips)==false) {
if($nochanges==false)
exec("rm -rf ".$certimappath.$file);
if($debug==true)
echo "[DEBUG] Found stale IMAP PEM file: ".$certimappath.$file."\n";
}
}
}
closedir($handle);
}
// Scanning for stale POP3 PEM files
if($handle = opendir($certpop3path)) {
while(false!==($file = readdir($handle))) {
$pos = strpos($file, "pop3d.pem.");
if($pos!==false && $pos===0) {
$ip = substr($file, 10);
if(strlen($ip)>0 && in_array($ip, $convertedips)==false) {
if($nochanges==false)
exec("rm -rf ".$certpop3path.$file);
if($debug==true)
echo "[DEBUG] Found stale POP3 PEM file: ".$certpop3path.$file."\n";
}
}
}
closedir($handle);
}
?>
For exim, you only need to change two lines, I'm pasting a patch here instead of adding it with my script above.
Code:
--- exim.conf.orig 2011-03-30 22:47:20.000000000 +0300
+++ exim.conf 2011-03-31 13:43:00.000000000 +0300
@@ -240,13 +260,15 @@
#sender_host_reject = +include_unknown:lsearch*;/etc/spammers
-tls_certificate = /etc/exim.crt
-tls_privatekey = /etc/exim.key
+#tls_certificate = /etc/exim.crt
+#tls_privatekey = /etc/exim.key
+tls_certificate = /usr/share/ssl/certs/${lookup{$interface_address}lsearch{/etc/domainips}{$value}{$primary_hostname}}.crt
+tls_privatekey = /usr/share/ssl/private/${lookup{$interface_address}lsearch{/etc/domainips}{$value}{$primary_hostname}}.key
tls_advertise_hosts = *
helo_accept_junk_hosts = *