Skip to content

Commit c66429a

Browse files
committed
GH-865: replace %h in HostName SSH config
OpenSSH does so. It enables for instance to write an SSH host entry Host foo* HostName %h.example.com to resolve "foobar" to "foobar.example.com" and "foobaz" to "foobaz.example.com".
1 parent 4eccf49 commit c66429a

3 files changed

Lines changed: 43 additions & 6 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
* [GH-814](https://github.com/apache/mina-sshd/pull/814) Include a fix for CVE-2020-36843 in optional dependency net.i2p.crypto:eddsa:0.3.0: perform the missing range check in Apache MINA SSHD before delegating to the signature verification in net.i2p.crypto:eddsa:0.3.0. This means that using net.i2p.crypto:eddsa:0.3.0 in Apache MINA SSHD is
4646
safe despite that CVE in the dependency.
47+
* [GH-865](https://github.com/apache/mina-sshd/issues/865) replace `%h` in `HostName` SSH config
4748

4849
## Potential Compatibility Issues
4950

sshd-common/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ public static HostConfigEntryResolver toHostConfigEntryResolver(Collection<? ext
647647
String temp = entry.getHostName(); // Remember that this was null above.
648648
if (temp == null || temp.isEmpty()) {
649649
entry.setHostName(host);
650+
} else {
651+
entry.setHostName(substituteHostName(temp, host));
650652
}
651653
temp = entry.getUsername();
652654
if (temp == null || temp.isEmpty()) {
@@ -919,6 +921,38 @@ public static String resolveIdentityFilePath(String id, String host, int port, S
919921
return sb.toString();
920922
}
921923

924+
private static String substituteHostName(String host, String originalHostName) {
925+
int len = host.length();
926+
int j = host.indexOf(PATH_MACRO_CHAR);
927+
if (j < 0) {
928+
return host;
929+
}
930+
StringBuilder result = new StringBuilder(len);
931+
result.append(host.substring(0, j));
932+
for (int i = j; i < len; i++) {
933+
char ch = host.charAt(i);
934+
if (ch == PATH_MACRO_CHAR) {
935+
i++;
936+
ValidateUtils.checkTrue(i < len, "Missing macro modifier in hostname %s", host);
937+
ch = host.charAt(i);
938+
switch (ch) {
939+
case PATH_MACRO_CHAR:
940+
result.append(ch);
941+
break;
942+
case REMOTE_HOST_MACRO:
943+
result.append(originalHostName);
944+
break;
945+
default:
946+
ValidateUtils.throwIllegalArgumentException("Bad modifier '%s' in hostname %s", String.valueOf(ch),
947+
host);
948+
}
949+
} else {
950+
result.append(ch);
951+
}
952+
}
953+
return result.toString();
954+
}
955+
922956
/**
923957
* @return The default {@link Path} location of the OpenSSH hosts entries configuration file
924958
*/

sshd-common/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,6 @@
3636
import org.junit.jupiter.api.Test;
3737
import org.junit.jupiter.api.TestMethodOrder;
3838

39-
import static org.junit.jupiter.api.Assertions.assertEquals;
40-
import static org.junit.jupiter.api.Assertions.assertFalse;
41-
import static org.junit.jupiter.api.Assertions.assertNotNull;
42-
import static org.junit.jupiter.api.Assertions.assertNull;
43-
import static org.junit.jupiter.api.Assertions.assertTrue;
44-
4539
/**
4640
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
4741
*/
@@ -95,6 +89,14 @@ void wildcardHostname() throws Exception {
9589
expect("foo.example.com", 2022, "testuser", resolved);
9690
}
9791

92+
@Test
93+
void substituteHostname() throws Exception {
94+
HostConfigEntry entry = new HostConfigEntry("foo*", "b%%ar%h.org", -1, "test");
95+
HostConfigEntry resolved = HostConfigEntry.toHostConfigEntryResolver(Collections.singleton(entry))
96+
.resolveEffectiveHost("fooby", 0, null, "", null, null);
97+
expect("b%arfooby.org", 22, "test", resolved);
98+
}
99+
98100
@Test
99101
void defaults() throws Exception {
100102
HostConfigEntry entry = new HostConfigEntry("foo*", "bar.example.com", 22, "test");

0 commit comments

Comments
 (0)