Kindly notice that citserver v8.24 segfaults when asked to transmit a
certain sort of message. Here are the details and a tested patch.
Harry
Details:
Using msmtp on a client system hoping to send via a citadel server, this appeared:
me@mysys$msmtp -C msmtp.conf d...@spamme.com
msmtp: cannot read from TLS connection: A TLS packet with unexpected length was received.
msmtp: could not send mail (account default from msmtp.conf)
This was a result of citserver segfaulting and restarting itself.
A gdb session shows citserver 8.24 segfaults as follows:
...
citserver[4201]: open_databases() finished
citserver[4201]: Changing uid to 110
citserver[4201]: libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3
[New Thread 0x7ffff0d60700 (LWP 4209)]
[New Thread 0x7ffff0c5f700 (LWP 4210)]
citserver[4201]: nothing to do for <Global Address Book>
citserver[4201]: SMTPCQ: processing outbound queue
citserver[4201]: SMTPCQ: queue run completed; 0 messages processed 0 activated
citserver[4201]: network: no neighbor nodes are configured - not polling.
citserver[4201]: No external notifiers configured on system/user
citserver[4201]: -- db checkpoint --
citserver[4201]: New client socket 38
citserver[4201]: Session (SMTPs-MTA) started from ceo1home.dontspamme.com (192.168.29.102)
citserver[4201]: SSL/TLS using DHE-RSA-AES128-SHA on TLSv1/SSLv3 (128 of 128 bits)
citserver[4201]: SMTP server: EHLO localhost
citserver[4201]: SMTP server: AUTH LOGIN
citserver[4201]: SMTP server: ZnMx
citserver[4201]: LDAP bind DN: cn=directory manager,dc=dontspamme,dc=com
citserver[4201]: LDAP search: (&(objectclass=posixAccount)(uid=fs1))
citserver[4201]: dn = cn=fs1,ou=people,dc=dontspamme,dc=com
citserver[4201]: cn = fs1
citserver[4201]: uidNumber = 1501
citserver[4201]: SMTP server: c2hhZXllaWJhZXNoZWU=
citserver[4201]: LDAP: trying to bind as cn=fs1,ou=people,dc=dontspamme,dc=com
citserver[4201]: LDAP: bind succeeded
citserver[4201]: Context: <fs1> logged in
citserver[4201]: CtdlCreateRoom(name=Mail, type=4, view=1)
citserver[4201]: Mail already exists.
citserver[4201]: CtdlCreateRoom(name=Sent Items, type=4, view=1)
citserver[4201]: Sent Items already exists.
citserver[4201]: CtdlCreateRoom(name=Trash, type=4, view=1)
citserver[4201]: Trash already exists.
citserver[4201]: CtdlCreateRoom(name=Drafts, type=4, view=1)
citserver[4201]: Drafts already exists.
citserver[4201]: CtdlCreateRoom(name=Calendar, type=4, view=3)
citserver[4201]: Calendar already exists.
citserver[4201]: CtdlCreateRoom(name=Tasks, type=4, view=4)
citserver[4201]: Tasks already exists.
citserver[4201]: CtdlCreateRoom(name=Notes, type=4, view=5)
citserver[4201]: Notes already exists.
citserver[4201]: LDAP bind DN: cn=directory manager,dc=dontspamme,dc=com
citserver[4201]: LDAP search: cn=fs1,ou=people,dc=dontspamme,dc=com
citserver[4201]: LDAP search, got user details for vcard.
citserver[4201]: LDAP Detected vcard change.
citserver[4201]: CC[1]MSGFinal selection: 0000000010.My Citadel Config (Sent Items)
citserver[4201]: CC[1]MSG<0000000010.My Citadel Config> 2 new of 2 total messages
citserver[4201]: Part 1 contains a vCard! Loading...
citserver[4201]: Searching for EUID <Citadel vCard: personal card for fs1 at email2> in <Global Address Book>
citserver[4201]: returning msgnum = 220
citserver[4201]: Delete directory entry: f...@dontspamme.com --> fs1 @ email2
citserver[4201]: Directory key is <f...@dontspamme.com>
citserver[4201]: Indexing message #223 <Citadel vCard: personal card for fs1 at email2> in <Global Address Book>
citserver[4201]: Checking for <f...@dontspamme.com>...
citserver[4201]: Directory key is <f...@dontspamme.com>
citserver[4201]: Adding fs1 @ email2 (f...@dontspamme.com) to directory
citserver[4201]: Create directory entry: f...@dontspamme.com --> fs1 @ email2
citserver[4201]: Directory key is <f...@dontspamme.com>
citserver[4201]: CC[1]MSG<> 0 new of 0 total messages
citserver[4201]: CtdlCreateRoom(name=Contacts, type=4, view=2)
citserver[4201]: Contacts already exists.
citserver[4201]: CC[1]MSG<Lobby> 0 new of 0 total messages
citserver[4201]: SMTP authenticated fs1
citserver[4201]: SMTP server: MAIL FROM:<erasedbecauseidontwantspam.com>
citserver[4201]: SMTP server: RCPT TO:<erasedbecauseidontwantspam.com>
citserver[4201]: SMTP server: DATA
citserver[4201]: Converting message...
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff0d60700 (LWP 4209)]
0x000000000046ef0d in smtp_data (offset=<optimized out>, flags=<optimized out>) at modules/smtp/serv_smtp.c:833
833 modules/smtp/serv_smtp.c: No such file or directory.
(gdb) bt
#0 0x000000000046ef0d in smtp_data (offset=<optimized out>, flags=<optimized out>) at modules/smtp/serv_smtp.c:833
#1 0x000000000046ecb8 in smtp_command_loop () at modules/smtp/serv_smtp.c:1048
#2 0x0000000000417ec7 in worker_thread (blah=blah@entry=0x0) at sysdep.c:1444
#3 0x00000000004350c5 in CTC_backend (supplied_start_routine=0x417bc0 <worker_thread>) at threads.c:153
#4 0x00007ffff6d31182 in start_thread (arg=0x7ffff0d60700) at pthread_create.c:312
#5 0x00007ffff593730d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) bt
#0 0x000000000046ef0d in smtp_data (offset=<optimized out>, flags=<optimized out>) at modules/smtp/serv_smtp.c:833
#1 0x000000000046ecb8 in smtp_command_loop () at modules/smtp/serv_smtp.c:1048
#2 0x0000000000417ec7 in worker_thread (blah=blah@entry=0x0) at sysdep.c:1444
#3 0x00000000004350c5 in CTC_backend (supplied_start_routine=0x417bc0 <worker_thread>) at threads.c:153
#4 0x00007ffff6d31182 in start_thread (arg=0x7ffff0c5f700) at pthread_create.c:312
#5 0x00007ffff593730d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) info locals
validemail = 0
CCC = 0x7fffdc000940
body = 0x0
defbody = 0x0
msg = 0x7fffdc009dc0
msgnum = -1
nowstamp = "Tue, 22 Jul 2014 12:01:42 -0500", '\000' <repeats 1905 times>...
valid = <optimized out>
scan_errors = <optimized out>
i = <optimized out>
sSMTP = 0x7fffdc016510(gdb) p msg->cm_fields['F']
$1 = 0x0
(gdb)
The relevant code is from modules/serv_smtp.c line 833:
if ( (CCC->logged_in) && (config.c_rfc822_strict_from != CFG_SMTP_FROM_NOFILTER) ) {
int validemail = 0;
if (!IsEmptyStr(msg->cm_fields['F']) &&
((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) ||
(config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT) ) )
{
..
Notice in libcitadel.h we have:
#ifndef IsEmptyStr
#define IsEmptyStr(a) ((a)[0] == '\0')
#endif
Which creates a segfault when asked to check whether a null pointer is an empty string.
It is best practice of course to rename the function everywhere, and this possible
change in libcitadel.h:
#ifndef IsNullOrEmptyStr
#define IsNullOrEmptyStr(a) ( ( (a) == NULL) || ((a)[0] == '\0') )
#endif
Another option that might only solve the immediate problem:
if ( (msg->cm_fields['F']!=NULL) && !IsEmptyStr(msg->cm_fields['F']) &&
((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) ||
(config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT) ) )
{
As I'm not one of the committers prepared to patch everywhere the function
is used, in the 'ugly hack' category I've made this change to libcitadel.h
-- libcitadel-8.24/lib/libcitadel.h 2014-01-27 09:42:11.000000000 -0600
+++ libcitadel-8.24patched/lib/libcitadel.h 2014-07-22 12:29:21.738515758 -0500
@@ -107,7 +107,7 @@
#define BLOG_EUIDBUF_SIZE 40
#ifndef IsEmptyStr
-#define IsEmptyStr(a) ((a)[0] == '\0')
+#define IsEmptyStr(a) ( ( (a) == NULL ) || ((a)[0] == '\0') )
#endif
@@ -427,7 +427,7 @@
char *memreadlinelen(char *start, char *buf, int maxlen, int *retlen);
const char *cmemreadline(const char *start, char *buf, int maxlen);
const char *cmemreadlinelen(const char *start, char *buf, int maxlen, int *retlen);
-#define IsEmptyStr(a) ((a)[0] == '\0')
+//#define IsEmptyStr(a) ((a)[0] == '\0')
#define num_parms(source) num_tokens(source,(char)'|')
int stripout(char *str, char leftboundary, char rightboundary);
long stripallbut(char *str, char leftboundary, char rightboundary);
which resolved the segfault, and possibly prevented others, but I hope
the maintainers choose to implement one of the first two suggested
fixes.
Harry