Anyway. Courier-0.68 has built-in openssl support on Debian and it initializes a SSL context the following way:
ctx=SSL_CTX_new(protocol && strcmp(protocol, "SSL3") == 0
? SSLv3_method():
protocol && strcmp(protocol, "SSL23") == 0
? SSLv23_method():
TLSv1_method());
// ...
SSL_CTX_set_options(ctx, SSL_OP_ALL);
if (!ssl_cipher_list)
ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";
SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
SSLv3_method would only allow SSLv3TLSv1_method would only allow TLSv1.0SSLv23_method is “the general-purpose version-flexible SSL/TLS method”So, if we do not want to limit ourselves to TLSv1.0, i.e. allow TLSv1.0, TLSv1.1 and TLSv1.2, we have to limit our protocol version support through other means.
Openssl-1.0.1 (remember, we’re on Debian wheezy) does neither come with TLS_method() the
generic TLS-only method, nor does it come with SSL_CTX_set_min_proto_version and we cannot
disable SSLv3 with the cipher list if we also want to allow TLSv1.0.
What if we upgrade to Debian jessie (current stable)? Jessie ships courier-0.73, so let’s see how SSL context intitialization looks there:
options=SSL_OP_ALL;
method=((!protocol || !*protocol)
? NULL:
strcmp(protocol, "SSL3") == 0
? SSLv3_method():
strcmp(protocol, "SSL23") == 0
? SSLv23_method():
strcmp(protocol, "TLSv1") == 0
? TLSv1_method():
#ifdef HAVE_TLSV1_1_METHOD
strcmp(protocol, "TLSv1.1") == 0
? TLSv1_1_method():
#endif
#ifdef HAVE_TLSV1_2_METHOD
strcmp(protocol, "TLSv1.2") == 0
? TLSv1_2_method():
#endif
NULL);
if (!method)
{
method=SSLv23_method();
options|=SSL_OP_NO_SSLv2;
}
ctx=SSL_CTX_new(method);
// ...
SSL_CTX_set_options(ctx, options);
if (!ssl_cipher_list)
ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";
SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
Jessie also comes with openssl-1.0.1, so the situation would not improve for our undertaking by upgrading to jessie.
What I came up with, is augmenting SSL_CTX_new and setting the desired SSL_OP_NO_SSLv3 on
each newly created SSL context.
#include <stdio.h>
#include <dlfcn.h>
#include <openssl/ssl.h>
static void *lib;
static void *new_sym;
static void *opt_sym;
static void dl() {
char *error;
if (!lib) {
lib = dlopen("libssl.so", RTLD_LAZY|RTLD_LOCAL);
if (!lib) {
fprintf(stderr, "dlopen: %s\n", dlerror());
exit(1);
}
dlerror();
}
if (!new_sym) {
*(void **) &new_sym = dlsym(lib, "SSL_CTX_new");
if ((error = dlerror())) {
fprintf(stderr, "dlsym: %s\n", error);
dlclose(lib);
exit(1);
}
}
if (!opt_sym) {
*(void **) &opt_sym = dlsym(lib, "SSL_CTX_ctrl");
if ((error = dlerror())) {
fprintf(stderr, "dlsym: %s\n", error);
dlclose(lib);
exit(1);
}
}
}
SSL_CTX *SSL_CTX_new(const SSL_METHOD *m)
{
SSL_CTX *ctx;
dl();
ctx = ((SSL_CTX *(*)(const SSL_METHOD*))new_sym)(m);
if (ctx) {
((long (*)(SSL_CTX *, int, long, void*))opt_sym)(ctx, SSL_CTRL_OPTIONS, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3, NULL);
}
return ctx;
}
This is the source of a tiny shared library pre-defining our SSL_CTX_new; to build like e.g.
gcc -ldl -fPIC -shared -o preload.so preload.c
It does the following:
SSL_CTX_new with our own version,
i.e. whenever courier calls SSL_CTX_new our own version gets calleddlopen’s libsslSSL_CTX_new and SSL_CTX_ctrl
(which is the actual function SSL_CTX_set_options calls)SSL_CTX_new to actually create the SSL contextSSL_CTX_ctrl on the new context with the options we want to set (SSL_OP_NO_SSLv3)Courier config files are basically shell scripts which set a environment variables, so we’ll enable it as follows:
cd /etc/courier
cat >>esmtpd >>esmtpd-msa >>esmtpd-ssl \
>>pop3d >>pop3d-ssl \
>>imapd >>imapd-ssl \
>>courierd <<EOF
LD_PRELOAD=/path/to/preload.so
EOF
Then restart each courier service.
Last, we have to verify that our solution actually works:
openssl s_client \
-CApath /etc/ssl/certs/ \
-starttls imap \
-connect localhost:143 \
-crlf -quiet -ssl3 \
<<<LOGOUT
139690858608296:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1261:SSL alert number 40
139690858608296:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:599:
A bunch of errors. “Good”! :)
Let’s see if we can still connect with TLSv1+:
openssl s_client \
-CApath /etc/ssl/certs/ \
-starttls imap \
-connect localhost:143 \
-crlf -quiet -tls1 \
<<<LOGOUT
depth=2 ...
verify return:1
depth=1 ...
verify return:1
depth=0 ...
verify return:1
. OK CAPABILITY completed
* BYE Courier-IMAP server shutting down
LOGOUT OK LOGOUT completed
Awesome. Mission accomplished.
Here’s my cipher list for the interested:
openssl ciphers -v 'HIGH+aRSA:+kEDH:+kRSA:+SHA:+3DES:!kSRP' \
| awk '{ printf "%-28s %-8s %-8s %-18s %-16s\n",$1,$2,$3,$5,$6 }'
Which results in the following ciphers:
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Enc=AES(128) Mac=SHA256
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Enc=AES(256) Mac=SHA256
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Enc=AES(128) Mac=SHA256
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Enc=AESGCM(256) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Enc=AES(256) Mac=SHA256
AES128-GCM-SHA256 TLSv1.2 Kx=RSA Enc=AESGCM(128) Mac=AEAD
AES128-SHA256 TLSv1.2 Kx=RSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Enc=AES(128) Mac=SHA1
DHE-RSA-AES256-SHA SSLv3 Kx=DH Enc=AES(256) Mac=SHA1
DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH Enc=Camellia(256) Mac=SHA1
DHE-RSA-AES128-SHA SSLv3 Kx=DH Enc=AES(128) Mac=SHA1
DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH Enc=Camellia(128) Mac=SHA1
AES256-SHA SSLv3 Kx=RSA Enc=AES(256) Mac=SHA1
CAMELLIA256-SHA SSLv3 Kx=RSA Enc=Camellia(256) Mac=SHA1
AES128-SHA SSLv3 Kx=RSA Enc=AES(128) Mac=SHA1
CAMELLIA128-SHA SSLv3 Kx=RSA Enc=Camellia(128) Mac=SHA1
ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Enc=3DES(168) Mac=SHA1
EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Enc=3DES(168) Mac=SHA1
DES-CBC3-SHA SSLv3 Kx=RSA Enc=3DES(168) Mac=SHA1
Note, that courier actually does not support ECDH key exchange, but I didn’t exclude it for
the sake of simplicity for using the same cipher list for every server (e.g. web etc.)
I just found a solution to bring the monitor back to life without rebooting the box; just ssh into and issue:
$ DISPLAY=:0 xset dpms force off
$ DISPLAY=:0 xset dpms force on
I’m running Gnome3 on Arch Linux, so YMMV.
]]>Enter travis-pecl.
This tiny support bin comes with a Makefile and small PHP scripts to generate the build matrix and check your package.xml file. It supports building PHP in a wide variety of flavors, installing PECL dependencies from the PECL website or from bundled pharext packages and running the testsuite with a comprehensive set of commands.
Let’s look at a few commands with a properly set up environment from the test matrix:
env:
- PHP=5.6 enable_debug=yes with_iconv=yes enable_json=yes
make -f travis/pecl/Makefile php
make -f travis/pecl/Makefile pecl PECL=propro
make -f travis/pecl/Makefile pharext/raphf-phpng
make -f travis/pecl/Makefile ext PECL=http
make -f travis/pecl/Makefile test
Finally, check out the README and have a look at a couple of complete examples here:
]]>I talk about software development, specifically development of and with PHP. We’ve seen some radical proposals in the nearer past and in deed are still seeing those for PHP, the language. Often, I was inclined to think “cool, that’s a great idea, let’s improve in that direction.”
PHP was and is a huge success, it attracts a lot of awesome people, sometimes becoming unhappy with the language’s principles and resulting limitiations, like its simplicity, its forgiving nature and the enigne’s effort to come to an end for this request, i.e. to die. Looking at the larger frameworks which have evolved the last few years, they head into a clear direction: strictly object oriented programming with RidiculouslyLongClassNamesLikeFoundInOtherStrictlyObjectOrientedLanguages. Anything non object oriented seems to be verboten. But this is not of what PHP was meant to be and it is very hard to change something that late in the game in such drastical ways. I don’t think PHP can change as fast as we do, it’s actually much longer around than most of us call ourself programmers.
What I mean to say is, don’t be angry with PHP the language, don’t force it to change in a way it’s not supposed to survive, stop proposing language level changes in a weekly manner, don’t be afraid to change yourself. Don’t be afraid to advance yourself. Don’t be afraid to change the language you program in. BOOM, I said it. Yes, don’t be afraid to explore other possibilities that better support your principles instead of fighting them.
I’m not saying go away, I’m saying go ahead, or at least I mean to.
Sorry for the fast write-up, all the typos and errors. Have a nice start into your week!
]]>I’m still ready & willing to hire a #PHP internals coder to work on PHP fulltime. Amazing place to work: http://t.co/GX4wtPSc
— Don MacAskill (@DonMacAskill) January 18, 2013
Fast-forward five months – now I am very excited to be able to announce that the Awesomes over at SmugMug, Inc. have hired me to work full-time on the core of PHP.
Hide bugs.php.net, expect massive amounts of commits, sleep well. Thank you for reading the simple words of the proudest man alive. Thank you SmugMug!
]]>Nearly a year and 170k downloads after the last release (1.7.4 was released April 2nd 2012).
It fixes a single bug:
The same user (thanks Niko), discovered a peculiarity of libcurl:
Slightly more background information is available at the relevant bug report.
Please leave a comment, if you have an opinion about which component’s behavior is arguable here.
]]>This might be confused with HTTP/2.0
There’s mysqli following this approach, but I think this is pretty odd.
Split the package up in several smaller sub-packages, like:
If you have an opinion, or maybe even a better idea, please leave a comment.
]]>/**
* @param handler a callback accepting Delayer.dispatch as argument
*/
function Delayer(handler) {
var self = this;
this.dispatch = function() {
for (var i = 0; i < self.length; ++i) {
console.log("running delayed init "+i+": "+self[i]);
self[i]();
}
};
if (typeof handler == "function" || handler instanceof Function) {
handler(this.dispatch);
}
}
Delayer.prototype = Array.prototype;
It can be initialized the following way:
/* e.g. with jQuery */
window.delayedInits = new Delayer($(document).ready);
/* e.g. with Facebook */
window.fbDelayedInits = new Delayer(function(dp){window.fbAsyncInit = dp;});
Then you push your work the usual way:
delayedInits.push(function() {alert("Hello, delayed!");});
I more or less lived with that, until a friend of mine got a new iphone… well yeah, one of those i-geeks, and that gadget apparently only supports imap, no pop.
To re-enable imap-before-smtp I wrote a little setuid wrapper, calling vpopmails open_smtp_relay(). This wrapper has to replace the imapd command in your courier-imap startup script and will exec imapd, after opening the smtp relay, wile imap-login is still in place to authenticate via authdaemond’s vchkpw module.
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <vpopmail_config.h>
#include <vauth.h>
#include <vpopmail.h>
#ifndef IMAPD
# define IMAPD "/usr/bin/imapd"
#endif
extern char **environ;
int main(int argc, const char *argv[]) {
if (argc != 2) {
printf("1 NO argc != 2n");
return -1;
}
open_smtp_relay();
/* no need to chown vpopmail.vchkpw the open-smtp file
* because vchkpw used by qmail-pop3d is setuid root */
sleep(1);
if (setgid(VPOPMAILGID) || setuid(VPOPMAILUID)) {
printf("1 NO setuid/gid, getuid=%dn", getuid());
return -2;
}
execl(IMAPD, IMAPD, argv[1], NULL);
printf("1 NO exec %s failedn", IMAPD);
return -3;
}
So while this worked to my satisfaction, I noticed that the tcp.smtp.cdb not always contained the IPs of the open-smtp file:
$ for ip in $(sed -re 's/:.*//' < open-smtp); do
cdbget $ip < tcp.smtp.cdb > /dev/null
|| echo "$ip is missing";
done
I also found out that, while the vpopmail FAQ is claiming that clearopensmtp is requesting locks on the open-smtp(.lock) file, the source does not read like it would.
I opened a bug report for that issue, but as you might have already guessed, I’m running all of this on an archaic debian box, where no upgrades are planned. So I came up with another home-brewed solution:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <vpopmail_config.h>
#include <vauth.h>
#include <vpopmail.h>
#include <fcntl.h>
extern int get_write_lock(FILE*);
extern int lock_reg(int,int,int,off_t,int,off_t);
#define unlock(F) lock_reg(fileno(F), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)
int main(int argc, const char *argv[]) {
FILE *fs_temp, *fs_smtp, *fs_lock = fopen(OPEN_SMTP_LOK_FILE, "w+");
time_t clear = RELAY_CLEAR_MINUTES * 60, now = time(NULL);
int cc = 0, rc = 0;
if (!fs_lock) {
return -1;
}
if (get_write_lock(fs_lock)) {
unlock(fs_lock);
fclose(fs_lock);
return -2;
}
if (!(fs_temp = fopen(OPEN_SMTP_TMP_FILE ".clear", "w"))) {
rc = -3;
} else if (!(fs_smtp = fopen(OPEN_SMTP_CUR_FILE, "r+"))) {
fclose(fs_temp);
rc = -4;
} else {
while (!rc && !feof(fs_smtp)) {
unsigned stime;
char sdata[256];
switch (fscanf(fs_smtp, "%255st%un", sdata, &stime)) {
case 2:
if ((clear + stime) >= now) {
fprintf(fs_temp, "%st%un", sdata, stime);
} else {
++cc;
}
break;
default:
rc = -5;
case EOF:
break;
}
}
fclose(fs_smtp);
fclose(fs_temp);
}
if (!rc) {
if (cc) {
if (rename(OPEN_SMTP_TMP_FILE ".clear", OPEN_SMTP_CUR_FILE)) {
rc = -6;
} else if(update_rules()) {
rc = -7;
}
} else {
unlink(OPEN_SMTP_TMP_FILE ".clear");
}
}
unlock(fs_lock);
fclose(fs_lock);
return rc;
}
It’s not the prettiest piece of code, but it helps.
Well, maybe someone else running last-millenium software finds this useful
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
To me this looks non conforming to the HTTP spec due to the lack of an indicator that the request contains a message body.
Quoting the 4th paragraph of section 4.3 of RFC2616:
The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request’s message-headers. A message-body MUST NOT be included in a request if the specification of the request method (section 5.1.1) does not allow sending an entity-body in requests. A server SHOULD read and forward a message-body on any request; if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.
Huh?
]]>