diff --git a/README.md b/README.md index 9b9e57b..1fd504a 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ lxs help # Show help | `lxs tool system` | System monitoring and diagnostics | | `lxs tool benchmark` | Server benchmark (CPU / RAM / disk / network) | | `lxs tool harden` | Baseline hardening: UFW + fail2ban + SSH key-only + unattended-upgrades | +| `lxs tool root-password` | Change the root password (interactive or generated) | +| `lxs tool update` | Update the server (apt update + upgrade + autoremove + autoclean) | ## Project structure @@ -70,7 +72,9 @@ lxs/ ├── index.sh # Interactive menu listing the tools below ├── system-infos.sh ├── server-benchmark.sh - └── harden.sh + ├── harden.sh + ├── root-password.sh + └── update-server.sh ``` After `lxs setup`, the full tree lives in `/usr/local/share/lxs/` and sub-scripts execute from disk. If `lxs.sh` is run without being installed (the one-liner mode), it falls back to downloading sub-scripts on demand. diff --git a/lxs.sh b/lxs.sh index 5e3e749..457ddec 100755 --- a/lxs.sh +++ b/lxs.sh @@ -287,6 +287,8 @@ cmd_tool() { system) download_and_run "tools/system-infos.sh" "$@" ;; benchmark) download_and_run "tools/server-benchmark.sh" "$@" ;; harden) download_and_run "tools/harden.sh" "$@" ;; + root-password) download_and_run "tools/root-password.sh" "$@" ;; + update) download_and_run "tools/update-server.sh" "$@" ;; "") echo -e "${RED}[✗] Missing tool name. Try: lxs help${NC}"; return 1 ;; *) echo -e "${RED}[✗] Unknown tool: $tool. Try: lxs help${NC}"; return 1 ;; esac diff --git a/tools/index.sh b/tools/index.sh index 41cb4f2..0d20299 100755 --- a/tools/index.sh +++ b/tools/index.sh @@ -60,17 +60,21 @@ menu_tools() { echo -e " ${CYAN}[1]${NC} System Infos" echo -e " ${PURPLE}[2]${NC} Server Benchmark" echo -e " ${YELLOW}[3]${NC} Harden Server" + echo -e " ${GREEN}[4]${NC} Change Root Password" + echo -e " ${CYAN}[5]${NC} Update Server" echo -e " ${RED}[0]${NC} Back" echo "" - echo -e -n "${BOLD}Choice [0-3]: ${NC}" + echo -e -n "${BOLD}Choice [0-5]: ${NC}" read -r choice case $choice in 1) run_sibling "tools/system-infos.sh" ;; 2) run_sibling "tools/server-benchmark.sh" ;; 3) run_sibling "tools/harden.sh" ;; + 4) run_sibling "tools/root-password.sh" ;; + 5) run_sibling "tools/update-server.sh" ;; 0) return ;; - *) echo -e "${RED}[✗] Invalid option. Please select 0-3.${NC}"; sleep 1; continue ;; + *) echo -e "${RED}[✗] Invalid option. Please select 0-5.${NC}"; sleep 1; continue ;; esac if [ "$choice" != "0" ]; then diff --git a/tools/root-password.sh b/tools/root-password.sh new file mode 100755 index 0000000..365530d --- /dev/null +++ b/tools/root-password.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +# LXS - Change root password +# Description: Change the root account password (interactive or generated) +# Author: LXS +# Date: 2025 + +# Load LXS common library (colors, separator, run_spinner, loggers, helpers) +LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}" +_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; } +eval "$_lib" +unset _lib +export LXS_LOG_FILE="/tmp/lxs_root_password.log" + +require_root "$0" "$@" + +set -u + +# ═══════════════════════════════════════════════════════════════════════════ +# Arguments +# ═══════════════════════════════════════════════════════════════════════════ + +MODE="" +PASSWORD_LENGTH=24 + +for arg in "$@"; do + case "$arg" in + -g|--generate) MODE="generate" ;; + -i|--interactive) MODE="interactive" ;; + --length=*) PASSWORD_LENGTH="${arg#*=}" ;; + -h|--help) + cat <&2 + exit 1 + ;; + esac +done + +# ═══════════════════════════════════════════════════════════════════════════ +# Actions +# ═══════════════════════════════════════════════════════════════════════════ + +change_interactive() { + info "Setting root password interactively..." + show_separator + if passwd root; then + show_separator + ok "Root password updated" + return 0 + fi + show_separator + err "Failed to update root password" + return 1 +} + +change_generated() { + if ! [[ "$PASSWORD_LENGTH" =~ ^[0-9]+$ ]] || [ "$PASSWORD_LENGTH" -lt 12 ]; then + err "--length must be a number ≥ 12 (got: ${PASSWORD_LENGTH})" + return 1 + fi + + local new_password + new_password=$(generate_password "$PASSWORD_LENGTH") + if [ -z "$new_password" ]; then + err "Failed to generate a password" + return 1 + fi + + if ! echo "root:${new_password}" | chpasswd; then + err "Failed to apply the generated password" + return 1 + fi + + show_separator + ok "Root password updated" + echo "" + echo -e "${WHITE}${BOLD}New root password:${NC} ${YELLOW}${new_password}${NC}" + echo "" + warn "Store this password in a secure place. It will not be shown again." + show_separator + return 0 +} + +# ═══════════════════════════════════════════════════════════════════════════ +# Menu (when no mode is given on the CLI) +# ═══════════════════════════════════════════════════════════════════════════ + +if [ -z "$MODE" ]; then + echo -e "${WHITE}${BOLD}LXS - Change root password${NC}" + show_separator + echo -e " ${CYAN}[1]${NC} Set a new password interactively" + echo -e " ${CYAN}[2]${NC} Generate a strong random password" + echo -e " ${RED}[0]${NC} Cancel" + echo "" + echo -e -n "${BOLD}Choice [0-2]: ${NC}" + read -r choice + case "$choice" in + 1) MODE="interactive" ;; + 2) MODE="generate" ;; + 0|"") info "Cancelled."; exit 0 ;; + *) err "Invalid option."; exit 1 ;; + esac +fi + +case "$MODE" in + interactive) change_interactive ;; + generate) change_generated ;; +esac diff --git a/tools/update-server.sh b/tools/update-server.sh new file mode 100755 index 0000000..13522ff --- /dev/null +++ b/tools/update-server.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +# LXS - Update server +# Description: Refresh package lists and upgrade installed packages +# Author: LXS +# Date: 2025 + +# Load LXS common library (colors, separator, run_spinner, loggers, helpers) +LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}" +_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; } +eval "$_lib" +unset _lib +export LXS_LOG_FILE="/tmp/lxs_update_server.log" + +require_root "$0" "$@" + +set -u + +# ═══════════════════════════════════════════════════════════════════════════ +# Arguments +# ═══════════════════════════════════════════════════════════════════════════ + +DO_FULL_UPGRADE=0 +DO_AUTOREMOVE=1 +DO_AUTOCLEAN=1 +ASSUME_YES=0 + +for arg in "$@"; do + case "$arg" in + --full|--dist-upgrade) DO_FULL_UPGRADE=1 ;; + --no-autoremove) DO_AUTOREMOVE=0 ;; + --no-autoclean) DO_AUTOCLEAN=0 ;; + -y|--yes) ASSUME_YES=1 ;; + -h|--help) + cat <&2 + exit 1 + ;; + esac +done + +# ═══════════════════════════════════════════════════════════════════════════ +# Pre-checks +# ═══════════════════════════════════════════════════════════════════════════ + +require_debian_ubuntu || exit 1 + +if ! command -v apt-get >/dev/null 2>&1; then + err "apt-get is not available on this system" + exit 1 +fi + +UPGRADE_CMD="upgrade" +UPGRADE_LABEL="Upgrade installed packages" +if [ $DO_FULL_UPGRADE -eq 1 ]; then + UPGRADE_CMD="full-upgrade" + UPGRADE_LABEL="Full-upgrade (may add/remove packages)" +fi + +echo -e "${WHITE}${BOLD}LXS Server Update${NC}" +show_separator +echo "The following actions will be performed:" +echo " • Refresh package lists (apt-get update)" +echo " • ${UPGRADE_LABEL}" +[ $DO_AUTOREMOVE -eq 1 ] && echo " • Remove unused packages (apt-get autoremove)" +[ $DO_AUTOCLEAN -eq 1 ] && echo " • Clean old package archives (apt-get autoclean)" +show_separator + +if [ $ASSUME_YES -ne 1 ]; then + echo -e -n "${BOLD}Proceed? [y/N]: ${NC}" + read -r reply + case "$reply" in + [yY]|[yY][eE][sS]) ;; + *) info "Cancelled."; exit 0 ;; + esac +fi + +# ═══════════════════════════════════════════════════════════════════════════ +# Run +# ═══════════════════════════════════════════════════════════════════════════ + +apt_noninteractive +wait_for_apt || exit 1 + +APT_OPTS='-y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"' + +run_spinner "Refreshing package lists..." "apt-get update" || { + err "apt-get update failed — see ${LXS_LOG_FILE}" + exit 1 +} + +run_spinner "${UPGRADE_LABEL}..." "apt-get ${APT_OPTS} ${UPGRADE_CMD}" || { + err "apt-get ${UPGRADE_CMD} failed — see ${LXS_LOG_FILE}" + exit 1 +} + +if [ $DO_AUTOREMOVE -eq 1 ]; then + run_spinner "Removing unused packages..." "apt-get ${APT_OPTS} autoremove --purge" \ + || warn "autoremove failed — see ${LXS_LOG_FILE}" +fi + +if [ $DO_AUTOCLEAN -eq 1 ]; then + run_spinner "Cleaning old archives..." "apt-get ${APT_OPTS} autoclean" \ + || warn "autoclean failed — see ${LXS_LOG_FILE}" +fi + +show_separator +ok "Server updated" + +# ═══════════════════════════════════════════════════════════════════════════ +# Reboot hint +# ═══════════════════════════════════════════════════════════════════════════ + +if [ -f /var/run/reboot-required ]; then + echo "" + warn "A reboot is required to complete the update." + if [ -f /var/run/reboot-required.pkgs ]; then + echo -e "${GRAY}Packages requiring reboot:${NC}" + sed 's/^/ • /' /var/run/reboot-required.pkgs + fi +fi