1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
---------------------------------------------------------------------- |
5
|
|
|
AlternC - Web Hosting System |
6
|
|
|
Copyright (C) 2000-2014 by the AlternC Development Team. |
7
|
|
|
https://alternc.org/ |
8
|
|
|
---------------------------------------------------------------------- |
9
|
|
|
LICENSE |
10
|
|
|
|
11
|
|
|
This program is free software; you can redistribute it and/or |
12
|
|
|
modify it under the terms of the GNU General Public License (GPL) |
13
|
|
|
as published by the Free Software Foundation; either version 2 |
14
|
|
|
of the License, or (at your option) any later version. |
15
|
|
|
|
16
|
|
|
This program is distributed in the hope that it will be useful, |
17
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
18
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19
|
|
|
GNU General Public License for more details. |
20
|
|
|
|
21
|
|
|
To read the license please visit http://www.gnu.org/copyleft/gpl.html |
22
|
|
|
---------------------------------------------------------------------- |
23
|
|
|
Purpose of file: Manage SSL Certificates and HTTPS Hosting |
24
|
|
|
---------------------------------------------------------------------- |
25
|
|
|
*/ |
26
|
|
|
|
27
|
|
|
// ----------------------------------------------------------------- |
28
|
|
|
/** |
29
|
|
|
* SSL Certificates management class |
30
|
|
|
*/ |
31
|
|
|
class m_ssl { |
32
|
|
|
|
33
|
|
|
const STATUS_PENDING = 0; // we have a key / csr, but no CRT |
34
|
|
|
const STATUS_OK = 1; // we have the key, csr, crt, chain |
35
|
|
|
const STATUS_EXPIRED = 99; // The certificate is now expired. |
36
|
|
|
|
37
|
|
|
public $error = ""; |
38
|
|
|
|
39
|
|
|
// Includes one or more of those flags to see only those certificates |
40
|
|
|
// when listing them: |
41
|
|
|
const FILTER_PENDING = 1; |
42
|
|
|
const FILTER_OK = 2; |
43
|
|
|
const FILTER_EXPIRED = 4; |
44
|
|
|
const FILTER_SHARED = 8; |
45
|
|
|
const SSL_INCRON_FILE = "/var/run/alternc-ssl/generate_certif_alias"; |
46
|
|
|
|
47
|
|
|
var $myDomainesTypes = array("vhost-ssl", "vhost-mixssl", "panel-ssl", "roundcube-ssl", "squirrelmail-ssl", "php52-ssl", "php52-mixssl", "url-ssl"); |
48
|
|
|
|
49
|
|
|
const KEY_REPOSITORY = "/var/lib/alternc/ssl/private"; |
50
|
|
|
|
51
|
|
|
// ----------------------------------------------------------------- |
52
|
|
|
/** |
53
|
|
|
* Constructor |
54
|
|
|
*/ |
55
|
|
|
function m_ssl() { |
56
|
|
|
|
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
// ----------------------------------------------------------------- |
60
|
|
|
/** |
61
|
|
|
* Hook to add the "ssl certificate" menu in the Panel |
62
|
|
|
*/ |
63
|
|
|
function hook_menu() { |
64
|
|
|
global $quota, $db, $cuid; |
65
|
|
|
$q = $quota->getquota("ssl"); |
66
|
|
|
$obj = null; |
67
|
|
|
if ($q['t'] > 0) { |
68
|
|
|
$obj = array( |
69
|
|
|
'title' => _("SSL Certificates"), |
70
|
|
|
'ico' => 'images/ssl.png', |
71
|
|
|
'link' => 'toggle', |
72
|
|
|
'pos' => 130, |
73
|
|
|
'links' => array(), |
74
|
|
|
); |
75
|
|
|
|
76
|
|
|
if ($quota->cancreate("ssl")) { |
77
|
|
|
$obj['links'][] = array( |
78
|
|
|
'ico' => 'images/new.png', |
79
|
|
|
'txt' => _("New SSL certificate"), |
80
|
|
|
'url' => "ssl_new.php", |
81
|
|
|
'class' => '', |
82
|
|
|
); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
// or admin shared >0 ! |
86
|
|
|
$db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' OR shared=1"); |
87
|
|
|
$used = $q['u']; |
88
|
|
|
if ($db->next_record()) { |
89
|
|
|
$used = $db->f("cnt"); |
90
|
|
|
} |
91
|
|
|
if ($used > 0) { // if there are some SSL certificates |
92
|
|
|
$obj['links'][] = array( |
93
|
|
|
'txt' => _("List SSL Certificates"), |
94
|
|
|
'url' => "ssl_list.php" |
95
|
|
|
); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
return $obj; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
// ----------------------------------------------------------------- |
102
|
|
|
/** Return all the SSL certificates for an account (or the searched one) |
103
|
|
|
* @param $filter an integer telling which certificate we want to see (see FILTER_* constants above) |
104
|
|
|
* the default is showing all certificate, but only Pending and OK certificates, not expired or shared one |
105
|
|
|
* when there is more than 10. |
106
|
|
|
* @return array all the ssl certificate this user can use |
107
|
|
|
* (each array is the content of the certificates table) |
108
|
|
|
*/ |
109
|
|
|
function get_list(&$filter = null) { |
110
|
|
|
global $db, $err, $cuid; |
111
|
|
|
$err->log("ssl", "get_list"); |
112
|
|
|
// Expire expired certificates: |
113
|
|
|
$db->query("UPDATE certificates SET status=".self::STATUS_EXPIRED." WHERE status=".self::STATUS_OK." AND validend<NOW();"); |
114
|
|
|
$r = array(); |
115
|
|
|
// If we have no filter, we filter by default on pending and ok certificates if there is more than 10 of them for the same user. |
116
|
|
|
if (is_null($filter)) { |
117
|
|
|
$db->query("SELECT count(*) AS cnt FROM certificates WHERE uid='$cuid' OR shared=1;"); |
118
|
|
|
$db->next_record(); |
119
|
|
|
if ($db->f("cnt") > 10) { |
120
|
|
|
$filter = (self::FILTER_PENDING | self::FILTER_OK); |
121
|
|
|
} else { |
122
|
|
|
$filter = (self::FILTER_PENDING | self::FILTER_OK | self::FILTER_EXPIRED | self::FILTER_SHARED); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
// filter the filter values :) |
126
|
|
|
$filter = ($filter & (self::FILTER_PENDING | self::FILTER_OK | self::FILTER_EXPIRED | self::FILTER_SHARED)); |
127
|
|
|
// Here filter can't be null (and will be returned to the caller !) |
128
|
|
|
$sql = ""; |
129
|
|
|
if ($filter & self::FILTER_SHARED) { |
130
|
|
|
$sql = " (uid='$cuid' OR shared=1) "; |
131
|
|
|
} else { |
132
|
|
|
$sql = " uid='$cuid' "; |
133
|
|
|
} |
134
|
|
|
$sql.=" AND status IN (-1"; |
135
|
|
|
if ($filter & self::FILTER_PENDING) { |
136
|
|
|
$sql.="," . self::STATUS_PENDING; |
137
|
|
|
} |
138
|
|
|
if ($filter & self::FILTER_OK) { |
139
|
|
|
$sql.="," . self::STATUS_OK; |
140
|
|
|
} |
141
|
|
|
if ($filter & self::FILTER_EXPIRED) { |
142
|
|
|
$sql.="," . self::STATUS_EXPIRED; |
143
|
|
|
} |
144
|
|
|
$sql.=") "; |
145
|
|
|
$db->query("SELECT *, UNIX_TIMESTAMP(validstart) AS validstartts, UNIX_TIMESTAMP(validend) AS validendts FROM certificates WHERE $sql ORDER BY shared, fqdn;"); |
146
|
|
|
if ($db->num_rows()) { |
147
|
|
|
while ($db->next_record()) { |
148
|
|
|
$r[] = $db->Record; |
149
|
|
|
} |
150
|
|
|
return $r; |
151
|
|
|
} else { |
152
|
|
|
$err->raise("ssl", _("No SSL certificates available")); |
153
|
|
|
return array(); |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
// ----------------------------------------------------------------- |
158
|
|
|
/** Return all the Vhosts of this user using SSL certificates |
159
|
|
|
* @return array all the ssl certificate and hosts of this user |
160
|
|
|
*/ |
161
|
|
|
function get_vhosts() { |
162
|
|
|
global $db, $err, $cuid; |
163
|
|
|
$err->log("ssl", "get_vhosts"); |
164
|
|
|
$r=array(); |
165
|
|
|
$db->query("SELECT ch.*, UNIX_TIMESTAMP(c.validstart) AS validstartts, UNIX_TIMESTAMP(c.validend) AS validendts, sd.domaine, sd.sub " |
166
|
|
|
. "FROM certif_hosts ch LEFT JOIN certificates c ON ch.certif=c.id " |
167
|
|
|
. ", sub_domaines sd WHERE sd.id=ch.sub AND ch.uid=$cuid " |
168
|
|
|
. "ORDER BY sd.domaine, sd.sub;"); |
169
|
|
|
if ($db->num_rows()) { |
170
|
|
|
while ($db->next_record()) { |
171
|
|
|
$r[] = $db->Record; |
172
|
|
|
} |
173
|
|
|
return $r; |
174
|
|
|
} else { |
175
|
|
|
$err->raise("ssl", _("You currently have no hosting using SSL certificate")); |
176
|
|
|
return array(); |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
// ----------------------------------------------------------------- |
181
|
|
|
/** Generate a new CSR, a new Private RSA Key, for FQDN. |
182
|
|
|
* @param $fqdn string the FQDN of the domain name for which we want a CSR. |
183
|
|
|
* a wildcard certificate must start by *. |
184
|
|
|
* @return integer the Certificate ID created in the MySQL database |
185
|
|
|
* or false if an error occurred |
186
|
|
|
*/ |
187
|
|
|
function new_csr($fqdn) { |
188
|
|
|
global $db, $err, $cuid; |
189
|
|
|
$err->log("ssl", "new_csr"); |
190
|
|
|
if (substr($fqdn, 0, 2) == "*.") { |
191
|
|
|
$f = substr($fqdn, 2); |
192
|
|
|
} else { |
193
|
|
|
$f = $fqdn; |
194
|
|
|
} |
195
|
|
|
if (checkfqdn($f)) { |
196
|
|
|
$err->raise("ssl", _("Bad FQDN domain name")); |
197
|
|
|
return false; |
198
|
|
|
} |
199
|
|
|
putenv("OPENSSL_CONF=/etc/alternc/openssl.cnf"); |
200
|
|
|
$pkey = openssl_pkey_new(); |
201
|
|
|
if (!$pkey) { |
202
|
|
|
$err->raise("ssl", _("Can't generate a private key (1)")); |
203
|
|
|
return false; |
204
|
|
|
} |
205
|
|
|
$privKey = ""; |
206
|
|
|
if (!openssl_pkey_export($pkey, $privKey)) { |
207
|
|
|
$err->raise("ssl", _("Can't generate a private key (2)")); |
208
|
|
|
return false; |
209
|
|
|
} |
210
|
|
|
$dn = array("commonName" => $fqdn); |
211
|
|
|
// override the (not taken from openssl.cnf) digest to use SHA-2 / SHA256 and not SHA-1 or MD5 : |
212
|
|
|
$config = array("digest_alg" => "sha256"); |
213
|
|
|
$csr = openssl_csr_new($dn, $pkey, $config); |
214
|
|
|
$csrout = ""; |
215
|
|
|
openssl_csr_export($csr, $csrout); |
216
|
|
|
$db->query("INSERT INTO certificates SET uid='$cuid', status=" . self::STATUS_PENDING . ", shared=0, fqdn='" . addslashes($fqdn) . "', altnames='', validstart=NOW(), sslcsr='" . addslashes($csrout) . "', sslkey='" . addslashes($privKey) . "';"); |
217
|
|
|
if (!($id = $db->lastid())) { |
218
|
|
|
$err->raise("ssl", _("Can't generate a CSR")); |
219
|
|
|
return false; |
220
|
|
|
} |
221
|
|
|
return $id; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
// ----------------------------------------------------------------- |
225
|
|
|
/** Return all informations of a given certificate for the current user. |
226
|
|
|
* @return array all the informations of the current certificate as a hash. |
227
|
|
|
*/ |
228
|
|
|
function get_certificate($id) { |
229
|
|
|
global $db, $err, $cuid; |
230
|
|
|
$err->log("ssl", "get_certificate"); |
231
|
|
|
$id = intval($id); |
232
|
|
|
$db->query("SELECT *, UNIX_TIMESTAMP(validstart) AS validstartts, UNIX_TIMESTAMP(validend) AS validendts FROM certificates WHERE (uid='$cuid' OR (shared=1 AND status=" . self::STATUS_OK . ") ) AND id='$id';"); |
233
|
|
|
if (!$db->next_record()) { |
234
|
|
|
$err->raise("ssl", _("Can't find this Certificate")); |
235
|
|
|
return false; |
236
|
|
|
} |
237
|
|
|
return $db->Record; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
// ----------------------------------------------------------------- |
241
|
|
|
/** Delete a Certificate for the current user. |
242
|
|
|
* @return boolean TRUE if the certificate has been deleted successfully. |
243
|
|
|
*/ |
244
|
|
|
function del_certificate($id) { |
245
|
|
|
global $db, $err, $cuid; |
246
|
|
|
$err->log("ssl", "del_certificate"); |
247
|
|
|
$id = intval($id); |
248
|
|
|
$db->query("SELECT * FROM certificates WHERE uid='$cuid' AND id='$id';"); |
249
|
|
|
if (!$db->next_record()) { |
250
|
|
|
$err->raise("ssl", _("Can't find this Certificate")); |
251
|
|
|
return false; |
252
|
|
|
} |
253
|
|
|
$fqdn = $db->Record["fqdn"]; |
254
|
|
|
$altnames = $db->Record["altnames"]; |
255
|
|
|
$db->query("DELETE FROM certificates WHERE uid='$cuid' AND id='$id';"); |
256
|
|
|
// Update any existing VHOST using this cert/key |
257
|
|
|
$this->updateTrigger($fqdn, $altnames); |
258
|
|
|
return true; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
// ----------------------------------------------------------------- |
262
|
|
|
/** Share (or unshare) an ssl certificate |
263
|
|
|
* @param $id integer the id of the certificate in the table. |
264
|
|
|
* @param $action integer share (1) or unshare (0) this certificate |
265
|
|
|
* @return boolean |
266
|
|
|
*/ |
267
|
|
|
function share($id, $action = 1) { |
268
|
|
|
global $db, $err, $cuid; |
269
|
|
|
$err->log("ssl", "share"); |
270
|
|
|
$id = intval($id); |
271
|
|
|
$db->query("SELECT * FROM certificates WHERE uid='$cuid' AND status=" . self::STATUS_OK . " AND id='$id';"); |
272
|
|
|
if (!$db->next_record()) { |
273
|
|
|
$err->raise("ssl", _("Can't find this Certificate")); |
274
|
|
|
return false; |
275
|
|
|
} |
276
|
|
|
if ($action) { |
277
|
|
|
$action = 1; |
278
|
|
|
$this->updateTrigger($db->Record["fqdn"], $db->Record["altnames"]); |
279
|
|
|
} else { |
280
|
|
|
$action = 0; |
281
|
|
|
} |
282
|
|
|
$db->query("UPDATE certificates SET shared=$action WHERE id='$id';"); |
283
|
|
|
return true; |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
// ----------------------------------------------------------------- |
287
|
|
|
/** Return all the subdomains that can be ssl-enabled for the current account. |
288
|
|
|
* @return array of strings : all the subdomains. |
289
|
|
|
* Excludes the one for which a cert is already available |
290
|
|
|
*/ |
291
|
|
|
function get_new_advice() { |
292
|
|
|
global $db, $err, $cuid; |
293
|
|
|
$err->log("ssl", "get_new_advice"); |
294
|
|
|
$r = array(); |
295
|
|
|
// my certificates, either OK or PENDING (not expired) or the SHARED one (only OK then) |
296
|
|
|
$db->query("SELECT fqdn FROM certificates WHERE |
297
|
|
|
(uid='$cuid' AND status IN (" . self::STATUS_PENDING . "," . self::STATUS_OK . ") ) |
298
|
|
|
OR (shared=1 AND status=" . self::STATUS_OK . ") |
299
|
|
|
ORDER BY shared, fqdn;"); |
300
|
|
|
$r = array(); |
301
|
|
|
while ($db->next_record()) { |
302
|
|
|
$r[] = $db->f("fqdn"); |
303
|
|
|
} |
304
|
|
|
// Now we get all our subdomains for certain domaines_types |
305
|
|
|
$db->query("SELECT sub,domaine FROM sub_domaines WHERE compte='$cuid' AND type IN ('vhost', 'url', 'roundcube', 'squirrelmail', 'panel', 'php52');"); |
306
|
|
|
$advice = array(); |
307
|
|
|
while ($db->next_record()) { |
308
|
|
|
$me = $db->f("sub"); |
309
|
|
|
if ($me) { |
310
|
|
|
$me.="."; |
311
|
|
|
} |
312
|
|
|
$me.=$db->f("domaine"); |
313
|
|
|
if (!in_array($me, $r) && !in_array($me, $advice)) { |
314
|
|
|
$advice[] = $me; |
315
|
|
|
} |
316
|
|
|
if (!in_array("*." . $db->f("domaine"), $r) && !in_array("*." . $db->f("domaine"), $advice)) { |
317
|
|
|
$advice[] = "*." . $db->f("domaine"); |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
sort($advice); |
321
|
|
|
return($advice); |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
// ----------------------------------------------------------------- |
325
|
|
|
/** Import an existing ssl Key, Certificate and (maybe) a Chained Cert |
326
|
|
|
* @param $key string the X.509 PEM-encoded RSA key |
327
|
|
|
* @param $crt string the X.509 PEM-encoded certificate, which *must* |
328
|
|
|
* be the one signinf the private RSA key in $key |
329
|
|
|
* @param $chain string the X.509 PEM-encoded list of SSL Certificate chain if intermediate authorities |
330
|
|
|
* @return integer the ID of the newly created certificate in the table |
331
|
|
|
* or false if an error occurred |
332
|
|
|
*/ |
333
|
|
|
function import_cert($key, $crt, $chain = "") { |
334
|
|
|
global $cuid, $err, $db; |
335
|
|
|
$err->log("ssl", "import_cert"); |
336
|
|
|
|
337
|
|
|
$result = $this->check_cert($crt, $chain, $key); |
338
|
|
|
if ($result === false) { |
339
|
|
|
$err->raise("ssl", $this->error); |
340
|
|
|
return false; |
341
|
|
|
} |
342
|
|
|
list($crt, $chain, $key, $crtdata) = $result; |
343
|
|
|
|
344
|
|
|
$validstart = $crtdata['validFrom_time_t']; |
345
|
|
|
$validend = $crtdata['validTo_time_t']; |
346
|
|
|
$fqdn = $crtdata["subject"]["CN"]; |
347
|
|
|
$altnames = $this->parseAltNames($crtdata["extensions"]["subjectAltName"]); |
348
|
|
|
|
349
|
|
|
// Everything is PERFECT and has been thoroughly checked, let's insert those in the DB ! |
350
|
|
|
$sql = "INSERT INTO certificates SET uid='$cuid', status=" . self::STATUS_OK . ", shared=0, fqdn='" . addslashes($fqdn) . "', altnames='" . addslashes($altnames) . "', validstart=FROM_UNIXTIME(" . intval($validstart) . "), validend=FROM_UNIXTIME(" . intval($validend) . "), sslkey='" . addslashes($key) . "', sslcrt='" . addslashes($crt) . "', sslchain='" . addslashes($chain) . "';"; |
351
|
|
|
$db->query($sql); |
352
|
|
|
if (!($id = $db->lastid())) { |
353
|
|
|
$err->raise("ssl", _("Can't save the Key/Crt/Chain now. Please try later.")); |
354
|
|
|
return false; |
355
|
|
|
} |
356
|
|
|
$this->updateTrigger($fqdn, $altnames); |
357
|
|
|
return $id; |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
// ----------------------------------------------------------------- |
361
|
|
|
/** Import an ssl certificate into an existing certificate entry in the DB. |
362
|
|
|
* (finalize an enrollment process) |
363
|
|
|
* @param $certid integer the ID in the database of the SSL Certificate |
364
|
|
|
* @param $crt string the X.509 PEM-encoded certificate, which *must* |
365
|
|
|
* be the one signing the private RSA key in certificate $certid |
366
|
|
|
* @param $chain string the X.509 PEM-encoded list of SSL Certificate chain if intermediate authorities |
367
|
|
|
* @return integer the ID of the updated certificate in the table |
368
|
|
|
* or false if an error occurred |
369
|
|
|
*/ |
370
|
|
|
function finalize($certid, $crt, $chain) { |
371
|
|
|
global $cuid, $err, $db; |
372
|
|
|
$err->log("ssl", "finalize"); |
373
|
|
|
|
374
|
|
|
$certid = intval($certid); |
375
|
|
|
$result = $this->check_cert($crt, $chain, "", $certid); |
376
|
|
|
if ($result === false) { |
377
|
|
|
$err->raise("ssl", $this->error); |
378
|
|
|
return false; |
379
|
|
|
} |
380
|
|
|
list($crt, $chain, $key, $crtdata) = $result; |
381
|
|
|
|
382
|
|
|
$validstart = $crtdata['validFrom_time_t']; |
383
|
|
|
$validend = $crtdata['validTo_time_t']; |
384
|
|
|
$fqdn = $crtdata["subject"]["CN"]; |
385
|
|
|
$altnames = $this->parseAltNames($crtdata["extensions"]["subjectAltName"]); |
386
|
|
|
|
387
|
|
|
// Everything is PERFECT and has been thoroughly checked, let's insert those in the DB ! |
388
|
|
|
$sql = "UPDATE certificates SET status=" . self::STATUS_OK . ", shared=0, fqdn='" . addslashes($fqdn) . "', altnames='" . addslashes($altnames) . "', validstart=FROM_UNIXTIME(" . intval($validstart) . "), validend=FROM_UNIXTIME(" . intval($validend) . "), sslcrt='" . addslashes($crt) . "', sslchain='" . addslashes($chain) . "' WHERE id='$certid' ;"; |
389
|
|
|
if (!$db->query($sql)) { |
390
|
|
|
$err->raise("ssl", _("Can't save the Crt/Chain now. Please try later.")); |
391
|
|
|
return false; |
392
|
|
|
} |
393
|
|
|
$this->updateTrigger($fqdn, $altnames); |
394
|
|
|
return $certid; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
// ----------------------------------------------------------------- |
398
|
|
|
/** Function called by a hook when an AlternC member is deleted. |
399
|
|
|
* @access private |
400
|
|
|
* TODO: delete unused ssl certificates ?? > do this in the crontab. |
401
|
|
|
*/ |
402
|
|
|
function alternc_del_member() { |
403
|
|
|
global $db, $err, $cuid; |
404
|
|
|
$err->log("ssl", "alternc_del_member"); |
405
|
|
|
$db->query("UPDATE certificates SET ssl_action='DELETE' WHERE uid='$cuid'"); |
406
|
|
|
return true; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
// ----------------------------------------------------------------- |
410
|
|
|
/** Hook which returns the used quota for the $name service for the current user. |
411
|
|
|
* @param $name string name of the quota |
412
|
|
|
* @return integer the number of service used or false if an error occured |
413
|
|
|
* @access private |
414
|
|
|
*/ |
415
|
|
|
function hook_quota_get() { |
416
|
|
|
global $db, $err, $cuid; |
417
|
|
|
$err->log("ssl", "getquota"); |
418
|
|
|
$q = Array("name" => "ssl", "description" => _("SSL Certificates"), "used" => 0); |
419
|
|
|
$db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' AND status!=" . self::STATUS_EXPIRED); |
420
|
|
|
if ($db->next_record()) { |
421
|
|
|
$q['used'] = $db->f("cnt"); |
422
|
|
|
} |
423
|
|
|
return $q; |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
// ----------------------------------------------------------------- |
427
|
|
|
/** Launched by functions in this class |
428
|
|
|
* when a certificate is validated, expired or shared. |
429
|
|
|
* so that existing vhost using expired or self-signed certificates |
430
|
|
|
* may have the chance to use a proper one automagically |
431
|
|
|
* @param string $fqdn the FQDN of the certificate |
432
|
|
|
* @param string $altnames any alternative names this certificate may have. |
433
|
|
|
*/ |
434
|
|
|
public function updateTrigger($fqdn, $altnames = "") { |
435
|
|
|
global $db; |
436
|
|
|
$fqdns = array($fqdn); |
437
|
|
|
$an = explode("\n", $altnames); |
438
|
|
|
foreach ($an as $a) |
439
|
|
|
if (trim($a)) |
440
|
|
|
$fqdns[] = trim($a); |
441
|
|
|
$db->query("UPDATE sub_domaines SET web_action='UPDATE' WHERE " |
442
|
|
|
. "if(LENGTH(sub)>0,CONCAT(sub,'.',domaine),domaine) IN ('" . implode("','", $fqdns) . "') " |
443
|
|
|
. "AND type LIKE '%ssl';"); |
444
|
|
|
} |
445
|
|
|
|
446
|
|
|
// ----------------------------------------------------------------- |
447
|
|
|
/** Launched by hosting_functions.sh launched by update_domaines.sh |
448
|
|
|
* Action may be create/postinst/delete/enable/disable |
449
|
|
|
* Change the template for this domain name to have the proper CERTIFICATE |
450
|
|
|
* An algorithm determine the best possible certificate, which may be a BAD one |
451
|
|
|
* (like a generic admin-shared or self-signed for localhost as a last chance) |
452
|
|
|
*/ |
453
|
|
|
public function updateDomain($action, $type, $fqdn, $mail = 0, $value = "") { |
|
|
|
|
454
|
|
|
global $db, $err; |
455
|
|
|
$err->log("ssl", "update_domain($action,$type,$fqdn)"); |
456
|
|
|
if (!in_array($type, $this->myDomainesTypes)) { |
457
|
|
|
return; // nothing to do : the type is not our to start with ;) |
458
|
|
|
} |
459
|
|
|
if ($action == "postinst") { |
460
|
|
|
$err->log("ssl", "update_domain:CREATE($action,$type,$fqdn)"); |
461
|
|
|
$offset = 0; |
462
|
|
|
$found = false; |
463
|
|
|
do { // try each subdomain (strtok-style) and search them in sub_domaines table: |
464
|
|
|
$db->query("SELECT * FROM sub_domaines WHERE " |
465
|
|
|
. "sub='" . substr($fqdn, 0, $offset) . "' AND domaine='" . substr($fqdn, $offset + ($offset != 0)) . "' " |
466
|
|
|
. "AND web_action NOT IN ('','OK') AND type='" . $type . "';"); |
467
|
|
|
if ($db->next_record()) { |
468
|
|
|
$found = true; |
469
|
|
|
break; |
470
|
|
|
} |
471
|
|
|
$offset = strpos($fqdn, ".", $offset); |
472
|
|
|
} while (true); |
473
|
|
|
if (!$found) { |
474
|
|
|
echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n"; |
475
|
|
|
return; |
476
|
|
|
} |
477
|
|
|
// found and $db point to it: |
478
|
|
|
$subdom = $db->Record; |
479
|
|
|
$TARGET_FILE = "/var/lib/alternc/apache-vhost/" . substr($subdom["compte"], -1) . "/" . $subdom["compte"] . "/" . $fqdn . ".conf"; |
480
|
|
|
$cert = $this->searchBestCert($subdom["compte"], $fqdn); |
481
|
|
|
// DEBUG echo "Return from searchBestCert(" . $subdom["compte"] . "," . $fqdn . ") is "; print_r($cert); |
482
|
|
|
// Save crt/key/chain into KEY_REPOSITORY |
483
|
|
|
$CRTDIR = self::KEY_REPOSITORY . "/" . $subdom["compte"]; |
484
|
|
|
@mkdir($CRTDIR); |
485
|
|
|
// Don't *overwrite* existing self-signed certificates in KEY_REPOSITORY |
486
|
|
|
if (isset($cert["selfsigned"]) && |
487
|
|
|
file_exists($CRTDIR . "/" . $fqdn . ".crt") && |
488
|
|
|
file_exists($CRTDIR . "/" . $fqdn . ".key")) { |
489
|
|
|
echo "Self-Signed certificate reused...\n"; |
490
|
|
|
} else { |
491
|
|
|
file_put_contents($CRTDIR . "/" . $fqdn . ".crt", $cert["sslcrt"]); |
492
|
|
|
file_put_contents($CRTDIR . "/" . $fqdn . ".key", $cert["sslkey"]); |
493
|
|
|
if (isset($cert["sslchain"]) && $cert["sslchain"]) { |
494
|
|
|
file_put_contents($CRTDIR . "/" . $fqdn . ".chain", $cert["sslchain"]); |
495
|
|
|
} |
496
|
|
|
} |
497
|
|
|
// edit apache conf file to set the certificate: |
498
|
|
|
$s = file_get_contents($TARGET_FILE); |
499
|
|
|
$s = str_replace("%%CRT%%", $CRTDIR . "/" . $fqdn . ".crt", $s); |
500
|
|
|
$s = str_replace("%%KEY%%", $CRTDIR . "/" . $fqdn . ".key", $s); |
501
|
|
|
if (isset($cert["sslchain"]) && $cert["sslchain"]) { |
502
|
|
|
$s = str_replace("%%CHAINLINE%%", "SSLCertificateChainFile " . $CRTDIR . "/" . $fqdn . ".chain", $s); |
503
|
|
|
} else { |
504
|
|
|
$s = str_replace("%%CHAINLINE%%", "", $s); |
505
|
|
|
} |
506
|
|
|
file_put_contents($TARGET_FILE, $s); |
507
|
|
|
// Edit certif_hosts: |
508
|
|
|
$db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";"); |
509
|
|
|
$db->query("INSERT INTO certif_hosts SET " |
510
|
|
|
. "sub=" . intval($subdom["id"]) . ", " |
511
|
|
|
. "certif=" . intval($cert["id"]) . ", " |
512
|
|
|
. "uid=" . intval($subdom["compte"]) . ";"); |
513
|
|
|
} // action==create |
514
|
|
|
if ($action == "delete") { |
515
|
|
|
$err->log("ssl", "update_domain:DELETE($action,$type,$fqdn)"); |
516
|
|
|
$offset = 0; |
517
|
|
|
$found = false; |
518
|
|
|
do { // try each subdomain (strtok-style) and search them in sub_domaines table: |
519
|
|
|
$db->query("SELECT * FROM sub_domaines WHERE " |
520
|
|
|
. "sub='" . substr($fqdn, 0, $offset) . "' AND domaine='" . substr($fqdn, $offset + ($offset != 0)) . "' " |
521
|
|
|
. "AND web_action NOT IN ('','OK') AND type='" . $type . "';"); |
522
|
|
|
if ($db->next_record()) { |
523
|
|
|
$found = true; |
524
|
|
|
break; |
525
|
|
|
} |
526
|
|
|
$offset = strpos($fqdn, ".", $offset); |
527
|
|
|
} while (true); |
528
|
|
|
if (!$found) { |
529
|
|
|
echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n"; |
530
|
|
|
return; |
531
|
|
|
} |
532
|
|
|
// found and $db point to it: |
533
|
|
|
$subdom = $db->Record; |
534
|
|
|
$db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";"); |
535
|
|
|
} |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
// ---------------------------------------------------------------- |
539
|
|
|
/** Search for the best certificate for a user and a fqdn |
540
|
|
|
* Return a hash with sslcrt, sslkey and maybe sslchain. |
541
|
|
|
* return ANYWAY : if necessary, return a newly created (and stored in KEY_REPOSITORY localhost self-signed certificate... |
542
|
|
|
*/ |
543
|
|
|
public function searchBestCert($uid, $fqdn) { |
544
|
|
|
global $db; |
545
|
|
|
$uid = intval($uid); |
546
|
|
|
// 1st search for a valid certificate in my account or shared by the admin: |
547
|
|
|
// the ORDER BY make it so that we try VALID then EXPIRED one (sad) |
548
|
|
|
$wildcard = "*." . substr($fqdn, strpos($fqdn, ".") + 1); |
549
|
|
|
$db->query("SELECT * FROM certificates WHERE (status=".self::STATUS_OK." OR status=".self::STATUS_EXPIRED.") " |
550
|
|
|
. "AND (uid=" . $uid . " OR shared=1) " |
551
|
|
|
. "AND (fqdn='" . $fqdn . "' OR fqdn='" . $wildcard . "' OR altnames LIKE '%" . $fqdn . "%') " |
552
|
|
|
. "ORDER BY (validstart<=NOW() AND validend>=NOW()) DESC, validstart DESC "); |
553
|
|
|
while ($db->next_record()) { |
554
|
|
|
// name |
555
|
|
|
if ($db->Record["fqdn"] == $fqdn) { |
556
|
|
|
return $db->Record; |
557
|
|
|
} |
558
|
|
|
// or alternative names |
559
|
|
|
$altnames = explode("\n", $db->Record["altnames"]); |
560
|
|
|
foreach ($altnames as $altname) { |
561
|
|
|
if (trim($altname) == $fqdn) { |
562
|
|
|
return $db->Record; |
563
|
|
|
} |
564
|
|
|
} |
565
|
|
|
// or wildcard |
566
|
|
|
if ($db->Record["fqdn"] == $wildcard) { |
567
|
|
|
return $db->Record; |
568
|
|
|
} |
569
|
|
|
} |
570
|
|
|
// not found, we generate a one-time self-signed certificate for this host. |
571
|
|
|
$crt = $this->selfSigned($fqdn); |
572
|
|
|
$crt["uid"] = $uid; |
573
|
|
|
return $crt; |
574
|
|
|
} |
575
|
|
|
|
576
|
|
|
// ----------------------------------------------------------------- |
577
|
|
|
/** Export every information for an AlternC's account |
578
|
|
|
* @access private |
579
|
|
|
* EXPERIMENTAL 'sid' function ;) |
580
|
|
|
*/ |
581
|
|
|
function alternc_export_conf() { |
582
|
|
|
global $db, $err, $cuid; |
583
|
|
|
$err->log("ssl", "export"); |
584
|
|
|
$str = " <ssl>"; |
585
|
|
|
$db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' AND status!=" . self::STATUS_EXPIRED); |
586
|
|
|
while ($db->next_record()) { |
587
|
|
|
$str.=" <id>" . ($db->Record["id"]) . "</id>\n"; |
588
|
|
|
$str.=" <csr>" . ($db->Record["sslcsr"]) . "</key>\n"; |
589
|
|
|
$str.=" <key>" . ($db->Record["sslkey"]) . "<key>\n"; |
590
|
|
|
$str.=" <crt>" . ($db->Record["sslcrt"]) . "</crt>\n"; |
591
|
|
|
$str.=" <chain>" . ($db->Record["sslchain"]) . "<chain>\n"; |
592
|
|
|
} |
593
|
|
|
$str.=" </ssl>\n"; |
594
|
|
|
return $str; |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
// ----------------------------------------------------------------- |
598
|
|
|
/** Returns the list of alternate names of an X.509 SSL Certificate |
599
|
|
|
* from the attribute list. |
600
|
|
|
* @param $str string the $crtdata["extensions"]["subjectAltName"] from openssl |
601
|
|
|
* @return array an array of FQDNs |
602
|
|
|
*/ |
603
|
|
|
function parseAltNames($str) { |
604
|
|
|
$mat = array(); |
605
|
|
|
if (preg_match_all("#DNS:([^,]*)#", $str, $mat, PREG_PATTERN_ORDER)) { |
606
|
|
|
return implode("\n", $mat[1]); |
607
|
|
|
} else { |
608
|
|
|
return ""; |
609
|
|
|
} |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
// ----------------------------------------------------------------- |
613
|
|
|
/** Add (immediately) a global alias to the HTTP |
614
|
|
|
* certif_alias table and add it to apache configuration |
615
|
|
|
* by launching a incron action. |
616
|
|
|
* name is the name of the alias, starting by / |
617
|
|
|
* content is the content of the filename stored at this location |
618
|
|
|
* If an alias with the same name already exists, return false. |
619
|
|
|
* if the alias has been properly defined, return true. |
620
|
|
|
* @return boolean |
621
|
|
|
*/ |
622
|
|
|
function alias_add($name, $content) { |
623
|
|
|
global $err, $cuid, $db; |
624
|
|
|
$db->query("SELECT name FROM certif_alias WHERE name='" . addslashes($name) . "';"); |
625
|
|
|
if ($db->next_record()) { |
626
|
|
|
$err->raise("ssl", _("Alias already exists")); |
627
|
|
|
return false; |
628
|
|
|
} |
629
|
|
|
$db->query("INSERT INTO certif_alias SET name='" . addslashes($name) . "', content='" . addslashes($content) . "', uid=" . intval($cuid) . ";"); |
630
|
|
|
touch(self::SSL_INCRON_FILE); |
631
|
|
|
return true; |
632
|
|
|
} |
633
|
|
|
|
634
|
|
|
// ----------------------------------------------------------------- |
635
|
|
|
/** Removes (immediately) a global alias to the HTTP |
636
|
|
|
* certif_alias table and add it to apache configuration |
637
|
|
|
* by launching a incron action. |
638
|
|
|
* name is the name of the alias, starting by / |
639
|
|
|
* @return boolean |
640
|
|
|
*/ |
641
|
|
|
function alias_del($name) { |
642
|
|
|
global $err, $cuid, $db; |
643
|
|
|
$db->query("SELECT name FROM certif_alias WHERE name='" . addslashes($name) . "' AND uid=" . intval($cuid) . ";"); |
644
|
|
|
if (!$db->next_record()) { |
645
|
|
|
$err->raise("ssl", _("Alias not found")); |
646
|
|
|
return false; |
647
|
|
|
} |
648
|
|
|
$db->query("DELETE FROM certif_alias WHERE name='" . addslashes($name) . "' AND uid=" . intval($cuid) . ";"); |
649
|
|
|
touch(self::SSL_INCRON_FILE); |
650
|
|
|
return true; |
651
|
|
|
} |
652
|
|
|
|
653
|
|
|
// ----------------------------------------------------------------- |
654
|
|
|
/** Check that a crt is a proper certificate |
655
|
|
|
* @param $crt string an SSL Certificate |
656
|
|
|
* @param $chain string is a list of certificates |
657
|
|
|
* @param $key string is a rsa key associated with certificate |
658
|
|
|
* @param $certid if no key is specified, use it from this certificate ID in the table |
659
|
|
|
* @return array the crt, chain, key, crtdata(array) after a proper reformatting |
660
|
|
|
* or false if an error occurred (in that case $this->error is filled) |
661
|
|
|
*/ |
662
|
|
|
function check_cert($crt, $chain, $key = "", $certid = null) { |
663
|
|
|
global $db; |
664
|
|
|
// Check that the key crt and chain are really SSL certificates and keys |
665
|
|
|
$crt = trim(str_replace("\r\n", "\n", $crt)) . "\n"; |
666
|
|
|
$key = trim(str_replace("\r\n", "\n", $key)) . "\n"; |
667
|
|
|
$chain = trim(str_replace("\r\n", "\n", $chain)) . "\n"; |
668
|
|
|
|
669
|
|
|
$this->error = ""; |
670
|
|
|
if (trim($key) == "" && !is_null($certid)) { |
671
|
|
|
// find it in the DB : |
672
|
|
|
$db->query("SELECT sslkey FROM certificates WHERE id=" . intval($certid) . ";"); |
673
|
|
|
if (!$db->next_record()) { |
674
|
|
|
$this->error.=_("Can't find the private key in the certificate table, please check your form."); |
675
|
|
|
return false; |
676
|
|
|
} |
677
|
|
|
$key = $db->f("sslkey"); |
678
|
|
|
$key = trim(str_replace("\r\n", "\n", $key)) . "\n"; |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
if (substr($crt, 0, 28) != "-----BEGIN CERTIFICATE-----\n" || |
682
|
|
|
substr($crt, -26, 26) != "-----END CERTIFICATE-----\n") { |
683
|
|
|
$this->error.=_("The certificate must begin by BEGIN CERTIFICATE and end by END CERTIFICATE lines. Please check you pasted it in PEM form.") . "<br>\n"; |
684
|
|
|
} |
685
|
|
|
if (trim($chain) && |
686
|
|
|
(substr($chain, 0, 28) != "-----BEGIN CERTIFICATE-----\n" || |
687
|
|
|
substr($chain, -26, 26) != "-----END CERTIFICATE-----\n")) { |
688
|
|
|
$this->error.=_("The chained certificate must begin by BEGIN CERTIFICATE and end by END CERTIFICATE lines. Please check you pasted it in PEM form.") . "<br>\n"; |
689
|
|
|
} |
690
|
|
|
if ((substr($key, 0, 32) != "-----BEGIN RSA PRIVATE KEY-----\n" || |
691
|
|
|
substr($key, -30, 30) != "-----END RSA PRIVATE KEY-----\n") && |
692
|
|
|
(substr($key, 0, 28) != "-----BEGIN PRIVATE KEY-----\n" || |
693
|
|
|
substr($key, -26, 26) != "-----END PRIVATE KEY-----\n")) { |
694
|
|
|
$this->error.=_("The private key must begin by BEGIN (RSA )PRIVATE KEY and end by END (RSA )PRIVATE KEY lines. Please check you pasted it in PEM form.") . "<br>\n"; |
695
|
|
|
} |
696
|
|
|
if ($this->error) { |
697
|
|
|
return false; |
698
|
|
|
} |
699
|
|
|
|
700
|
|
|
// We split the chained certificates in individuals certificates : |
701
|
|
|
$chains = array(); |
702
|
|
|
$status = 0; |
703
|
|
|
$new = ""; |
704
|
|
|
$lines = explode("\n", $chain); |
705
|
|
|
foreach ($lines as $line) { |
706
|
|
|
if ($line == "-----BEGIN CERTIFICATE-----" && $status == 0) { |
707
|
|
|
$status = 1; |
708
|
|
|
$new = $line . "\n"; |
709
|
|
|
continue; |
710
|
|
|
} |
711
|
|
|
if ($line == "-----END CERTIFICATE-----" && $status == 1) { |
712
|
|
|
$status = 0; |
713
|
|
|
$new.=$line . "\n"; |
714
|
|
|
$chains[] = $new; |
715
|
|
|
$new = ""; |
716
|
|
|
continue; |
717
|
|
|
} |
718
|
|
|
if ($status == 1) { |
719
|
|
|
$new.=$line . "\n"; |
720
|
|
|
} |
721
|
|
|
} |
722
|
|
|
// here chains contains all the ssl certificates in the chained certs. |
723
|
|
|
// Now we check those using Openssl functions (real check :) ) |
724
|
|
|
$rchains = array(); |
725
|
|
|
$i = 0; |
726
|
|
|
foreach ($chains as $tmpcert) { |
727
|
|
|
$i++; |
728
|
|
|
$tmpr = openssl_x509_read($tmpcert); |
729
|
|
|
if ($tmpr === false) { |
730
|
|
|
$this->error.=sprintf(_("The %d-th certificate in the chain is invalid"), $i) . "<br>\n"; |
731
|
|
|
} else { |
732
|
|
|
$rchains[] = $tmpr; |
733
|
|
|
} |
734
|
|
|
} |
735
|
|
|
$rcrt = openssl_x509_read($crt); |
736
|
|
|
$crtdata = openssl_x509_parse($crt); |
737
|
|
|
if ($rcrt === false || $crtdata === false) { |
738
|
|
|
$this->error.=_("The certificate is invalid.") . "<br>\n"; |
739
|
|
|
} |
740
|
|
|
|
741
|
|
|
$rkey = openssl_pkey_get_private($key); |
742
|
|
|
if ($rkey === false) { |
743
|
|
|
$this->error.=_("The private key is invalid.") . "<br>\n"; |
744
|
|
|
} |
745
|
|
|
if (!$this->error) { |
746
|
|
|
// check that the private key and the certificates are matching : |
747
|
|
|
if (!openssl_x509_check_private_key($rcrt, $rkey)) { |
748
|
|
|
$this->error.=_("The private key is not the one signed inside the certificate.") . "<br>\n"; |
749
|
|
|
} |
750
|
|
|
} |
751
|
|
|
if (!$this->error) { |
752
|
|
|
// Everything is fine, let's recreate crt, chain, key from our internal OpenSSL structures: |
753
|
|
|
if (!openssl_x509_export($rcrt, $crt)) { |
754
|
|
|
$this->error.=_("Can't export your certificate as a string, please check its syntax.") . "<br>\n"; |
755
|
|
|
} |
756
|
|
|
$chain = ""; |
757
|
|
|
foreach ($rchains as $r) { |
758
|
|
|
if (!openssl_x509_export($r, $tmp)) { |
759
|
|
|
$this->error.=_("Can't export one of your chained certificates as a string, please check its syntax.") . "<br>\n"; |
760
|
|
|
} else { |
761
|
|
|
$chain.=$tmp; |
762
|
|
|
} |
763
|
|
|
} |
764
|
|
|
if (!openssl_pkey_export($rkey, $key)) { |
765
|
|
|
$this->error.=_("Can't export your private key as a string, please check its syntax.") . "<br>\n"; |
766
|
|
|
} |
767
|
|
|
} |
768
|
|
|
return array($crt, $chain, $key, $crtdata); |
769
|
|
|
} |
770
|
|
|
|
771
|
|
|
// ----------------------------------------------------------------- |
772
|
|
|
/** Generate a self-signed certificate |
773
|
|
|
* |
774
|
|
|
* @param string $fqdn the fully qualified domain name to set as commonName for the certificate |
775
|
|
|
* @return hash an array similar to a certificate DB row containing everything (sslcrt, sslcsr, sslkey, sslchain) |
776
|
|
|
*/ |
777
|
|
|
private function selfSigned($fqdn) { |
778
|
|
|
global $err; |
779
|
|
|
putenv("OPENSSL_CONF=/etc/alternc/openssl.cnf"); |
780
|
|
|
$pkey = openssl_pkey_new(); |
781
|
|
|
if (!$pkey) { |
782
|
|
|
$err->raise("ssl", _("Can't generate a private key (1)")); |
783
|
|
|
return false; |
784
|
|
|
} |
785
|
|
|
$privKey = ""; |
786
|
|
|
if (!openssl_pkey_export($pkey, $privKey)) { |
787
|
|
|
$err->raise("ssl", _("Can't generate a private key (2)")); |
788
|
|
|
return false; |
789
|
|
|
} |
790
|
|
|
$dn = array("commonName" => $fqdn); |
791
|
|
|
// override the (not taken from openssl.cnf) digest to use SHA-2 / SHA256 and not SHA-1 or MD5 : |
792
|
|
|
$config = array("digest_alg" => "sha256"); |
793
|
|
|
$csr = openssl_csr_new($dn, $pkey, $config); |
794
|
|
|
$csrout = ""; |
795
|
|
|
openssl_csr_export($csr, $csrout); |
796
|
|
|
$crt = openssl_csr_sign($csr, null, $pkey, 3650, $config); |
797
|
|
|
$crtout = ""; |
798
|
|
|
openssl_x509_export($crt, $crtout); |
799
|
|
|
return array("id" => 0, "status" => 1, "shared" => 0, "fqdn" => $fqdn, "altnames" => "", |
800
|
|
|
"validstart" => date("Y-m-d H:i:s"), "validend" => date("Y-m-d H:i:s", time() + 86400 * 10 * 365.249), |
801
|
|
|
"sslcsr" => $csrout, "sslcrt" => $crtout, "sslkey" => $privKey, "sslchain" => "", |
802
|
|
|
"selfsigned" => true, |
803
|
|
|
); |
804
|
|
|
} |
805
|
|
|
|
806
|
|
|
|
807
|
|
|
function dummy() { |
808
|
|
|
_("Locally hosted forcing HTTPS"); |
809
|
|
|
_("Locally hosted HTTP and HTTPS"); |
810
|
|
|
_("HTTPS AlternC panel access"); |
811
|
|
|
_("HTTPS Roundcube Webmail"); |
812
|
|
|
_("HTTPS Squirrelmail Webmail"); |
813
|
|
|
_("php52 forcing HTTPS"); |
814
|
|
|
_("php52 HTTP and HTTPS"); |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
} |
818
|
|
|
|
819
|
|
|
/* Class m_ssl */ |
820
|
|
|
|
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.