diff --git a/src/main/java/org/apache/commons/net/ftp/FTP.java b/src/main/java/org/apache/commons/net/ftp/FTP.java index 07420b81d..2beebb0ef 100644 --- a/src/main/java/org/apache/commons/net/ftp/FTP.java +++ b/src/main/java/org/apache/commons/net/ftp/FTP.java @@ -427,6 +427,13 @@ public int appe(final String path) throws IOException { return sendCommand(FTPCmd.APPE, path); } + private static void checkCRLF(final String command, final String args) { + if (command != null && (command.indexOf('\r') >= 0 || command.indexOf('\n') >= 0) + || args != null && (args.indexOf('\r') >= 0 || args.indexOf('\n') >= 0)) { + throw new IllegalArgumentException("Commands and arguments cannot contain CR or LF characters"); + } + } + private String buildMessage(final String command, final String args) { final StringBuilder builder = new StringBuilder(command); if (args != null) { @@ -1296,6 +1303,7 @@ public int sendCommand(final String command) throws IOException { * @throws IOException If an I/O error occurs while either sending the command or receiving the server reply. */ public int sendCommand(final String command, final String args) throws IOException { + checkCRLF(command, args); if (_controlOutput_ == null) { throw new IOException("Connection is not open"); } diff --git a/src/main/java/org/apache/commons/net/nntp/NNTP.java b/src/main/java/org/apache/commons/net/nntp/NNTP.java index c6430cefa..7130df028 100644 --- a/src/main/java/org/apache/commons/net/nntp/NNTP.java +++ b/src/main/java/org/apache/commons/net/nntp/NNTP.java @@ -641,6 +641,10 @@ public int sendCommand(final String command) throws IOException { * @throws IOException If an I/O error occurs while either sending the command or receiving the server reply. */ public int sendCommand(final String command, final String args) throws IOException { + if (command != null && (command.indexOf('\r') >= 0 || command.indexOf('\n') >= 0) + || args != null && (args.indexOf('\r') >= 0 || args.indexOf('\n') >= 0)) { + throw new IllegalArgumentException("Commands and arguments cannot contain CR or LF characters"); + } final StringBuilder builder = new StringBuilder(command); if (args != null) { builder.append(' '); diff --git a/src/main/java/org/apache/commons/net/pop3/POP3.java b/src/main/java/org/apache/commons/net/pop3/POP3.java index a93561ef1..2db9c2f44 100644 --- a/src/main/java/org/apache/commons/net/pop3/POP3.java +++ b/src/main/java/org/apache/commons/net/pop3/POP3.java @@ -277,6 +277,10 @@ public int sendCommand(final String command) throws IOException { * @throws IOException on error */ public int sendCommand(final String command, final String args) throws IOException { + if (command != null && (command.indexOf('\r') >= 0 || command.indexOf('\n') >= 0) + || args != null && (args.indexOf('\r') >= 0 || args.indexOf('\n') >= 0)) { + throw new IllegalArgumentException("Commands and arguments cannot contain CR or LF characters"); + } if (writer == null) { throw new IllegalStateException("Socket is not connected"); } diff --git a/src/main/java/org/apache/commons/net/smtp/SMTP.java b/src/main/java/org/apache/commons/net/smtp/SMTP.java index 6102397cd..9c85ea5cf 100644 --- a/src/main/java/org/apache/commons/net/smtp/SMTP.java +++ b/src/main/java/org/apache/commons/net/smtp/SMTP.java @@ -517,6 +517,10 @@ public int sendCommand(final String command, final String args) throws IOExcepti * @throws IOException */ private int sendCommand(final String command, final String args, final boolean includeSpace) throws IOException { + if (command != null && (command.indexOf('\r') >= 0 || command.indexOf('\n') >= 0) + || args != null && (args.indexOf('\r') >= 0 || args.indexOf('\n') >= 0)) { + throw new IllegalArgumentException("Commands and arguments cannot contain CR or LF characters"); + } final StringBuilder builder = new StringBuilder(command); if (args != null) { if (includeSpace) { diff --git a/src/test/java/org/apache/commons/net/ftp/FTPTest.java b/src/test/java/org/apache/commons/net/ftp/FTPTest.java new file mode 100644 index 000000000..07ecf4e39 --- /dev/null +++ b/src/test/java/org/apache/commons/net/ftp/FTPTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.ftp; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class FTPTest { + + @Test + void testRejectCRInArgs() { + assertThrows(IllegalArgumentException.class, () -> new FTP().sendCommand("RETR", "file\rDELE secret")); + } + + @Test + void testRejectCRLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new FTP().sendCommand("RETR", "file\r\nDELE secret")); + } + + @Test + void testRejectLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new FTP().sendCommand("RETR", "file\nDELE secret")); + } + + @Test + void testRejectLFInCommand() { + assertThrows(IllegalArgumentException.class, () -> new FTP().sendCommand("NOOP\nDELE secret")); + } +} diff --git a/src/test/java/org/apache/commons/net/nntp/NNTPTest.java b/src/test/java/org/apache/commons/net/nntp/NNTPTest.java new file mode 100644 index 000000000..4144b7a22 --- /dev/null +++ b/src/test/java/org/apache/commons/net/nntp/NNTPTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.nntp; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class NNTPTest { + + @Test + void testRejectCRInArgs() { + assertThrows(IllegalArgumentException.class, () -> new NNTP().sendCommand("GROUP", "news\rQUIT")); + } + + @Test + void testRejectCRLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new NNTP().sendCommand("GROUP", "news\r\nQUIT")); + } + + @Test + void testRejectLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new NNTP().sendCommand("GROUP", "news\nQUIT")); + } + + @Test + void testRejectLFInCommand() { + assertThrows(IllegalArgumentException.class, () -> new NNTP().sendCommand("NOOP\nQUIT")); + } +} diff --git a/src/test/java/org/apache/commons/net/pop3/POP3Test.java b/src/test/java/org/apache/commons/net/pop3/POP3Test.java new file mode 100644 index 000000000..c49009bc7 --- /dev/null +++ b/src/test/java/org/apache/commons/net/pop3/POP3Test.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.pop3; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class POP3Test { + + @Test + void testRejectCRInArgs() { + assertThrows(IllegalArgumentException.class, () -> new POP3().sendCommand("USER", "name\rPASS x")); + } + + @Test + void testRejectCRLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new POP3().sendCommand("USER", "name\r\nPASS x")); + } + + @Test + void testRejectLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new POP3().sendCommand("USER", "name\nPASS x")); + } + + @Test + void testRejectLFInCommand() { + assertThrows(IllegalArgumentException.class, () -> new POP3().sendCommand("NOOP\nPASS x")); + } +} diff --git a/src/test/java/org/apache/commons/net/smtp/SMTPTest.java b/src/test/java/org/apache/commons/net/smtp/SMTPTest.java new file mode 100644 index 000000000..73877c90d --- /dev/null +++ b/src/test/java/org/apache/commons/net/smtp/SMTPTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.smtp; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class SMTPTest { + + @Test + void testRejectCRInArgs() { + assertThrows(IllegalArgumentException.class, () -> new SMTP().sendCommand("MAIL", "FROM:\rRCPT TO:")); + } + + @Test + void testRejectCRLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new SMTP().sendCommand("MAIL", "FROM:\r\nRCPT TO:")); + } + + @Test + void testRejectLFInArgs() { + assertThrows(IllegalArgumentException.class, () -> new SMTP().sendCommand("MAIL", "FROM:\nRCPT TO:")); + } + + @Test + void testRejectLFInCommand() { + assertThrows(IllegalArgumentException.class, () -> new SMTP().sendCommand("NOOP\nRSET")); + } +}