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







Reply via email to