CVS: tmda/TMDA ChangeLog, 1.289, 1.290 Defaults.py, 1.186, 1.187 Util.py, 1.107, 1.108
"Jason R. Mastaler" <[email protected]>
| Newsgroups | gmane.mail.spam.tmda.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/tmda/tmda/TMDA In directory sc8-pr-cvs1:/tmp/cvs-serv15319/TMDA Modified Files: ChangeLog Defaults.py Util.py Log Message: Bugfix/security. It looks like this week's TMDA flame-war on the qmail list did have one positive outcome, and that is a new method of invoking /usr/sbin/sendmail that doesn't use the shell. Thus we avoid the possible security implications as well as argument quoting and escaping issues. You can avoid the shell by passing a tuple of arguments to Util.pipecmd() as the command instead of a string. This will cause the popen2.Popen3() code to execvp() "/usr/bin/sendmail" with these arguments exactly, with no trip through any shell. We already knew this, as ancient TMDA did exactly this. The problem was that we kept getting burned by silent failures in the case of a non-zero exit from the child process (e.g, if /usr/sbin/sendmail was a truncated file, the message would silently be dropped on the floor). What I didn't realize is that I needed to call wait(), capturing the return value, and then use os.WIFEXITED(), os.WEXITSTATUS(), and friends to get the exit status of the invoked command. Our Util.pipecmd() function already does the above, so we just had to pass the arguments in as a tuple, and now we get the best of both worlds. The scary security warning has been removed from the Defaults.OUTGOINGMAIL comments. Thanks to Chuck Cazabon (private e-mail xchange) for helping me iron this out. Index: ChangeLog =================================================================== RCS file: /cvsroot/tmda/tmda/TMDA/ChangeLog,v retrieving revision 1.289 retrieving revision 1.290 diff -u -r1.289 -r1.290 --- ChangeLog 9 Oct 2003 23:51:32 -0000 1.289 +++ ChangeLog 10 Oct 2003 03:29:39 -0000 1.290 @@ -1,5 +1,9 @@ 2003-10-09 Jason R. Mastaler <[email protected]> + * Util.py (sendmail): If using /usr/sbin/sendmail, pass a tuple of + arguments into pipecmd() instead of a string to avoid the shell + completely. Also, add '-i' to the list of args. + * Version.py (PLATFORM): Use the more descriptive 'platform' module if it's available. Index: Defaults.py =================================================================== RCS file: /cvsroot/tmda/tmda/TMDA/Defaults.py,v retrieving revision 1.186 retrieving revision 1.187 diff -u -r1.186 -r1.187 --- Defaults.py 23 Jul 2003 20:01:05 -0000 1.186 +++ Defaults.py 10 Oct 2003 03:29:39 -0000 1.187 @@ -189,15 +189,7 @@ # # "sendmail" # Deliver messages via the command line interface to the sendmail -# program (/usr/sbin/sendmail). Use at your own risk. "smtp" is -# highly recommended. -# -# SECURITY WARNING: The 'sendmail' method is not secure. Because -# this method uses popen(), it goes through the shell. It does not -# scan the arguments for potential exploits and so it should be -# considered unsafe. For performance reasons, it's not recommended -# either -- use the 'smtp' method instead, even if -# MAIL_TRANSFER_AGENT is "sendmail". +# program (/usr/sbin/sendmail). # # Default is "smtp" if not vars().has_key('OUTGOINGMAIL'): Index: Util.py =================================================================== RCS file: /cvsroot/tmda/tmda/TMDA/Util.py,v retrieving revision 1.107 retrieving revision 1.108 diff -u -r1.107 -r1.108 --- Util.py 1 Oct 2003 22:46:42 -0000 1.107 +++ Util.py 10 Oct 2003 03:29:39 -0000 1.108 @@ -564,8 +564,12 @@ server.sendmail(envsender, envrecip, msgstr) server.quit() elif Defaults.OUTGOINGMAIL == 'sendmail': - cmd = "%s -f '%s' -- '%s'" % (Defaults.SENDMAIL_PROGRAM, - envsender, envrecip) + # You can avoid the shell by passing a tuple of arguments as + # the command instead of a string. This will cause the + # popen2.Popen3() code to execvp() "/usr/bin/sendmail" with + # these arguments exactly, with no trip through any shell. + cmd = (Defaults.SENDMAIL_PROGRAM, '-i', + '-f', envsender, '--', envrecip) pipecmd(cmd, msgstr) else: raise Errors.ConfigError, \