Some people seem to have trouble understanding how the STARTTLS command works, and how it interacts with other things like the recordio program, or programs like the "greylite" greylisting program, which works by monitoring the data transfer between the SMTP client and server.
STARTTLS is an extension to the SMTP protocol. It is officially defined in RFC 2487. It's not very difficult to understand- it looks like this:
Client sends ---> EHLO hostname STARTTLS nôðûCF ~!ãP u¶ 1!)âh% RïÐ9÷èIªQé ´>¹·" · YPY IÈLé\ ¼ß½BHºº i(ø÷pOÀ r©>¨, ³CzoÂÙÛW y¡5åòEH â[ÈKøÞ Í q/;T¨Z VƬÖmë ¡ 1<^ªñK¸à *u²Èzuíî ´æ àÁSØÓ HBPAcE4, íD6¼1ÿ~ü¿ ©½Ï¶Ría ... |
<--- Server sends
220 server.xyz NO UCE
250-server.xyz NO UCE 250-STARTTLS 250-SIZE 0 250-PIPELINING 250 8BITMIME 220 Ready for TLS... [ôj/ÿý Ý´Ï å:Ó3 8d£è[8 v\6EÙzQ ª8ð B· Ú} Ï5¡ÏÌí±¦f G.·oº{X1Æ Ój1kÁRᥠ°ºÉr ¢³Qî $ÝïakΣR lÆØG Vü[ö½µ³ ¾ "Ó õÙ&ï îÙW¿.è¿´ 'ö8zIÈ©6 ÆóñK~Nî{ `&¥ëÆ U(0ÔàE¾®ê <¾P¯0 ÜáMÍ Ýix ... |
As you can see, after the client sends "STARTTLS" and the server responds with a 220 message, everything after that is encrypted.
What this means is that programs like "greylite", which work by monitoring the data stream between the client and server, will not work if the client and server are using STARTTLS to secure the connection.
I should explain further: now that I've actually tried it on a test SMTP service on my own server, I can tell you that greylite "works", in as much as the connection goes through un-hindered (greylite dumps the connection into a binary pass-through mode after the server's response to the STARTTLS command.) However, greylite is not able to inspect the MAIL or RCPT commands within a STARTTLS connection, and is therefore unable to do the job for which it was written. My apologies to anybody who may have been confused by the language which was here before.
It also means that, since the encrypted data stream is just as likely to contain a "0x00" byte as any other, and the C language treats the zero byte as an "end of string" marker, programs such like "recordio", which involve themselves in the data stream between the client and qmail-smtpd, are likely to become confused.
You may have noticed me mentioning a program called "greylite" a few times above. This isn't because I'm a big fan of the program- in fact, when I first wrote this page, I hadn't even tried it.
I have since tried it, and I've found a few bugs in it- nothing really serious, just a few things which the author probably didn't think about while writing it. (From greylite version 2.3)
In the main() function of greylite.c, he calls the fork() function.
The fork() function causes the current process to duplicate itself. When a process calls it, TWO processes actually return from it, one being a "child" of the other. The normal routine is for the child process to then call the exec() function, which overwrites itself with a new process.
The fork() function can return one of three values:
If it returns a positive value, the process knows that it is the "parent", the original process which had been running all along, and the actual number returned is the PID (process identifier) of the child process.
If it returns zero, the process knows that it is the "child", the new process which was created. If it needs to know the PID of its parent, usually the parent will have saved that information (in a variable which will have been copied, along with the rest of the process) before calling fork(). If not, the child can call the getppid() function as well.
If it returns a negative value, the fork() call failed, no new process was created, and the value is actually an error code (or the process can inspect the errno variable.
Looking at the code, he never checks for a negative return value. What this means is that if there's a condition which prevents fork() from working (i.e. the kernel's process table is full, the current userid has reached the limit on the number of processes they may start, etc.) greylite will continue along its merry way, oblivious to the fact that anything is wrong.
This is a common mistake among people who aren't used to programming for a *nix environment. I did it myself once... once.
In the proxy_data() function of greylite.c, he uses the poll() function to wait for packets to arrive from either the client or the server. The problem is that on some systems, such as the Darwin kernel, which is the base of Mac OS X, the poll() function is known to not work correctly.
There is an alternative. The select() function can be used for the same purpose- to make the process wait until data is available on one or more file handles, along with a timeout value (so that if no data is available on any of the file handles, select() will return anyway, so the process can do other things, rather than waiting forever.) The select() function is much more widely used- it was the original way to wait for "data or a timeout", and works with every *nix kernel.
I don't feel this is any kind of negative reflection on the author; I wasn't aware of it myself until I tried to run daemontools on OSX and my CPU to jumped to 100% and stayed there.
In the man page, he mentions a GREYLIST environment variable, but the example below it shows a GREYLITE variable being used. Looking at the code, it should be GREYLIST.
Again, just a typo, I make them all the time.
Not a bug, but a suggestion... I would make all of the environment variables which have to do with greylite start with "GREYLITE_" (i.e. "GREYLITE_DBFILE", "GREYLITE_LOGTHRESHOLD", etc.) so they don't accidentally interfere with other variables that people may already be using (the name "GREYLIST" is used as a variable, but not an environment variable, in my qmail-smtpd "run" script, for example.)
I would also have the names be the same as the internal variables they control- trying to remember that the "LOGTHRESHOLD" environment variable sets the "loglevel" variable, or that the DBFILE environment variable overrides the DBNAME constant within the code, just makes things a bit more complicated. I would have used "GREYLITE_LOGLEVEL" and "GREYLITE_DBNAME", so the names are consistent.
I am looking at the program with an eye towards fixing the problems and using it on my own server. I will detail any further bugs I find on this page.
Apparently, at some point in the past, the author of greylite received error reports from two different "qmailrocks" users, who were having trouble with greylite, when "used with the JMS patch". His response was to post this on his web site:
When I first emailed him about the statement on his web site, his response tried to claim that he wasn't blaming my patch for the problem. Read the text above, and you decide if you believe this or not.
I don't really have a problem with that, however... the facts speak for themselves. What I have a problem with, is the fact that he added this to his web page, WITHOUT HAVING EVER CONTACTED ME. He never asked me for any help in resolving the issue, he never even contacted me to TELL me that there was an issue- he just put a notice on his web page which recommends that people avoid my patch.
I have asked him three times why he never contacted me about it. He refuses to answer the question. The only conclusion I can draw is that he is more interested in pointing fingers at somebody else, than he is in figuring out what the real problem is, and providing his users with a solution to their problems.
In fact, the original version of the web page you are reading right now was written, at least in part, to illustrate the real cause of the problem that his users (at least, those of his users who are also qmailrocks users) were reporting.
From what it says on his web site, it looked to me like the problem was with the STARTTLS command itself. I assumed that's what it was, because recordio has the same issue.
However, I was wrong about that. He says, and I have verified in the code, that greylite handles the STARTTLS command by dumping the connection into a binary pass-through mode (the "proxy_data()" function,) and before this check is done, if the server had responded with an error message (status code starting with 4 or 5) it loops back to wait for the next command.
So it doesn't look like that was the cause of the problems.
He also states...
On Mar 9, 2008, at 08:00 , John Simpson wrote:
> ...
> please explain what you mean by the term "qmailrocks plain"- are
> you trying to claim that there's a version of qmailrocks floating
> around which doesn't have my patch as part of it? if so, send me
> the URL where i can see it- because both the "stable" and
> "development" releases on
http://www.qmailrocks.org/ COME WITH MY
> PATCH PRE-INSTALLED.
> ...
I don't use qmailrocks thus I could only rely on user feedback. As
per the investigation, you know that it is very difficult to drive
people to do it, especially when they are not proficient with the
software. In my about 20 emails with 2 different people showing the
same problem, I obtained that qmailrocks patched with your patch shows
the behavior, qmailrocks in which your patch is not applied does not,
and qmailrock + your patch contacted via tcp does work again.
Unless I'm missing something here, he's admitting that he relied on bug reports from people who "are not proficient with the software" (which is about 95% of qmailrocks' users.) He also admits and demonstrates that he knows nothing about qmailrocks, and obviously he knows nothing about my patch.
And yet somehow, this clown feels justified in giving people advice about my patch?
I have explained to him that qmailrocks was built around my combined patch, that there is no such thing as "qmailrocks in which your patch is not applied", and that because of this, the original bug reports were probably wrong. However, he continues to use the same excuse, over and over again- which only demonstrates that he's either ignoring me, he doesn't want to admit that he made a mistake, or he truly doesn't understand that he's wrong.
In any event, he's making himself look like an idiot.
Of course, since he didn't tell me about the original problems when they happened, and doesn't seem to want to give me any details about them now, I don't have any way to know what the original problems were. I can, however, tell you that I have tried greylite on my own server, with version 7.05 of my combined patch, and it does work.
I suspect the real problem is that the people who reported these issues had already installed greylite and had it working, and then tried to upgrade to a current version of the patch without understanding the issues involve with upgrading... and instead of reading my web site for help, or emailing me directly to ask for help (I would have directed them to my web site), or even asking for help on the qmailrocks mailing list (where other people would have directed them to my web site), they decided to ask the author of greylite- and rather than trying to understand the real problem, he took them at their word (even though he admits that he knew they were "not proficient with the software") and blamed it on my patch.
All of which leads back to the main problem- he never contacted me about the problem at all.
I should also point out that the comment "the STARTTLS command is useless after all" on his web page, is totally wrong. I'm sorry, but I have a client (an ISP) with several thousand customers who would probably disagree with you. Their MUAs don't support any kind of encrypted SMTP other than using STARTTLS, and my client (the ISP) wisely refuses to allow the AUTH command on a channel which is not encrypted.
In fact, the opposite seems to be true- not only for SMTP, but for several other protocols as well (POP3, IMAP, XMPP, LDAP, etc.) STARTTLS even has its own RFC, which is part of the "standards track", meaning it is recognized as the best way to do the job. Just because there are other ways to do encrypted SMTP (i.e. running normal SMTP within an SSL tunnel on port 465, which was being done before STARTTLS existed, and is still being done by many people today) doesn't mean those ways are necessarily better. (For the record, my own server supports BOTH ways, STARTTLS and SSL-SMTP.)
I honestly have no idea why he would say this, unless he has some personal stake in seeing people not use STARTTLS. Maybe the fact that it prevents greylite from working?
He didn't see fit to tell me when he felt there was a problem with my code, and he obviously doesn't want to talk to me about this in a mature or professional manner, so to put it very bluntly, I give up. Some people just plain don't want to learn, and don't care about bad-mouthing other people. If he happens to visit this web page and find the bug reports above, more power to him.
And that's really sad- because, other than the minor problems I've found so far, greylite seems to be a pretty good program. I like the idea of applying different rules based on the country in which the IP address lives, for example. I'm thinking seriously about using it on my own server, instead of my own jgreylist program (which only looks at the source IP, not the sender or recipient.) I will, of course, fix the program if I do so.
Either that, or I'll just write a new greylisting program, which uses the "monitor the packets" idea, but which IS compatible with the STARTTLS command (if qmail-smtpd is using my combined patch, of course.)
If you are using my patch because it was included as part of qmailrocks, and you haven't done so already, you should seriously look into upgrading to a current version of the patch and away from the garbage that the qmailrocks installed on your machine.
And yes, if you think that upgrading will be "hard", then that's probably because you don't understand how qmail works in the first place, and in that case you're right- it WILL be hard.
However, if you're willing and able to spend the time and effort to learn how qmail was designed to work, and you are familiar enough with *nix system administration to be trusted with running a server in the first place, then you CAN upgrade to a much more secure server- and by the time you're finished, you will have a much better understanding of how your server works... which is a good thing to have, when your server breaks.
And regardless of how you added STARTTLS support to your SMTP service... be aware that using recordio will cause the connection to break soon after the STARTTLS command has been sent and accepted, and greylite will not be able to read the sender and recipient from the connection and therefore will not be able to do its job.
If you are using my patch, version 5f or later (qmailrocks uses version 5, you should upgrade), creating a "DENY_TLS=1" envirionment variable will make qmail-smtpd not advertise or accept the STARTTLS command. You may want to do this for any SMTP service on port 25 with which you plan to use recordio, greylite, or any other program which involves itself in the connection.
And if you're setting up an AUTH-only STARTTLS service on port 587, you don't need to use a greylisting program to begin with- even if the spammers DO connect to your port 587, if they don't have a valid ID and password for your server, they won't be able to send mail (and if they DO have a valid ID and password, you have bigger problems.)