237 lines
12 KiB
Diff
237 lines
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: AlphaKR93 <dev@alpha93.kr>
|
|
Date: Tue, 5 Nov 2024 18:31:09 +0900
|
|
Subject: [PATCH] Hashed rcon password
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
index 3dd5c7441bb300ca17d717af37edbefb89db4b2f..df367fbb8c582614aaf2087aa37d5e47247af810 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
@@ -73,7 +73,6 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
|
public final int queryPort;
|
|
public final boolean enableRcon;
|
|
public final int rconPort;
|
|
- public final String rconPassword;
|
|
public final boolean hardcore;
|
|
public final boolean allowNether;
|
|
public final boolean spawnMonsters;
|
|
@@ -113,6 +112,25 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
|
|
|
public final String rconIp; // Paper - Configurable rcon ip
|
|
|
|
+ // Plazma start - hashed rcon password
|
|
+ private final boolean rconHash;
|
|
+ private final int rconHashIterationCount;
|
|
+ private final byte[] rconSalt;
|
|
+ private final String rconPassword;
|
|
+
|
|
+ private static final @Nullable javax.crypto.SecretKeyFactory HASH_INSTANCE;
|
|
+ static {
|
|
+ @Nullable javax.crypto.SecretKeyFactory factory;
|
|
+ try {
|
|
+ factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512/256");
|
|
+ } catch (Exception e) {
|
|
+ LOGGER.error("Failed to initialize rcon hash instance", e);
|
|
+ factory = null;
|
|
+ }
|
|
+ HASH_INSTANCE = factory;
|
|
+ }
|
|
+ // Plazma end - hashed rcon password
|
|
+
|
|
// CraftBukkit start
|
|
public DedicatedServerProperties(Properties properties, OptionSet optionset) {
|
|
super(properties, optionset);
|
|
@@ -126,7 +144,7 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
|
this.queryPort = this.get("query.port", 25565);
|
|
this.enableRcon = this.get("enable-rcon", false);
|
|
this.rconPort = this.get("rcon.port", 25575);
|
|
- this.rconPassword = this.get("rcon.password", "");
|
|
+ // this.rconPassword = this.get("rcon.password", ""); // Plazma - hashed rcon password
|
|
this.hardcore = this.get("hardcore", false);
|
|
this.allowNether = this.get("allow-nether", true);
|
|
this.spawnMonsters = this.get("spawn-monsters", true);
|
|
@@ -179,7 +197,82 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
|
final String rconIp = this.getStringRaw("rcon.ip");
|
|
this.rconIp = rconIp == null ? this.serverIp : rconIp;
|
|
// Paper end - Configurable rcon ip
|
|
+
|
|
+ // Plazma start - hashed rcon password
|
|
+ this.rconHash = this.get("rcon.hash", false);
|
|
+ this.rconHashIterationCount = this.get("rcon.hash.iteration-count", Character.MAX_VALUE);
|
|
+ this.rconSalt = this.rconSalt();
|
|
+ this.rconPassword = this.rconPassword();
|
|
+ // Plazma end - hashed rcon password
|
|
+ }
|
|
+
|
|
+ // Plazma start - hashed rcon password
|
|
+ private byte[] rconSalt() {
|
|
+ if (!this.rconHash) return org.plazmamc.plazma.constants.Null.BYTE;
|
|
+
|
|
+ String salt = this.get("rcon.hash.salt", "");
|
|
+ if (!salt.isBlank()) {
|
|
+ try {
|
|
+ return java.util.HexFormat.of().parseHex(salt);
|
|
+ } catch (Exception e) {
|
|
+ LOGGER.error("Invalid RCON salt detected! RCON will be disabled");
|
|
+ return org.plazmamc.plazma.constants.Null.BYTE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ byte[] newSalt = new byte[16];
|
|
+ (new java.security.SecureRandom()).nextBytes(newSalt);
|
|
+ salt = java.util.HexFormat.of().formatHex(newSalt);
|
|
+ this.set("rcon.hash.salt", salt);
|
|
+ return newSalt;
|
|
+ }
|
|
+
|
|
+ private String rconPassword() {
|
|
+ String hashed = this.get("rcon.hash.password", "");
|
|
+ if (!hashed.isBlank()) {
|
|
+ try {
|
|
+ java.util.HexFormat.of().parseHex(hashed);
|
|
+ } catch (Exception e) {
|
|
+ LOGGER.error("Invalid hashed RCON password detected! RCON will be disabled");
|
|
+ return "";
|
|
+ }
|
|
+ return hashed;
|
|
+ }
|
|
+
|
|
+ String decoded = this.get("rcon.password", "");
|
|
+ if (decoded.isBlank() || HASH_INSTANCE == null || this.rconSalt.length == 0) return decoded;
|
|
+
|
|
+ try {
|
|
+ final java.security.spec.KeySpec spec = new javax.crypto.spec.PBEKeySpec(decoded.toCharArray(), this.rconSalt, this.rconHashIterationCount, 256);
|
|
+ byte[] hashedByte = HASH_INSTANCE.generateSecret(spec).getEncoded();
|
|
+ hashed = java.util.HexFormat.of().formatHex(hashedByte);
|
|
+ this.set("rcon.hash.password", hashed);
|
|
+ this.remove("rcon.password");
|
|
+ return hashed;
|
|
+ } catch (Exception e) {
|
|
+ LOGGER.error("Failed to encode rcon password", e);
|
|
+ return "";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public Boolean shouldStartRCON() {
|
|
+ return this.enableRcon && !this.rconPassword.isBlank();
|
|
+ }
|
|
+
|
|
+ public Boolean matchRconPassword(String value) {
|
|
+ if (this.rconSalt.length == 0 || HASH_INSTANCE == null) return this.rconPassword.equals(value);
|
|
+
|
|
+ try {
|
|
+ final java.security.spec.KeySpec spec = new javax.crypto.spec.PBEKeySpec(value.toCharArray(), this.rconSalt, this.rconHashIterationCount, 256);
|
|
+ byte[] hashedByte = HASH_INSTANCE.generateSecret(spec).getEncoded();
|
|
+ String hashed = java.util.HexFormat.of().formatHex(hashedByte);
|
|
+ return this.rconPassword.equals(hashed);
|
|
+ } catch (Exception e) {
|
|
+ LOGGER.error("Failed to validate rcon password", e);
|
|
+ return false;
|
|
+ }
|
|
}
|
|
+ // Plazma end - hashed rcon password
|
|
|
|
// CraftBukkit start
|
|
public static DedicatedServerProperties fromFile(Path path, OptionSet optionset) {
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/Settings.java b/src/main/java/net/minecraft/server/dedicated/Settings.java
|
|
index d7bd235ef2815890e038091dd625177049d253a5..afced52731868d5726b85a03011111adeffeb074 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/Settings.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/Settings.java
|
|
@@ -243,6 +243,11 @@ public abstract class Settings<T extends Settings<T>> {
|
|
return v1;
|
|
}
|
|
|
|
+ // Plazma start - Settings helper
|
|
+ protected <V> void set(String key, V value) { this.properties.put(key, value); }
|
|
+ protected void remove(String key) { this.properties.remove(key); }
|
|
+ // Plazma end - Settings helper
|
|
+
|
|
protected <V> Settings<T>.MutableValue<V> getMutable(String key, Function<String, V> parser, Function<V, String> stringifier, V fallback) {
|
|
String s1 = this.getStringRaw(key);
|
|
V v1 = MoreObjects.firstNonNull(s1 != null ? parser.apply(s1) : null, fallback);
|
|
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconClient.java b/src/main/java/net/minecraft/server/rcon/thread/RconClient.java
|
|
index 1c3775c6d29a85803c87948c64ec81cbeb87aef4..4f6f46398ac0814a95d8253cc5f575b8f09f7209 100644
|
|
--- a/src/main/java/net/minecraft/server/rcon/thread/RconClient.java
|
|
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconClient.java
|
|
@@ -26,13 +26,12 @@ public class RconClient extends GenericThread {
|
|
private boolean authed;
|
|
private final Socket client;
|
|
private final byte[] buf = new byte[1460];
|
|
- private final String rconPassword;
|
|
// CraftBukkit start
|
|
private final DedicatedServer serverInterface;
|
|
private final RconConsoleSource rconConsoleSource;
|
|
// CraftBukkit end
|
|
|
|
- RconClient(ServerInterface server, String password, Socket socket) {
|
|
+ RconClient(ServerInterface server, Socket socket) {// Plazma - hashed rcon password
|
|
super("RCON Client " + String.valueOf(socket.getInetAddress()));
|
|
this.serverInterface = (DedicatedServer) server; // CraftBukkit
|
|
this.client = socket;
|
|
@@ -43,7 +42,6 @@ public class RconClient extends GenericThread {
|
|
this.running = false;
|
|
}
|
|
|
|
- this.rconPassword = password;
|
|
this.rconConsoleSource = new net.minecraft.server.rcon.RconConsoleSource(this.serverInterface, socket.getRemoteSocketAddress()); // CraftBukkit
|
|
}
|
|
|
|
@@ -93,7 +91,7 @@ public class RconClient extends GenericThread {
|
|
String s1 = PktUtils.stringFromByteArray(this.buf, j, i);
|
|
int j1 = j + s1.length();
|
|
|
|
- if (!s1.isEmpty() && s1.equals(this.rconPassword)) {
|
|
+ if (!s1.isEmpty() && serverInterface.getProperties().matchRconPassword(s1)) {
|
|
this.authed = true;
|
|
this.send(l, 2, "");
|
|
continue;
|
|
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
|
index c12d7db2b048a327c0e8f398848cd3a9bce0ebce..150cecc44a7f49740fa400e02de09671ff8b392a 100644
|
|
--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
|
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
|
|
@@ -16,15 +16,13 @@ import org.slf4j.Logger;
|
|
public class RconThread extends GenericThread {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private final ServerSocket socket;
|
|
- private final String rconPassword;
|
|
private final List<RconClient> clients = Lists.newArrayList();
|
|
private final ServerInterface serverInterface;
|
|
|
|
- private RconThread(ServerInterface server, ServerSocket listener, String password) {
|
|
+ private RconThread(ServerInterface server, ServerSocket listener) {// Plazma - hashed rcon password
|
|
super("RCON Listener");
|
|
this.serverInterface = server;
|
|
this.socket = listener;
|
|
- this.rconPassword = password;
|
|
}
|
|
|
|
private void clearClients() {
|
|
@@ -37,7 +35,7 @@ public class RconThread extends GenericThread {
|
|
while (this.running) {
|
|
try {
|
|
Socket socket = this.socket.accept();
|
|
- RconClient rconClient = new RconClient(this.serverInterface, this.rconPassword, socket);
|
|
+ RconClient rconClient = new RconClient(this.serverInterface, socket); // Plazma - hashed rcon password
|
|
rconClient.start();
|
|
this.clients.add(rconClient);
|
|
this.clearClients();
|
|
@@ -64,15 +62,14 @@ public class RconThread extends GenericThread {
|
|
|
|
int i = dedicatedServerProperties.rconPort;
|
|
if (0 < i && 65535 >= i) {
|
|
- String string2 = dedicatedServerProperties.rconPassword;
|
|
- if (string2.isEmpty()) {
|
|
+ if (!dedicatedServerProperties.shouldStartRCON()) { // Plazma - hashed rcon password
|
|
LOGGER.warn("No rcon password set in server.properties, rcon disabled!");
|
|
return null;
|
|
} else {
|
|
try {
|
|
ServerSocket serverSocket = new ServerSocket(i, 0, InetAddress.getByName(string));
|
|
serverSocket.setSoTimeout(500);
|
|
- RconThread rconThread = new RconThread(server, serverSocket, string2);
|
|
+ RconThread rconThread = new RconThread(server, serverSocket); // Plazma - hashed rcon password
|
|
if (!rconThread.start()) {
|
|
return null;
|
|
} else {
|