#!/bin/bash useGeneratedLogs=${GENERATE_LOG4J2_CONFIG:-${ENABLE_ROLLING_LOGS:-false}} useFallbackJvmFlag=false patchLog4jConfig() { file=${1?} url=${2?} if ! get -o "${SERVER_DIR}/${file}" "$url"; then logError "Failed to download corrected log4j config, fallback to JVM flag" useFallbackJvmFlag=true return 1 fi JVM_OPTS="-Dlog4j.configurationFile=${file} ${JVM_OPTS}" useGeneratedLogs=false } # Temporarily disable debugging output oldState=$(shopt -po xtrace || true) shopt -u -o xtrace # Patch Log4j remote code execution vulnerability # See https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition if isFamily NATIVE; then : # Native server, so there is no log4j to patch elif versionLessThan 1.7; then : # No patch required here. elif isFamily VANILLA && versionLessThan 1.12; then patchLog4jConfig log4j2_17-111.xml https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml elif isFamily VANILLA && versionLessThan 1.17; then patchLog4jConfig log4j2_112-116.xml https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml # See https://purpurmc.org/docs/Log4j/ elif isType PURPUR && versionLessThan 1.17; then patchLog4jConfig purpur_log4j2_1141-1165.xml https://purpurmc.org/docs/xml/purpur_log4j2_1141-1165.xml elif isType PURPUR && versionLessThan 1.18.1; then patchLog4jConfig purpur_log4j2_117.xml https://purpurmc.org/docs/xml/purpur_log4j2_117.xml elif versionLessThan 1.18.1; then useFallbackJvmFlag=true fi eval "$oldState" if ${useFallbackJvmFlag}; then JVM_OPTS="-Dlog4j2.formatMsgNoLookups=true ${JVM_OPTS}" fi if isFamily NATIVE; then : # Native server, so no Log4jPatcher agent elif versionLessThan 1.7; then : # No patch required here. elif versionLessThan 1.18.1; then if isTrue "${SKIP_LOG4J_PATCHER:-false}"; then log "Skipping Log4jPatcher, make sure you are not affected" else JVM_OPTS="-javaagent:/image/Log4jPatcher.jar ${JVM_OPTS}" fi fi # Set up log4j2 configuration with templating support LOGFILE="${SERVER_DIR}/log4j2.xml" if isFamily NATIVE; then : # Native server, so no log4j configuration elif ${useGeneratedLogs}; then # Set up log configuration defaults : "${LOG_LEVEL:=info}" : "${ROLLING_LOG_MAX_FILES:=1000}" # Note: Can't use ${VAR:=default} syntax for values containing } as it breaks parsing if [ -z "${ROLLING_LOG_FILE_PATTERN}" ]; then ROLLING_LOG_FILE_PATTERN='logs/%d{yyyy-MM-dd}-%i.log.gz' fi # Pattern format defaults (compatible with vanilla Minecraft) # Note: Can't use ${VAR:=default} syntax because } in the value breaks parsing if [ -z "${LOG_CONSOLE_FORMAT}" ]; then LOG_CONSOLE_FORMAT='[%d{HH:mm:ss}] [%t/%level]: %msg%n' fi if [ -z "${LOG_TERMINAL_FORMAT}" ]; then LOG_TERMINAL_FORMAT='[%d{HH:mm:ss} %level]: %msg%n' fi if [ -z "${LOG_FILE_FORMAT}" ]; then LOG_FILE_FORMAT='[%d{HH:mm:ss}] [%t/%level]: %msg%n' fi export LOG_LEVEL ROLLING_LOG_FILE_PATTERN ROLLING_LOG_MAX_FILES export LOG_CONSOLE_FORMAT LOG_TERMINAL_FORMAT LOG_FILE_FORMAT # Always regenerate if file doesn't exist if [ ! -e "$LOGFILE" ] || isTrue "${REGENERATE_LOG4J2:-true}"; then log "Generating log4j2.xml from template in ${LOGFILE}" # Generate log4j2.xml using heredoc for reliable variable substitution cat > "$LOGFILE" < EOF else log "log4j2.xml already exists and is up to date, skipping generation" fi # Apply the log4j2 configuration JVM_OPTS="-Dlog4j.configurationFile=log4j2.xml ${JVM_OPTS}" else rm -f "${LOGFILE}" fi