summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-12-03 07:38:22 (GMT)
committerGeorg Brandl <georg@python.org>2010-12-03 07:38:22 (GMT)
commit1e5c5f8f7d507af580486529399f12f7e2bbf70a (patch)
treed55d91fc4b5e7a303756376fe19e7cc277bf9268 /Lib
parent106a54d764f1f796a67c4dfef8c98b1a7f8bf183 (diff)
downloadcpython-1e5c5f8f7d507af580486529399f12f7e2bbf70a.zip
cpython-1e5c5f8f7d507af580486529399f12f7e2bbf70a.tar.gz
cpython-1e5c5f8f7d507af580486529399f12f7e2bbf70a.tar.bz2
#1745035: add limits for command and data size to smtpd; patch by Savio Sena.
Diffstat (limited to 'Lib')
-rwxr-xr-xLib/smtpd.py24
-rw-r--r--Lib/test/test_smtpd.py18
2 files changed, 42 insertions, 0 deletions
diff --git a/Lib/smtpd.py b/Lib/smtpd.py
index 23787fd..599e79b 100755
--- a/Lib/smtpd.py
+++ b/Lib/smtpd.py
@@ -109,6 +109,9 @@ class SMTPChannel(asynchat.async_chat):
COMMAND = 0
DATA = 1
+ data_size_limit = 33554432
+ command_size_limit = 512
+
def __init__(self, server, conn, addr):
asynchat.async_chat.__init__(self, conn)
self.smtp_server = server
@@ -121,6 +124,7 @@ class SMTPChannel(asynchat.async_chat):
self.rcpttos = []
self.received_data = ''
self.fqdn = socket.getfqdn()
+ self.num_bytes = 0
try:
self.peer = conn.getpeername()
except socket.error as err:
@@ -262,6 +266,15 @@ class SMTPChannel(asynchat.async_chat):
# Implementation of base class abstract method
def collect_incoming_data(self, data):
+ limit = None
+ if self.smtp_state == self.COMMAND:
+ limit = self.command_size_limit
+ elif self.smtp_state == self.DATA:
+ limit = self.data_size_limit
+ if limit and self.num_bytes > limit:
+ return
+ elif limit:
+ self.num_bytes += len(data)
self.received_lines.append(str(data, "utf8"))
# Implementation of base class abstract method
@@ -270,6 +283,11 @@ class SMTPChannel(asynchat.async_chat):
print('Data:', repr(line), file=DEBUGSTREAM)
self.received_lines = []
if self.smtp_state == self.COMMAND:
+ if self.num_bytes > self.command_size_limit:
+ self.push('500 Error: line too long')
+ self.num_bytes = 0
+ return
+ self.num_bytes = 0
if not line:
self.push('500 Error: bad syntax')
return
@@ -290,6 +308,11 @@ class SMTPChannel(asynchat.async_chat):
else:
if self.smtp_state != self.DATA:
self.push('451 Internal confusion')
+ self.num_bytes = 0
+ return
+ if self.num_bytes > self.data_size_limit:
+ self.push('552 Error: Too much mail data')
+ self.num_bytes = 0
return
# Remove extraneous carriage returns and de-transparency according
# to RFC 821, Section 4.5.2.
@@ -307,6 +330,7 @@ class SMTPChannel(asynchat.async_chat):
self.rcpttos = []
self.mailfrom = None
self.smtp_state = self.COMMAND
+ self.num_bytes = 0
self.set_terminator(b'\r\n')
if not status:
self.push('250 Ok')
diff --git a/Lib/test/test_smtpd.py b/Lib/test/test_smtpd.py
index 3d55bb2..a4cd670 100644
--- a/Lib/test/test_smtpd.py
+++ b/Lib/test/test_smtpd.py
@@ -121,6 +121,24 @@ class SMTPDChannelTest(TestCase):
self.assertEqual(self.channel.socket.last,
b'451 Internal confusion\r\n')
+ def test_command_too_long(self):
+ self.write_line(b'MAIL from ' +
+ b'a' * self.channel.command_size_limit +
+ b'@example')
+ self.assertEqual(self.channel.socket.last,
+ b'500 Error: line too long\r\n')
+
+ def test_data_too_long(self):
+ # Small hack. Setting limit to 2K octets here will save us some time.
+ self.channel.data_size_limit = 2048
+ self.write_line(b'MAIL From:eggs@example')
+ self.write_line(b'RCPT To:spam@example')
+ self.write_line(b'DATA')
+ self.write_line(b'A' * self.channel.data_size_limit +
+ b'A\r\n.')
+ self.assertEqual(self.channel.socket.last,
+ b'552 Error: Too much mail data\r\n')
+
def test_need_MAIL(self):
self.write_line(b'RCPT to:spam@example')
self.assertEqual(self.channel.socket.last,