diff --git a/scripts/share/lxc-mount-manager.sh b/scripts/share/lxc-mount-manager.sh index 01e310b..f31245f 100644 --- a/scripts/share/lxc-mount-manager.sh +++ b/scripts/share/lxc-mount-manager.sh @@ -1,18 +1,17 @@ #!/bin/bash # ========================================================== -# ProxMenux - LXC Mount Manager (Standalone - CLEAN v1) +# ProxMenux - LXC Mount Manager # ========================================================== # Author : MacRimi # Copyright : (c) 2024 MacRimi # License : MIT -# Version : 3.0-clean +# Version : 3.1-enhanced # Last Updated: $(date +%d/%m/%Y) # ========================================================== BASE_DIR="/usr/local/share/proxmenux" source "$BASE_DIR/utils.sh" - SHARE_COMMON_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main/scripts/global/share-common.func" if ! source <(curl -s "$SHARE_COMMON_URL" 2>/dev/null); then SHARE_COMMON_LOADED=false @@ -25,7 +24,6 @@ initialize_cache # ========================================================== - get_container_uid_shift() { local ctid="$1" local conf="/etc/pve/lxc/${ctid}.conf" @@ -36,12 +34,10 @@ get_container_uid_shift() { return 0 fi - local unpriv unpriv=$(grep "^unprivileged:" "$conf" | awk '{print $2}') if [[ "$unpriv" == "1" ]]; then - uid_shift=$(grep "^lxc.idmap" "$conf" | grep 'u 0' | awk '{print $5}' | head -1) echo "${uid_shift:-100000}" return 0 @@ -51,7 +47,6 @@ get_container_uid_shift() { return 0 } - setup_container_access() { local ctid="$1" group_name="$2" host_gid="$3" host_dir="$4" local uid_shift mapped_gid @@ -63,51 +58,181 @@ setup_container_access() { uid_shift=$(get_container_uid_shift "$ctid") + + + + # =================================================================== + # CONTAINER TYPE DETECTION AND STRATEGY + # =================================================================== + if [[ "$uid_shift" -eq 0 ]]; then + msg_ok "$(translate "PRIVILEGED container detected - using direct UID/GID mapping")" mapped_gid="$host_gid" - msg_ok "$(translate "Privileged container - using same GID as host:") $host_gid" + container_type="privileged" else + msg_ok "$(translate "UNPRIVILEGED container detected - using mapped UID/GID")" mapped_gid=$((uid_shift + host_gid)) - msg_ok "$(translate "Unprivileged container - using mapped GID:") $mapped_gid (host GID: $host_gid, shift: $uid_shift)" + container_type="unprivileged" + msg_ok "UID shift: $uid_shift, Host GID: $host_gid → Container GID: $mapped_gid" + fi - pct exec "$ctid" -- sh -c " - if ! getent group $group_name >/dev/null 2>&1; then - groupadd -g $mapped_gid $group_name 2>/dev/null || true + + + + # =================================================================== + # STEP 1: ACL TOOLS (only for unprivileged containers) + # =================================================================== + + if [[ "$container_type" == "unprivileged" ]]; then + if ! command -v setfacl >/dev/null 2>&1; then + msg_info "$(translate "Installing ACL tools (REQUIRED for unprivileged containers)...")" + apt-get update >/dev/null 2>&1 + apt-get install -y acl >/dev/null 2>&1 + if command -v setfacl >/dev/null 2>&1; then + msg_ok "$(translate "ACL tools installed successfully")" + else + msg_error "$(translate "Failed to install ACL tools - permissions may not work correctly")" + fi else - ct_gid=\$(getent group $group_name | cut -d: -f3) - if [ \"\$ct_gid\" != \"$mapped_gid\" ]; then + msg_ok "$(translate "ACL tools already available")" + fi + else + msg_ok "$(translate "Privileged container - ACL tools not required (using POSIX permissions)")" + fi + + + + + + # =================================================================== + # STEP 2: CONTAINER GROUP CONFIGURATION + # =================================================================== + + msg_info "$(translate "Configuring container group with") $container_type $(translate "strategy...")" + + pct exec "$ctid" -- sh -c " + # Remove existing group if GID is wrong + if getent group $group_name >/dev/null 2>&1; then + current_gid=\$(getent group $group_name | cut -d: -f3) + if [ \"\$current_gid\" != \"$mapped_gid\" ]; then groupdel $group_name 2>/dev/null || true - groupadd -g $mapped_gid $group_name 2>/dev/null || true fi fi - - - getent passwd | while IFS=: read -r username _ uid gid _ home _; do - if [ \"\$uid\" -eq 0 ] || [ \"\$uid\" -ge 1000 ] || [ \"\$username\" = \"nobody\" ] || [ \"\$username\" = \"www-data\" ]; then - usermod -aG $group_name \"\$username\" 2>/dev/null || true - fi - done + + # Create group with correct GID + groupadd -g $mapped_gid $group_name 2>/dev/null || true " 2>/dev/null + msg_ok "$(translate "Container group configured:") $group_name (GID: $mapped_gid)" - if command -v setfacl >/dev/null 2>&1; then - pct exec "$ctid" -- getent passwd | awk -F: '{print $1, $3}' | while read user uid; do - [[ "$uid" -eq 0 ]] && continue - host_uid=$((uid_shift + uid)) - setfacl -m u:$host_uid:rwx "$host_dir" 2>/dev/null || true - done - msg_ok "$(translate "ACL permissions applied for container users")" + + + + + # =================================================================== + # STEP 3: USER PROCESSING (different strategies) + # =================================================================== + + local container_users + container_users=$(pct exec "$ctid" -- getent passwd | awk -F: '{print $1 ":" $3}' 2>/dev/null) + + local users_added=0 + local acls_applied=0 + + if [[ "$container_type" == "privileged" ]]; then + + + msg_ok "$(translate "Privileged container:") $users_added $(translate "users added to group (no ACLs needed)")" + + else + + msg_info "$(translate "Using UNPRIVILEGED strategy: mapped UIDs + ACL permissions")" + + while IFS=: read -r username ct_uid; do + if [[ -n "$username" && "$ct_uid" =~ ^[0-9]+$ ]]; then + local host_uid=$((uid_shift + ct_uid)) + + if pct exec "$ctid" -- usermod -aG "$group_name" "$username" 2>/dev/null; then + users_added=$((users_added + 1)) + + if command -v setfacl >/dev/null 2>&1; then + setfacl -m u:$host_uid:rwx "$host_dir" 2>/dev/null + setfacl -m d:u:$host_uid:rwx "$host_dir" 2>/dev/null + acls_applied=$((acls_applied + 1)) + fi + + case "$username" in + root|www-data|ncp|nobody|ubuntu|debian) + msg_ok "$(translate "Configured user:") $username (CT_UID:$ct_uid → HOST_UID:$host_uid)" + ;; + esac + fi + fi + done <<< "$container_users" + + msg_ok "$(translate "Unprivileged container:") $users_added $(translate "users added,") $acls_applied $(translate "ACL entries applied")" fi + + + # =================================================================== + # STEP 4: DIRECTORY PERMISSIONS + # =================================================================== + msg_info "$(translate "Setting optimal directory permissions...")" + chmod 2775 "$host_dir" 2>/dev/null || true chgrp "$group_name" "$host_dir" 2>/dev/null || true + + msg_ok "$(translate "Host directory permissions:") 2775 root:$group_name" - msg_ok "$(translate "Group mapping ensured:") host=$host_gid → ct=$mapped_gid" - msg_ok "$(translate "Multi-approach access configuration completed")" + + + + # =================================================================== + # STEP 5: VERIFICATION + # =================================================================== + msg_info "$(translate "Verifying configuration...")" + + if [[ "$container_type" == "unprivileged" ]] && command -v getfacl >/dev/null 2>&1; then + local acl_count=$(getfacl "$host_dir" 2>/dev/null | grep "^user:" | grep -v "^user::" | wc -l) + msg_ok "$(translate "ACL entries configured:") $acl_count" + + # Show sample ACL entries + if [[ $acl_count -gt 0 ]]; then + echo -e "${TAB}${BGN}$(translate "ACL entries:")${CL}" + getfacl "$host_dir" 2>/dev/null | grep "^user:" | grep -v "^user::" | head -3 | while read acl_line; do + echo -e "${TAB} ${BL}$acl_line${CL}" + done + fi + fi + + + local test_users=("www-data" "root" "ncp" "nobody") + local successful_tests=0 + + for test_user in "${test_users[@]}"; do + if pct exec "$ctid" -- id "$test_user" >/dev/null 2>&1; then + if pct exec "$ctid" -- su -s /bin/bash "$test_user" -c "ls '$4' >/dev/null 2>&1" 2>/dev/null; then + successful_tests=$((successful_tests + 1)) + fi + fi + done + + if [[ $successful_tests -gt 0 ]]; then + msg_ok "$(translate "Access verification:") $successful_tests $(translate "users can access mount point")" + fi + + + if [[ "$container_type" == "privileged" ]]; then + msg_ok "$(translate "PRIVILEGED container configuration completed - using direct POSIX permissions")" + else + msg_ok "$(translate "UNPRIVILEGED container configuration completed - using ACL permissions")" + fi + return 0 } @@ -133,6 +258,10 @@ get_next_mp_index() { } + + + + add_bind_mount() { local ctid="$1" host_path="$2" ct_path="$3" local mpidx result @@ -147,7 +276,6 @@ add_bind_mount() { return 1 fi - if pct config "$ctid" | grep -q "$host_path"; then echo -e msg_warn "$(translate "Directory already mounted in container configuration.")" @@ -177,61 +305,6 @@ add_bind_mount() { -select_container_mount_point() { - local ctid="$1" - local host_dir="$2" - local choice mount_point existing_dirs options - - while true; do - choice=$(whiptail --title "$(translate "Configure Mount Point inside LXC")" \ - --menu "$(translate "Where to mount inside container?")" 18 70 5 \ - "1" "$(translate "Create new directory in /mnt")" \ - "2" "$(translate "Use existing directory in /mnt")" \ - "3" "$(translate "Enter path manually")" \ - "4" "$(translate "Cancel")" 3>&1 1>&2 2>&3) || return 1 - - case "$choice" in - 1) - mount_point=$(whiptail --inputbox "$(translate "Enter folder name for /mnt:")" 10 60 "shared" 3>&1 1>&2 2>&3) || continue - [[ -z "$mount_point" ]] && continue - mount_point="/mnt/$mount_point" - pct exec "$ctid" -- mkdir -p "$mount_point" 2>/dev/null - ;; - - 2) - existing_dirs=$(pct exec "$ctid" -- ls -1 /mnt 2>/dev/null | awk '{print "/mnt/"$1" "$1}') - if [[ -z "$existing_dirs" ]]; then - whiptail --msgbox "$(translate "No existing directories found in /mnt")" 8 60 - continue - fi - mount_point=$(whiptail --title "$(translate "Select Existing Folder")" \ - --menu "$(translate "Choose a folder from /mnt:")" 20 70 10 \ - $existing_dirs 3>&1 1>&2 2>&3) || continue - ;; - - 3) - mount_point=$(whiptail --inputbox "$(translate "Enter full path:")" 10 70 "/mnt/shared" 3>&1 1>&2 2>&3) || continue - [[ -z "$mount_point" ]] && continue - pct exec "$ctid" -- mkdir -p "$mount_point" 2>/dev/null - ;; - - 4) - return 1 - ;; - esac - - if pct exec "$ctid" -- test -d "$mount_point" 2>/dev/null; then - echo "$mount_point" - return 0 - else - whiptail --msgbox "$(translate "Could not create or access directory:") $mount_point" 8 70 - continue - fi - done -} - - - mount_host_directory_to_lxc() { # Step 1: Select container @@ -256,9 +329,7 @@ mount_host_directory_to_lxc() { return 1 fi fi - msg_ok "$(translate 'Select LXC container')" - - + msg_ok "$(translate 'Container selected and running')" # Step 2: Select host directory local host_dir @@ -266,7 +337,7 @@ mount_host_directory_to_lxc() { if [[ -z "$host_dir" ]]; then return 1 fi - msg_ok "$(translate 'Select Host directory')" + msg_ok "$(translate 'Host directory selected')" # Step 3: Setup group local group_name="sharedfiles" @@ -280,7 +351,7 @@ mount_host_directory_to_lxc() { chown -R root:"$group_name" "$host_dir" 2>/dev/null || true chmod -R 2775 "$host_dir" 2>/dev/null || true - msg_ok "$(translate 'Select container mount point')" + msg_ok "$(translate 'Host group configured')" # Step 4: Select container mount point local ct_mount_point @@ -316,19 +387,9 @@ $(translate "Proceed?")" return 1 fi - - - - - # Step 7: Setup access ====================================================== - + # Step 7: Setup access (handles both privileged and unprivileged) setup_container_access "$container_id" "$group_name" "$group_gid" "$host_dir" - # =========================================================================== - - - - # Step 8: Final setup pct exec "$container_id" -- chgrp "$group_name" "$ct_mount_point" 2>/dev/null || true pct exec "$container_id" -- chmod 2775 "$ct_mount_point" 2>/dev/null || true @@ -341,6 +402,11 @@ $(translate "Proceed?")" echo -e "${TAB}${BGN}$(translate 'Mount Point:')${CL} ${BL}$ct_mount_point${CL}" echo -e "${TAB}${BGN}$(translate 'Group:')${CL} ${BL}$group_name (GID: $group_gid)${CL}" + if [[ "$uid_shift" -eq 0 ]]; then + echo -e "${TAB}${BGN}$(translate 'Permission Strategy:')${CL} ${BL}POSIX (direct mapping)${CL}" + else + echo -e "${TAB}${BGN}$(translate 'Permission Strategy:')${CL} ${BL}ACL (mapped UIDs)${CL}" + fi echo -e "" if whiptail --yesno "$(translate "Restart container to activate mount?")" 8 60; then @@ -370,9 +436,7 @@ $(translate "Proceed?")" read -r } -# ========================================================== - - +# Main menu main_menu() { while true; do choice=$(dialog --title "$(translate 'LXC Mount Manager')" \ @@ -401,6 +465,4 @@ main_menu() { done } - - main_menu