2025-08-22 18:05:14 +02:00
#!/bin/bash
# ==========================================================
# ProxMenu CT - Samba Client Manager for Proxmox LXC
# ==========================================================
# Based on ProxMenux by MacRimi
# ==========================================================
# Description:
# This script allows you to manage Samba/CIFS client mounts inside Proxmox CTs:
# - Mount Samba/CIFS shares (temporary and permanent)
# - View current mounts
# - Unmount and remove Samba shares
# - Auto-discover Samba servers
# - Manage credentials securely
# ==========================================================
# Configuration
REPO_URL = "https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR = "/usr/local/share/proxmenux"
UTILS_FILE = " $BASE_DIR /utils.sh "
VENV_PATH = "/opt/googletrans-env"
CREDENTIALS_DIR = "/etc/samba/credentials"
if [ [ -f " $UTILS_FILE " ] ] ; then
source " $UTILS_FILE "
fi
load_language
initialize_cache
# === Select CT ===
CT_LIST = $( pct list | awk 'NR>1 {print $1, $3}' )
if [ -z " $CT_LIST " ] ; then
dialog --title " $( translate "Error" ) " --msgbox " $( translate "No CTs available in the system." ) " 8 50
exit 1
fi
CTID = $( dialog --title " $( translate "Select CT" ) " --menu " $( translate "Select the CT to manage Samba client:" ) " 20 70 12 $CT_LIST 3>& 1 1>& 2 2>& 3)
if [ -z " $CTID " ] ; then
dialog --title " $( translate "Error" ) " --msgbox " $( translate "No CT was selected." ) " 8 50
exit 1
fi
# === Start CT if not running ===
CT_STATUS = $( pct status " $CTID " | awk '{print $2}' )
if [ " $CT_STATUS " != "running" ] ; then
show_proxmenux_logo
msg_info " $( translate "Starting CT" ) $CTID ... "
pct start " $CTID "
sleep 2
if [ " $( pct status " $CTID " | awk '{print $2}' ) " != "running" ] ; then
msg_error " $( translate "Failed to start the CT." ) "
exit 1
fi
msg_ok " $( translate "CT started successfully." ) "
fi
install_samba_client( ) {
if pct exec " $CTID " -- dpkg -s cifs-utils & >/dev/null && pct exec " $CTID " -- dpkg -s smbclient & >/dev/null; then
pct exec " $CTID " -- mkdir -p " $CREDENTIALS_DIR "
pct exec " $CTID " -- chmod 700 " $CREDENTIALS_DIR "
return 0
fi
show_proxmenux_logo
msg_title " $( translate "Installing Samba Client" ) "
msg_info " $( translate "Installing Samba/CIFS client packages..." ) "
if ! pct exec " $CTID " -- apt-get update & >/dev/null; then
msg_error " $( translate "Failed to update package list." ) "
return 1
fi
if ! pct exec " $CTID " -- apt-get install -y cifs-utils smbclient & >/dev/null; then
msg_error " $( translate "Failed to install Samba client packages." ) "
return 1
fi
if ! pct exec " $CTID " -- which smbclient >/dev/null 2>& 1; then
msg_error " $( translate "smbclient command not found after installation." ) "
return 1
fi
if ! pct exec " $CTID " -- which mount.cifs >/dev/null 2>& 1; then
msg_error " $( translate "mount.cifs command not found after installation." ) "
return 1
fi
pct exec " $CTID " -- mkdir -p " $CREDENTIALS_DIR "
pct exec " $CTID " -- chmod 700 " $CREDENTIALS_DIR "
msg_ok " $( translate "Samba/CIFS client installed successfully." ) "
return 0
}
discover_samba_servers( ) {
show_proxmenux_logo
msg_title " $( translate "Samba LXC Manager" ) "
msg_info " $( translate "Scanning network for Samba servers..." ) "
HOST_IP = $( hostname -I | awk '{print $1}' )
NETWORK = $( echo " $HOST_IP " | cut -d. -f1-3) .0/24
for pkg in nmap samba-common-bin; do
if ! which ${ pkg %%-* } >/dev/null 2>& 1; then
apt-get install -y " $pkg " & >/dev/null
fi
done
SERVERS = $( nmap -p 139,445 --open " $NETWORK " 2>/dev/null | grep -B 4 -E "(139|445)/tcp open" | grep "Nmap scan report" | awk '{print $5}' | sort -u || true )
if [ [ -z " $SERVERS " ] ] ; then
cleanup
whiptail --title " $( translate "No Servers Found" ) " --msgbox " $( translate "No Samba servers found on the network." ) \n\n $( translate "You can add servers manually." ) " 10 60
return 1
fi
SERVER_LINES = ( )
while IFS = read -r server; do
[ [ -z " $server " ] ] && continue
NB_NAME = $( nmblookup -A " $server " 2>/dev/null | awk '/<00> -.*B <ACTIVE>/ {print $1; exit}' )
if [ [ -z " $NB_NAME " || " $NB_NAME " = = " $server " || " $NB_NAME " = = "address" || " $NB_NAME " = = "-" ] ] ; then
NB_NAME = "Unknown"
fi
SERVER_LINES += ( " $server | $NB_NAME ( $server ) " )
done <<< " $SERVERS "
IFS = $'\n' SORTED = ( $( printf "%s\n" " ${ SERVER_LINES [@] } " | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n) )
OPTIONS = ( )
declare -A SERVER_IPS
i = 1
for entry in " ${ SORTED [@] } " ; do
server = " ${ entry %%|* } "
label = " ${ entry #*| } "
OPTIONS += ( " $i " " $label " )
SERVER_IPS[ " $i " ] = " $server "
( ( i++) )
done
if [ [ ${# OPTIONS [@] } -eq 0 ] ] ; then
cleanup
whiptail --title " $( translate "No Valid Servers" ) " --msgbox " $( translate "No accessible Samba servers found." ) " 8 50
return 1
fi
msg_ok " $( translate "Samba servers detected" ) "
CHOICE = $( dialog --title " $( translate "Select Samba Server" ) " \
--menu " $( translate "Choose a Samba server:" ) " 20 80 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
if [ [ -n " $CHOICE " ] ] ; then
SAMBA_SERVER = " ${ SERVER_IPS [ $CHOICE ] } "
return 0
else
return 1
fi
}
select_samba_server( ) {
METHOD = $( dialog --title " $( translate "Samba Server Selection" ) " --menu " $( translate "How do you want to select the Samba server?" ) " 15 70 3 \
"auto" " $( translate "Auto-discover servers on network" ) " \
"manual" " $( translate "Enter server IP" ) " \
"recent" " $( translate "Select from recent servers" ) " 3>& 1 1>& 2 2>& 3)
case " $METHOD " in
auto)
discover_samba_servers || return 1
; ;
manual)
SAMBA_SERVER = $( whiptail --inputbox " $( translate "Enter Samba server IP:" ) " 10 60 --title " $( translate "Samba Server" ) " 3>& 1 1>& 2 2>& 3)
[ [ -z " $SAMBA_SERVER " ] ] && return 1
; ;
recent)
RECENT = $( pct exec " $CTID " -- grep "cifs" /etc/fstab 2>/dev/null | awk '{print $1}' | cut -d/ -f3 | sort -u || true )
if [ [ -z " $RECENT " ] ] ; then
whiptail --title " $( translate "No Recent Servers" ) " --msgbox " $( translate "No recent Samba servers found." ) " 8 50
return 1
fi
OPTIONS = ( )
while IFS = read -r server; do
[ [ -n " $server " ] ] && OPTIONS += ( " $server " " $( translate "Recent Samba server" ) " )
done <<< " $RECENT "
SAMBA_SERVER = $( whiptail --title " $( translate "Recent Samba Servers" ) " --menu " $( translate "Choose a recent server:" ) " 20 70 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
[ [ -z " $SAMBA_SERVER " ] ] && return 1
; ;
*)
return 1
; ;
esac
return 0
}
validate_guest_access( ) {
local server = " $1 "
show_proxmenux_logo
msg_info " $( translate "Testing comprehensive guest access to server" ) $server ... "
GUEST_LIST_OUTPUT = $( smbclient -L " $server " -N 2>& 1)
GUEST_LIST_RESULT = $?
if [ [ $GUEST_LIST_RESULT -ne 0 ] ] ; then
cleanup
if echo " $GUEST_LIST_OUTPUT " | grep -qi "access denied\|logon failure" ; then
whiptail --title " $( translate "Guest Access Denied" ) " \
--msgbox " $( translate "Guest access is not allowed on this server." ) \n\n $( translate "You need to use username and password authentication." ) " \
10 70
else
whiptail --title " $( translate "Guest Access Error" ) " \
--msgbox " $( translate "Guest access failed." ) \n\n $( translate "Error details:" ) \n $( echo " $GUEST_LIST_OUTPUT " | head -3) " \
12 70
fi
return 1
fi
sleep 2
msg_ok " $( translate "Guest share listing successful" ) "
GUEST_SHARES = $( echo " $GUEST_LIST_OUTPUT " | awk '/Disk/ && !/IPC\$/ && !/ADMIN\$/ && !/print\$/ {print $1}' | grep -v " ^ $" )
if [ [ -z " $GUEST_SHARES " ] ] ; then
whiptail --title " $( translate "No Guest Shares" ) " \
--msgbox " $( translate "Guest access works for listing, but no shares are available." ) \n\n $( translate "The server may require authentication for actual share access." ) " \
10 70
return 1
fi
msg_ok " $( translate "Found guest-accessible shares:" ) $( echo " $GUEST_SHARES " | wc -l) "
msg_info " $( translate "Step 2: Testing actual share access with guest..." ) "
ACCESSIBLE_SHARES = ""
FAILED_SHARES = ""
sleep 1
while IFS = read -r share; do
if [ [ -n " $share " ] ] ; then
SHARE_TEST_OUTPUT = $( smbclient " // $server / $share " -N -c "ls" 2>& 1)
SHARE_TEST_RESULT = $?
if [ [ $SHARE_TEST_RESULT -eq 0 ] ] ; then
echo -e
msg_ok " $( translate "Guest access confirmed for share:" ) $share "
echo -e
ACCESSIBLE_SHARES = " $ACCESSIBLE_SHARES $share \n "
else
msg_error " $( translate "Guest access denied for share:" ) $share "
FAILED_SHARES = " $FAILED_SHARES $share \n "
if echo " $SHARE_TEST_OUTPUT " | grep -qi "access denied\|logon failure\|authentication" ; then
msg_warn " $( translate "Reason: Authentication required" ) "
elif echo " $SHARE_TEST_OUTPUT " | grep -qi "permission denied" ; then
msg_warn " $( translate "Reason: Permission denied" ) "
else
msg_warn " $( translate "Reason: Access denied" ) "
fi
fi
fi
done <<< " $GUEST_SHARES "
ACCESSIBLE_COUNT = $( echo -e " $ACCESSIBLE_SHARES " | grep -v " ^ $" | wc -l)
FAILED_COUNT = $( echo -e " $FAILED_SHARES " | grep -v " ^ $" | wc -l)
echo -e ""
msg_info2 " $( translate "Guest Access Validation Results:" ) "
echo -e " ${ TAB } ${ BGN } $( translate "Shares found:" ) ${ CL } ${ BL } $( echo " $GUEST_SHARES " | wc -l) ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Guest accessible:" ) ${ CL } ${ GN } $ACCESSIBLE_COUNT ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Authentication required:" ) ${ CL } ${ YW } $FAILED_COUNT ${ CL } "
if [ [ $ACCESSIBLE_COUNT -gt 0 ] ] ; then
msg_ok " $( translate "Guest access validated successfully!" ) "
echo -e ""
echo -e " ${ TAB } ${ BOLD } $( translate "Available shares for guest access:" ) ${ CL } "
while IFS = read -r share; do
[ [ -n " $share " ] ] && echo -e " ${ TAB } • ${ BL } $share ${ CL } "
done <<< " $( echo -e " $ACCESSIBLE_SHARES " | grep -v " ^ $" ) "
echo -e
msg_success " $( translate "Press Enter to continue..." ) "
read -r
clear
VALIDATED_GUEST_SHARES = " $ACCESSIBLE_SHARES "
return 0
else
msg_success " $( translate "Press Enter to continue..." ) "
read -r
whiptail --title " $( translate "Guest Access Failed" ) " \
--msgbox " $( translate "While the server allows guest listing, no shares are actually accessible without authentication." ) \n\n $( translate "You need to use username and password authentication." ) " \
12 70
clear
return 1
fi
}
get_samba_credentials( ) {
while true; do
CHOICE = $( whiptail --title " $( translate "Samba Credentials" ) " \
--menu " $( translate "Select authentication mode:" ) " 13 60 2 \
"1" " $( translate "Configure with username and password" ) " \
"2" " $( translate "Configure as guest (no authentication)" ) " \
3>& 1 1>& 2 2>& 3)
if [ [ $? -ne 0 ] ] ; then
return 1
fi
case " $CHOICE " in
1)
while true; do
USERNAME = $( whiptail --inputbox " $( translate "Enter username for Samba server:" ) " 10 60 --title " $( translate "Username" ) " 3>& 1 1>& 2 2>& 3)
if [ [ $? -ne 0 ] ] ; then
break
fi
if [ [ -z " $USERNAME " ] ] ; then
whiptail --title " $( translate "Error" ) " --msgbox " $( translate "Username cannot be empty." ) " 8 50
continue
fi
while true; do
PASSWORD = $( whiptail --passwordbox " $( translate "Enter password for" ) $USERNAME : " 10 60 --title " $( translate "Password" ) " 3>& 1 1>& 2 2>& 3)
if [ [ $? -ne 0 ] ] ; then
break
fi
if [ [ -z " $PASSWORD " ] ] ; then
whiptail --title " $( translate "Error" ) " --msgbox " $( translate "Password cannot be empty." ) " 8 50
continue
fi
PASSWORD_CONFIRM = $( whiptail --passwordbox " $( translate "Confirm password for" ) $USERNAME : " 10 60 --title " $( translate "Confirm Password" ) " 3>& 1 1>& 2 2>& 3)
if [ [ $? -ne 0 ] ] ; then
continue
fi
if [ [ -z " $PASSWORD_CONFIRM " ] ] ; then
whiptail --title " $( translate "Error" ) " --msgbox " $( translate "Password confirmation cannot be empty." ) " 8 50
continue
fi
if [ [ " $PASSWORD " = = " $PASSWORD_CONFIRM " ] ] ; then
show_proxmenux_logo
msg_info " $( translate "Validating credentials with server" ) $SAMBA_SERVER ... "
TEMP_CRED = " /tmp/validate_cred_ $$ "
cat > " $TEMP_CRED " << EOF
username = $USERNAME
password = $PASSWORD
EOF
chmod 600 " $TEMP_CRED "
SHARES_OUTPUT = $( smbclient -L " $SAMBA_SERVER " -A " $TEMP_CRED " 2>& 1)
SHARES_RESULT = $?
if [ [ $SHARES_RESULT -eq 0 ] ] ; then
FIRST_SHARE = $( echo " $SHARES_OUTPUT " | awk '/Disk/ && !/IPC\$/ && !/ADMIN\$/ && !/print\$/ {print $1; exit}' )
if [ [ -n " $FIRST_SHARE " ] ] ; then
SHARE_TEST_OUTPUT = $( smbclient " // $SAMBA_SERVER / $FIRST_SHARE " -A " $TEMP_CRED " -c "ls" 2>& 1)
SHARE_TEST_RESULT = $?
rm -f " $TEMP_CRED "
if [ [ $SHARE_TEST_RESULT -eq 0 ] ] ; then
cleanup
if echo " $SHARE_TEST_OUTPUT " | grep -qi "guest" ; then
whiptail --title " $( translate "Authentication Error" ) " \
--msgbox " $( translate "The server connected you as guest instead of the specified user." ) \n\n $( translate "This means the credentials are incorrect." ) \n\n $( translate "Please check:" ) \n• $( translate "Username is correct" ) \n• $( translate "Password is correct" ) \n• $( translate "User account exists on server" ) " \
14 70
else
msg_ok " $( translate "Credentials validated successfully" ) "
USE_GUEST = false
return 0
fi
else
cleanup
if echo " $SHARE_TEST_OUTPUT " | grep -qi "access denied\|logon failure\|authentication\|NT_STATUS_LOGON_FAILURE" ; then
whiptail --title " $( translate "Authentication Error" ) " \
--msgbox " $( translate "Invalid username or password." ) \n\n $( translate "Error details:" ) \n $( echo " $SHARE_TEST_OUTPUT " | head -2) \n\n $( translate "Please check:" ) \n• $( translate "Username is correct" ) \n• $( translate "Password is correct" ) \n• $( translate "User account exists on server" ) " \
16 70
elif echo " $SHARE_TEST_OUTPUT " | grep -qi "connection refused\|network unreachable" ; then
whiptail --title " $( translate "Network Error" ) " \
--msgbox " $( translate "Cannot connect to server" ) $SAMBA_SERVER \n\n $( translate "Please check network connectivity." ) " \
10 60
return 1
else
whiptail --title " $( translate "Share Access Error" ) " \
--msgbox " $( translate "Failed to access share with provided credentials." ) \n\n $( translate "Error details:" ) \n $( echo " $SHARE_TEST_OUTPUT " | head -3) " \
12 70
fi
fi
else
cleanup
whiptail --title " $( translate "No Shares Available" ) " \
--msgbox " $( translate "Cannot validate credentials - no shares available for testing." ) \n\n $( translate "The server may not have accessible shares." ) " \
10 70
fi
else
rm -f " $TEMP_CRED "
if echo " $SHARES_OUTPUT " | grep -qi "access denied\|logon failure\|authentication\|NT_STATUS_LOGON_FAILURE" ; then
cleanup
whiptail --title " $( translate "Authentication Error" ) " \
--msgbox " $( translate "Invalid username or password." ) \n\n $( translate "Please check:" ) \n• $( translate "Username is correct" ) \n• $( translate "Password is correct" ) \n• $( translate "User account exists on server" ) \n• $( translate "Account is not locked" ) " \
12 70
elif echo " $SHARES_OUTPUT " | grep -qi "connection refused\|network unreachable" ; then
cleanup
whiptail --title " $( translate "Network Error" ) " \
--msgbox " $( translate "Cannot connect to server" ) $SAMBA_SERVER \n\n $( translate "Please check network connectivity." ) " \
10 60
return 1
else
cleanup
whiptail --title " $( translate "Connection Error" ) " \
--msgbox " $( translate "Failed to connect to server." ) \n\n $( translate "Error details:" ) \n $( echo " $SHARES_OUTPUT " | head -3) " \
12 70
fi
fi
break
else
cleanup
whiptail --title " $( translate "Password Mismatch" ) " \
--msgbox " $( translate "Passwords do not match. Please try again." ) " \
8 50
fi
done
if [ [ $? -ne 0 ] ] ; then
break
fi
done
; ;
2)
if validate_guest_access " $SAMBA_SERVER " ; then
USE_GUEST = true
return 0
fi
; ;
*)
return 1
; ;
esac
if ! whiptail --yesno " $( translate "Authentication failed." ) \n\n $( translate "Do you want to try different credentials or authentication method?" ) " 10 70 --title " $( translate "Try Again" ) " ; then
return 1
fi
done
}
select_samba_share( ) {
if ! which smbclient >/dev/null 2>& 1; then
whiptail --title " $( translate "SMB Client Error" ) " \
--msgbox " $( translate "smbclient command is not working properly." ) \n\n $( translate "Please check the installation." ) " \
10 60
return 1
fi
if [ [ " $USE_GUEST " = = "true" ] ] ; then
if [ [ -n " $VALIDATED_GUEST_SHARES " ] ] ; then
SHARES = $( echo -e " $VALIDATED_GUEST_SHARES " | grep -v " ^ $" )
else
SHARES_OUTPUT = $( smbclient -L " $SAMBA_SERVER " -N 2>& 1)
SHARES_RESULT = $?
if [ [ $SHARES_RESULT -eq 0 ] ] ; then
SHARES = $( echo " $SHARES_OUTPUT " | awk '/Disk/ && !/IPC\$/ && !/ADMIN\$/ && !/print\$/ {print $1}' | grep -v " ^ $" )
else
show_proxmenux_logo
msg_error " $( translate "Failed to get shares" ) "
echo -e
msg_success " $( translate "Press Enter to continue..." ) "
read -r
return 1
fi
fi
else
TEMP_CRED = " /tmp/temp_smb_cred_ $$ "
cat > " $TEMP_CRED " << EOF
username = $USERNAME
password = $PASSWORD
EOF
chmod 600 " $TEMP_CRED "
SHARES_OUTPUT = $( smbclient -L " $SAMBA_SERVER " -A " $TEMP_CRED " 2>& 1)
SHARES_RESULT = $?
rm -f " $TEMP_CRED "
if [ [ $SHARES_RESULT -ne 0 ] ] ; then
whiptail --title " $( translate "SMB Error" ) " \
--msgbox " $( translate "Failed to get shares from" ) $SAMBA_SERVER \n\n $( translate "This is unexpected since credentials were validated." ) " \
12 80
return 1
fi
SHARES = $( echo " $SHARES_OUTPUT " | awk '/Disk/ && !/IPC\$/ && !/ADMIN\$/ && !/print\$/ {print $1}' | grep -v " ^ $" )
fi
if [ [ -z " $SHARES " ] ] ; then
whiptail --title " $( translate "No Shares Found" ) " \
--msgbox " $( translate "No shares found on server" ) $SAMBA_SERVER \n\n $( translate "You can enter the share name manually." ) " \
12 70
SAMBA_SHARE = $( whiptail --inputbox " $( translate "Enter Samba share name:" ) " 10 60 --title " $( translate "Share Name" ) " 3>& 1 1>& 2 2>& 3)
[ [ -z " $SAMBA_SHARE " ] ] && return 1
return 0
fi
OPTIONS = ( )
while IFS = read -r share; do
if [ [ -n " $share " && " $share " != " IPC $" && " $share " != " ADMIN $" && " $share " != " print $" ] ] ; then
if [ [ " $USE_GUEST " = = "true" ] ] ; then
if echo -e " $VALIDATED_GUEST_SHARES " | grep -q " ^ $share $" ; then
OPTIONS += ( " $share " " $( translate "Guest accessible share" ) " )
fi
else
OPTIONS += ( " $share " " $( translate "Samba share" ) " )
fi
fi
done <<< " $SHARES "
if [ [ ${# OPTIONS [@] } -eq 0 ] ] ; then
whiptail --title " $( translate "No Available Shares" ) " \
--msgbox " $( translate "No accessible shares found." ) \n\n $( translate "You can enter the share name manually." ) " \
10 70
SAMBA_SHARE = $( whiptail --inputbox " $( translate "Enter Samba share name:" ) " 10 60 --title " $( translate "Share Name" ) " 3>& 1 1>& 2 2>& 3)
[ [ -z " $SAMBA_SHARE " ] ] && return 1
return 0
fi
SAMBA_SHARE = $( whiptail --title " $( translate "Select Samba Share" ) " --menu " $( translate "Choose a share to mount:" ) " 20 70 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
[ [ -n " $SAMBA_SHARE " ] ] && return 0 || return 1
}
select_mount_point( ) {
while true; do
METHOD = $( whiptail --title " $( translate "Select Mount Point" ) " --menu " $( translate "Where do you want to mount the Samba share?" ) " 15 70 3 \
"existing" " $( translate "Select from existing folders in /mnt" ) " \
"new" " $( translate "Create new folder in /mnt" ) " \
"custom" " $( translate "Enter custom path" ) " 3>& 1 1>& 2 2>& 3)
case " $METHOD " in
existing)
DIRS = $( pct exec " $CTID " -- find /mnt -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
if [ [ -z " $DIRS " ] ] ; then
whiptail --title " $( translate "No Folders" ) " --msgbox " $( translate "No folders found in /mnt. Please create a new folder." ) " 8 60
continue
fi
OPTIONS = ( )
while IFS = read -r dir; do
if [ [ -n " $dir " ] ] ; then
name = $( basename " $dir " )
if pct exec " $CTID " -- [ " $( ls -A " $dir " 2>/dev/null | wc -l) " -eq 0 ] ; then
status = " $( translate "Empty" ) "
else
status = " $( translate "Contains files" ) "
fi
OPTIONS += ( " $dir " " $name ( $status ) " )
fi
done <<< " $DIRS "
MOUNT_POINT = $( whiptail --title " $( translate "Select Existing Folder" ) " --menu " $( translate "Choose a folder to mount the share:" ) " 20 80 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
if [ [ -n " $MOUNT_POINT " ] ] ; then
if pct exec " $CTID " -- [ " $( ls -A " $MOUNT_POINT " 2>/dev/null | wc -l) " -gt 0 ] ; then
FILE_COUNT = $( pct exec " $CTID " -- ls -A " $MOUNT_POINT " 2>/dev/null | wc -l)
if ! whiptail --yesno " $( translate "WARNING: The selected directory is not empty!" ) \n\n $( translate "Directory:" ) : $MOUNT_POINT \n $( translate "Contains:" ) : $FILE_COUNT $( translate "files/folders" ) \n\n $( translate "Mounting here will hide existing files until unmounted." ) \n\n $( translate "Do you want to continue?" ) " 14 70 --title " $( translate "Directory Not Empty" ) " ; then
continue
fi
fi
return 0
fi
; ;
new)
FOLDER_NAME = $( whiptail --inputbox " $( translate "Enter new folder name:" ) " 10 60 " ${ SAMBA_SHARE } " --title " $( translate "New Folder in /mnt" ) " 3>& 1 1>& 2 2>& 3)
if [ [ -n " $FOLDER_NAME " ] ] ; then
MOUNT_POINT = " /mnt/ $FOLDER_NAME "
return 0
fi
; ;
custom)
MOUNT_POINT = $( whiptail --inputbox " $( translate "Enter full path for mount point:" ) " 10 70 "/mnt/samba_share" --title " $( translate "Custom Path" ) " 3>& 1 1>& 2 2>& 3)
if [ [ -n " $MOUNT_POINT " ] ] ; then
return 0
fi
; ;
*)
return 1
; ;
esac
done
}
configure_mount_options( ) {
MOUNT_TYPE = $( whiptail --title " $( translate "Mount Options" ) " --menu " $( translate "Select mount configuration:" ) " 15 70 4 \
2025-09-04 20:23:00 +02:00
"1" " $( translate "Default options read/write" ) " \
"2" " $( translate "Read-only mount" ) " \
"3" " $( translate "Performance optimized" ) " \
2025-08-22 18:05:14 +02:00
"custom" " $( translate "Custom options" ) " 3>& 1 1>& 2 2>& 3)
case " $MOUNT_TYPE " in
2025-09-04 20:23:00 +02:00
1)
2025-08-22 18:05:14 +02:00
MOUNT_OPTIONS = "rw,file_mode=0664,dir_mode=0775,iocharset=utf8"
; ;
2025-09-04 20:23:00 +02:00
1)
2025-08-22 18:05:14 +02:00
MOUNT_OPTIONS = "ro,file_mode=0444,dir_mode=0555,iocharset=utf8"
; ;
2025-09-04 20:23:00 +02:00
3)
2025-08-22 18:05:14 +02:00
MOUNT_OPTIONS = $( whiptail --inputbox " $( translate "Enter custom mount options:" ) " 10 70 "rw,file_mode=0664,dir_mode=0775" --title " $( translate "Custom Options" ) " 3>& 1 1>& 2 2>& 3)
[ [ -z " $MOUNT_OPTIONS " ] ] && MOUNT_OPTIONS = "rw,file_mode=0664,dir_mode=0775"
; ;
*)
MOUNT_OPTIONS = "rw,file_mode=0664,dir_mode=0775,iocharset=utf8"
; ;
esac
if whiptail --yesno " $( translate "Do you want to make this mount permanent?" ) \n\n $( translate "This will add the mount to /etc/fstab so it persists after reboot." ) " 10 70 --title " $( translate "Permanent Mount" ) " ; then
PERMANENT_MOUNT = true
else
PERMANENT_MOUNT = false
fi
}
create_credentials_file( ) {
if [ [ " $USE_GUEST " = = "true" ] ] ; then
return 0
fi
CRED_FILE = " $CREDENTIALS_DIR / ${ SAMBA_SERVER } _ ${ SAMBA_SHARE } .cred "
pct exec " $CTID " -- bash -c " cat > ' $CRED_FILE ' << EOF
username = $USERNAME
password = $PASSWORD
EOF"
pct exec " $CTID " -- chmod 600 " $CRED_FILE "
msg_ok " $( translate "Credentials file created securely." ) "
}
validate_share_exists( ) {
local server = " $1 "
local share = " $2 "
local use_guest = " $3 "
local username = " $4 "
local password = " $5 "
if [ [ " $use_guest " = = "true" ] ] ; then
VALIDATION_OUTPUT = $( pct exec " $CTID " -- smbclient -L " $server " -N 2>/dev/null | grep " ^[[:space:]]* $share [[:space:]] " )
else
TEMP_CRED = " /tmp/validate_cred_ $$ "
pct exec " $CTID " -- bash -c " cat > $TEMP_CRED << EOF
username = $username
password = $password
EOF"
pct exec " $CTID " -- chmod 600 " $TEMP_CRED "
VALIDATION_OUTPUT = $( pct exec " $CTID " -- smbclient -L " $server " -A " $TEMP_CRED " 2>/dev/null | grep " ^[[:space:]]* $share [[:space:]] " )
pct exec " $CTID " -- rm -f " $TEMP_CRED "
fi
if [ [ -n " $VALIDATION_OUTPUT " ] ] ; then
return 0
else
show_proxmenux_logo
msg_error " $( translate "Share not found on server:" ) $share "
msg_success " $( translate "Press Enter to continue..." ) "
read -r
return 1
fi
}
mount_samba_share( ) {
# Step 0:
install_samba_client || return
# Step 1:
select_samba_server || return
# Step 2:
get_samba_credentials || return
# Step 3:
select_samba_share || return
if ! validate_share_exists " $SAMBA_SERVER " " $SAMBA_SHARE " " $USE_GUEST " " $USERNAME " " $PASSWORD " ; then
echo -e ""
msg_error " $( translate "Cannot proceed with invalid share name." ) "
msg_success " $( translate "Press Enter to return to menu..." ) "
read -r
return
fi
# Step 4:
select_mount_point || return
# Step 5:
configure_mount_options || return
show_proxmenux_logo
2025-09-04 20:26:51 +02:00
msg_title " $( translate "Installing Samba Client in LXC" ) "
2025-08-22 18:05:14 +02:00
if ! pct exec " $CTID " -- test -d " $MOUNT_POINT " ; then
if pct exec " $CTID " -- mkdir -p " $MOUNT_POINT " ; then
msg_ok " $( translate "Mount point created." ) "
else
msg_error " $( translate "Failed to create mount point." ) "
return 1
fi
fi
if pct exec " $CTID " -- mount | grep -q " $MOUNT_POINT " ; then
msg_warn " $( translate "Something is already mounted at" ) $MOUNT_POINT "
if ! whiptail --yesno " $( translate "Do you want to unmount it first?" ) " 8 60 --title " $( translate "Already Mounted" ) " ; then
return
fi
pct exec " $CTID " -- umount " $MOUNT_POINT " 2>/dev/null || true
fi
if [ [ " $USE_GUEST " != "true" ] ] ; then
create_credentials_file
CRED_OPTION = " credentials= $CRED_FILE "
else
CRED_OPTION = "guest"
fi
FULL_OPTIONS = " $MOUNT_OPTIONS , $CRED_OPTION "
UNC_PATH = " // $SAMBA_SERVER / $SAMBA_SHARE "
#if pct exec "$CTID" -- mount -t cifs "$UNC_PATH" "$MOUNT_POINT" -o "$FULL_OPTIONS"; then
if pct exec " $CTID " -- mount -t cifs " $UNC_PATH " " $MOUNT_POINT " -o " $FULL_OPTIONS " 2>/dev/null; then
msg_ok " $( translate "Samba share mounted successfully!" ) "
if pct exec " $CTID " -- touch " $MOUNT_POINT /.test_write " 2>/dev/null; then
pct exec " $CTID " -- rm " $MOUNT_POINT /.test_write " 2>/dev/null
msg_ok " $( translate "Write access confirmed." ) "
else
msg_warn " $( translate "Read-only access (or no write permissions)." ) "
fi
if [ [ " $PERMANENT_MOUNT " = = "true" ] ] ; then
pct exec " $CTID " -- sed -i " \| $MOUNT_POINT |d " /etc/fstab
FSTAB_ENTRY = " $UNC_PATH $MOUNT_POINT cifs $FULL_OPTIONS 0 0 "
pct exec " $CTID " -- bash -c " echo ' $FSTAB_ENTRY ' >> /etc/fstab "
msg_ok " $( translate "Added to /etc/fstab for permanent mounting." ) "
fi
echo -e ""
echo -e " ${ TAB } ${ BOLD } $( translate "Mount Information:" ) ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Server:" ) ${ CL } ${ BL } $SAMBA_SERVER ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Share:" ) ${ CL } ${ BL } $SAMBA_SHARE ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Mount Point:" ) ${ CL } ${ BL } $MOUNT_POINT ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Authentication:" ) ${ CL } ${ BL } $( [ " $USE_GUEST " = = "true" ] && echo "Guest" || echo " User: $USERNAME " ) ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Permanent:" ) ${ CL } ${ BL } $PERMANENT_MOUNT ${ CL } "
else
msg_error " $( translate "Failed to mount Samba share." ) "
echo -e " ${ TAB } $( translate "Please check:" ) "
echo -e " ${ TAB } • $( translate "Server is accessible:" ) : $SAMBA_SERVER "
echo -e " ${ TAB } • $( translate "Share exists:" ) : $SAMBA_SHARE "
echo -e " ${ TAB } • $( translate "Credentials are correct" ) "
echo -e " ${ TAB } • $( translate "Network connectivity" ) "
echo -e " ${ TAB } • $( translate "Samba server is running" ) "
if [ [ " $USE_GUEST " != "true" && -n " $CRED_FILE " ] ] ; then
pct exec " $CTID " -- rm -f " $CRED_FILE " 2>/dev/null || true
fi
fi
echo -e ""
msg_success " $( translate "Press Enter to return to menu..." ) "
read -r
}
view_samba_mounts( ) {
show_proxmenux_logo
msg_title " $( translate "Current Samba Mounts" ) "
echo -e " $( translate "Samba/CIFS mounts in CT" ) $CTID : "
echo "=================================="
CURRENT_MOUNTS = $( pct exec " $CTID " -- mount -t cifs 2>/dev/null || true )
if [ [ -n " $CURRENT_MOUNTS " ] ] ; then
echo -e " ${ BOLD } $( translate "Currently Mounted:" ) ${ CL } "
echo " $CURRENT_MOUNTS "
echo ""
else
echo " $( translate "No Samba shares currently mounted." ) "
echo ""
fi
FSTAB_CIFS = $( pct exec " $CTID " -- grep "cifs" /etc/fstab 2>/dev/null || true )
if [ [ -n " $FSTAB_CIFS " ] ] ; then
echo -e " ${ BOLD } $( translate "Permanent Mounts (fstab):" ) ${ CL } "
echo " $FSTAB_CIFS "
echo ""
echo -e " ${ TAB } ${ BOLD } $( translate "Mount Details:" ) ${ CL } "
while IFS = read -r fstab_line; do
if [ [ -n " $fstab_line " && ! " $fstab_line " = ~ ^# ] ] ; then
UNC_PATH = $( echo " $fstab_line " | awk '{print $1}' )
MOUNT_POINT = $( echo " $fstab_line " | awk '{print $2}' )
OPTIONS = $( echo " $fstab_line " | awk '{print $4}' )
SERVER = $( echo " $UNC_PATH " | cut -d/ -f3)
SHARE = $( echo " $UNC_PATH " | cut -d/ -f4)
echo -e " ${ TAB } ${ BGN } $( translate "Server:" ) ${ CL } ${ BL } $SERVER ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Share:" ) ${ CL } ${ BL } $SHARE ${ CL } "
echo -e " ${ TAB } ${ BGN } $( translate "Mount Point:" ) ${ CL } ${ BL } $MOUNT_POINT ${ CL } "
if echo " $OPTIONS " | grep -q "guest" ; then
echo -e " ${ TAB } ${ BGN } $( translate "Authentication:" ) ${ CL } ${ BL } Guest ${ CL } "
elif echo " $OPTIONS " | grep -q "credentials=" ; then
CRED_FILE = $( echo " $OPTIONS " | grep -o "credentials=[^,]*" | cut -d= -f2)
echo -e " ${ TAB } ${ BGN } $( translate "Authentication:" ) ${ CL } ${ BL } Credentials ( $CRED_FILE ) ${ CL } "
fi
if pct exec " $CTID " -- mount | grep -q " $MOUNT_POINT " ; then
echo -e " ${ TAB } ${ BGN } $( translate "Status:" ) ${ CL } ${ GN } $( translate "Mounted" ) ${ CL } "
else
echo -e " ${ TAB } ${ BGN } $( translate "Status:" ) ${ CL } ${ RD } $( translate "Not Mounted" ) ${ CL } "
fi
echo ""
fi
done <<< " $FSTAB_CIFS "
else
echo " $( translate "No permanent Samba mounts configured." ) "
fi
CRED_FILES = $( pct exec " $CTID " -- find " $CREDENTIALS_DIR " -name "*.cred" 2>/dev/null || true )
if [ [ -n " $CRED_FILES " ] ] ; then
echo -e " ${ BOLD } $( translate "Stored Credentials:" ) ${ CL } "
while IFS = read -r cred_file; do
if [ [ -n " $cred_file " ] ] ; then
FILENAME = $( basename " $cred_file " )
echo -e " ${ TAB } • $FILENAME "
fi
done <<< " $CRED_FILES "
echo ""
fi
echo ""
msg_success " $( translate "Press Enter to return to menu..." ) "
read -r
}
unmount_samba_share( ) {
MOUNTS = $( pct exec " $CTID " -- mount -t cifs 2>/dev/null | awk '{print $3}' | sort -u || true )
FSTAB_MOUNTS = $( pct exec " $CTID " -- grep -E "cifs" /etc/fstab 2>/dev/null | grep -v "^#" | awk '{print $2}' | sort -u || true )
ALL_MOUNTS = $( echo -e " $MOUNTS \n $FSTAB_MOUNTS " | sort -u | grep -v " ^ $" || true )
if [ [ -z " $ALL_MOUNTS " ] ] ; then
dialog --title " $( translate "No Mounts" ) " --msgbox " \n $( translate "No Samba mounts found." ) " 8 50
return
fi
OPTIONS = ( )
while IFS = read -r mount_point; do
[ [ -n " $mount_point " ] ] && OPTIONS += ( " $mount_point " "" )
done <<< " $ALL_MOUNTS "
SELECTED_MOUNT = $( dialog --title " $( translate "Unmount Samba Share" ) " --menu " $( translate "Select mount point to unmount:" ) " 20 80 10 " ${ OPTIONS [@] } " 3>& 1 1>& 2 2>& 3)
[ [ -z " $SELECTED_MOUNT " ] ] && return
if whiptail --yesno " $( translate "Are you sure you want to unmount this Samba share?" ) \n\n $( translate "Mount Point:" ) $SELECTED_MOUNT \n\n $( translate "This will remove the mount from /etc/fstab and delete credentials if present." ) " 14 80 --title " $( translate "Confirm Unmount" ) " ; then
show_proxmenux_logo
msg_title " $( translate "Unmount Samba Share" ) "
CRED_FILE = $( pct exec " $CTID " -- grep -E " \s+ $SELECTED_MOUNT \s+ " /etc/fstab 2>/dev/null | grep -o "credentials=[^, ]*" | cut -d= -f2 || true )
pct exec " $CTID " -- sed -i " \|[[:space:]] $SELECTED_MOUNT [[:space:]]|d " /etc/fstab
msg_ok " $( translate "Removed from /etc/fstab." ) "
if [ [ -n " $CRED_FILE " && " $CRED_FILE " != "guest" ] ] ; then
if pct exec " $CTID " -- test -f " $CRED_FILE " ; then
pct exec " $CTID " -- rm -f " $CRED_FILE "
msg_ok " $( translate "Credentials file removed." ) "
fi
fi
echo -e ""
msg_ok " $( translate "Samba share unmount successfully. Reboot LXC required to take effect." ) "
echo -e ""
msg_success " $( translate "Press Enter to return to menu..." ) "
read -r
fi
}
test_samba_connectivity( ) {
show_proxmenux_logo
msg_title " $( translate "Test Samba Connectivity" ) "
echo -e " $( translate "Samba/CIFS Client Status in CT" ) $CTID : "
echo "=================================="
if pct exec " $CTID " -- dpkg -s cifs-utils & >/dev/null; then
echo " $( translate "CIFS Client: INSTALLED" ) "
if pct exec " $CTID " -- which smbclient >/dev/null 2>& 1; then
echo " $( translate "SMB Client Tools: AVAILABLE" ) "
else
echo " $( translate "SMB Client Tools: NOT AVAILABLE" ) "
fi
echo ""
echo " $( translate "Current CIFS mounts:" ) "
CURRENT_MOUNTS = $( pct exec " $CTID " -- mount -t cifs 2>/dev/null || true )
if [ [ -n " $CURRENT_MOUNTS " ] ] ; then
echo " $CURRENT_MOUNTS "
else
echo " $( translate "No CIFS mounts active." ) "
fi
echo ""
echo " $( translate "Testing network connectivity..." ) "
FSTAB_SERVERS = $( pct exec " $CTID " -- grep "cifs" /etc/fstab 2>/dev/null | awk '{print $1}' | cut -d/ -f3 | sort -u || true )
if [ [ -n " $FSTAB_SERVERS " ] ] ; then
while IFS = read -r server; do
if [ [ -n " $server " ] ] ; then
echo -n " $( translate "Testing" ) $server : "
if pct exec " $CTID " -- ping -c 1 -W 2 " $server " >/dev/null 2>& 1; then
echo -e " ${ GN } $( translate "Reachable" ) ${ CL } "
if pct exec " $CTID " -- nc -z -w 2 " $server " 445 2>/dev/null; then
echo " $( translate "SMB port 445:" ) : ${ GN } $( translate "Open" ) ${ CL } "
elif pct exec " $CTID " -- nc -z -w 2 " $server " 139 2>/dev/null; then
echo " $( translate "NetBIOS port 139:" ) : ${ GN } $( translate "Open" ) ${ CL } "
else
echo " $( translate "SMB ports:" ) : ${ RD } $( translate "Closed" ) ${ CL } "
fi
echo -n " $( translate "Guest access test:" ) : "
if pct exec " $CTID " -- smbclient -L " $server " -N >/dev/null 2>& 1; then
echo -e " ${ GN } $( translate "Available" ) ${ CL } "
else
echo -e " ${ YW } $( translate "Requires authentication" ) ${ CL } "
fi
else
echo -e " ${ RD } $( translate "Unreachable" ) ${ CL } "
fi
fi
done <<< " $FSTAB_SERVERS "
else
echo " $( translate "No Samba servers configured to test." ) "
fi
echo ""
echo " $( translate "Stored credentials:" ) "
CRED_FILES = $( pct exec " $CTID " -- find " $CREDENTIALS_DIR " -name "*.cred" 2>/dev/null || true )
if [ [ -n " $CRED_FILES " ] ] ; then
while IFS = read -r cred_file; do
if [ [ -n " $cred_file " ] ] ; then
FILENAME = $( basename " $cred_file " )
echo " • $FILENAME "
fi
done <<< " $CRED_FILES "
else
echo " $( translate "No stored credentials found." ) "
fi
else
echo " $( translate "CIFS Client: NOT INSTALLED" ) "
echo ""
echo " $( translate "Run 'Mount Samba Share' to install CIFS client automatically." ) "
fi
echo ""
msg_success " $( translate "Press Enter to return to menu..." ) "
read -r
}
# === Main Menu ===
while true; do
CHOICE = $( dialog --title " $( translate "Samba Client Manager - CT" ) $CTID " \
--menu " $( translate "Choose an option:" ) " 20 70 12 \
"1" " $( translate "Mount Samba Share" ) " \
"2" " $( translate "View Current Mounts" ) " \
"3" " $( translate "Unmount Samba Share" ) " \
"4" " $( translate "Test Samba Connectivity" ) " \
"5" " $( translate "Exit" ) " \
3>& 1 1>& 2 2>& 3)
RETVAL = $?
if [ [ $RETVAL -ne 0 ] ] ; then
exit 0
fi
case $CHOICE in
1) mount_samba_share ; ;
2) view_samba_mounts ; ;
3) unmount_samba_share ; ;
4) test_samba_connectivity ; ;
5) exit 0 ; ;
*) exit 0 ; ;
esac
done