#!/usr/bin/env sh # Pi-hole: A black hole for Internet advertisements # (c) 2017 Pi-hole, LLC (https://pi-hole.net) # Network-wide ad blocking via your own hardware. # # Script to hold utility functions for use in other scripts # # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. # Basic Housekeeping rules # - Functions must be self contained # - Functions should be grouped with other similar functions # - Functions must be documented # - New functions must have a test added for them in test/test_any_utils.py ####################### # Takes Three arguments: file, key, and value. # # Checks the target file for the existence of the key # - If it exists, it changes the value # - If it does not exist, it adds the value # # Example usage: # addOrEditKeyValPair "/etc/pihole/setupVars.conf" "BLOCKING_ENABLED" "true" ####################### addOrEditKeyValPair() { local file="${1}" local key="${2}" local value="${3}" if grep -q "^${key}=" "${file}"; then # Key already exists in file, modify the value sed -i "/^${key}=/c\\${key}=${value}" "${file}" else # Key does not already exist, add it and it's value echo "${key}=${value}" >> "${file}" fi } ####################### # Safely loads key=value pairs from the Pi-hole versions cache file. # Unlike `source`, this function never executes file content as shell code. # Only known keys are assigned, and values are validated against a strict # character allowlist to prevent shell injection. # # Takes one argument: path to the versions file # Returns 0 in all cases (compatible with set -e) # Example loadVersionFile "/etc/pihole/versions" ####################### loadVersionFile() { local file="${1}" local line key value [ -f "${file}" ] || return 0 while IFS= read -r line || [ -n "${line}" ]; do # Skip blank lines and comments case "${line}" in ''|\#*) continue ;; esac # Require KEY=VALUE format (key must be non-empty) key="${line%%=*}" value="${line#*=}" [ -z "${key}" ] && continue [ "${key}" = "${line}" ] && continue # no '=' found # Allowlist: only assign known version-file keys case "${key}" in CORE_VERSION|CORE_BRANCH|CORE_HASH|\ GITHUB_CORE_VERSION|GITHUB_CORE_HASH|\ WEB_VERSION|WEB_BRANCH|WEB_HASH|\ GITHUB_WEB_VERSION|GITHUB_WEB_HASH|\ FTL_VERSION|FTL_BRANCH|FTL_HASH|\ GITHUB_FTL_VERSION|GITHUB_FTL_HASH|\ DOCKER_VERSION|GITHUB_DOCKER_VERSION) ;; *) continue ;; esac # Validate value: allow only characters safe in version strings and branch names. # Permits: letters, digits, dot, hyphen, underscore, slash, plus sign, and empty string. case "${value}" in *[!a-zA-Z0-9._/+\-]*) continue ;; esac # Safe to assign: key is from the allowlist, value contains no shell metacharacters eval "${key}=\${value}" done < "${file}" } ####################### # returns FTL's PID based on the content of the pihole-FTL.pid file ####################### getFTLPID() { local FTL_PID_FILE="/run/pihole-FTL.pid" # hardcoded — see GHSA-6w8x-p785-6pm4 local FTL_PID if [ -s "${FTL_PID_FILE}" ]; then # -s: FILE exists and has a size greater than zero FTL_PID="$(cat "${FTL_PID_FILE}")" # Exploit prevention: unset the variable if there is malicious content # Verify that the value read from the file is numeric expr "${FTL_PID}" : "[^[:digit:]]" > /dev/null && unset FTL_PID fi # If FTL is not running, or the PID file contains malicious stuff, substitute # negative PID to signal this FTL_PID=${FTL_PID:=-1} echo "${FTL_PID}" } ####################### # returns value from FTLs config file using pihole-FTL --config # # Takes one argument: key # Example getFTLConfigValue dns.piholePTR ####################### getFTLConfigValue(){ # Pipe to cat to avoid pihole-FTL assuming this is an interactive command # returning colored output. pihole-FTL --config -q "${1}" | cat } ####################### # sets value in FTLs config file using pihole-FTL --config # # Takes two arguments: key and value # Example setFTLConfigValue dns.piholePTR PI.HOLE # # Note, for complex values such as dns.upstreams, you should wrap the value in single quotes: # setFTLConfigValue dns.upstreams '[ "8.8.8.8" , "8.8.4.4" ]' ####################### setFTLConfigValue(){ local err { pihole-FTL --config "${1}" "${2}" >/dev/null; err="$?"; } || true case $err in 0) ;; 5) # FTL returns 5 if the value was set by an environment variable and is therefore read-only printf " %s %s set by environment variable. Please unset it to use this function\n" "${CROSS}" "${1}"; exit 5;; *) printf " %s Failed to set %s. Try with sudo power\n" "${CROSS}" "${1}" exit 1 esac }