Dotfiles/setup/modules/FreeipaAnsible/ansible/policies.d/usr_smb.sh

146 lines
5.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
# policy: usr_smb — auto-mount network shares in user home directories.
# usr_smb_r_<name> mount read-only share ~/name for logged-in members
# usr_smb_rw_<name> mount read-write share ~/name for logged-in members
# rw membership takes precedence over r for the same share name.
# Credential (server, Samba user, password) stored in IPA group description by
# ansipa-smb-setup.sh: cifs://<ipa-host>:<samba-user>:<password>
# Requires: cifs-utils installed on the client.
SMB_MOUNT_STATE="$STATE_DIR/smb-mounts"
[[ -f "$SMB_MOUNT_STATE" ]] || touch "$SMB_MOUNT_STATE"
SMB_CREDS_DIR="$STATE_DIR/smb-creds"
mkdir -p "$SMB_CREDS_DIR"
chmod 700 "$SMB_CREDS_DIR"
if command -v mount.cifs &>/dev/null; then
# ── Discover usr_smb_r_* / usr_smb_rw_* from the already-fetched group list
declare -A _SMB_R_GRP _SMB_RW_GRP
while IFS= read -r _g; do
[[ -z "$_g" ]] && continue
if [[ "$_g" =~ ^usr_smb_r_(.+)$ ]]; then _SMB_R_GRP["${BASH_REMATCH[1]}"]="$_g"
elif [[ "$_g" =~ ^usr_smb_rw_(.+)$ ]]; then _SMB_RW_GRP["${BASH_REMATCH[1]}"]="$_g"
fi
done <<< "$_ALL_USER_GROUPS"
unset _g
declare -A _SMB_NAMES
for _n in "${!_SMB_R_GRP[@]}" "${!_SMB_RW_GRP[@]}"; do _SMB_NAMES["$_n"]=1; done
unset _n
_smb_member() { id -nG "$1" 2>/dev/null | tr ' ' '\n' | grep -qxF "$2"; }
declare -A _SMB_SESS
_smb_add_sess() {
local _u
[[ "$2" == "loginctl" ]] && _u=$(awk '{print $3}' <<< "$1") \
|| _u=$(awk '{print $1}' <<< "$1")
[[ -z "$_u" || "$_u" == "root" || "$_u" == "USER" ]] && return 0
local _h; _h=$(getent passwd "$_u" | cut -d: -f6 2>/dev/null) || return 0
[[ -d "$_h" ]] && _SMB_SESS["$_u"]="$_h"
}
if loginctl list-sessions --no-legend &>/dev/null; then
while IFS= read -r _L; do _smb_add_sess "$_L" "loginctl"
done < <(loginctl list-sessions --no-legend 2>/dev/null)
else
while IFS= read -r _L; do _smb_add_sess "$_L" "who"
done < <(who 2>/dev/null)
fi
unset _L
for _SMB_NAME in "${!_SMB_NAMES[@]}"; do
_R_GRP="${_SMB_R_GRP[$_SMB_NAME]:-}"
_RW_GRP="${_SMB_RW_GRP[$_SMB_NAME]:-}"
_CRED_LINE=""
[[ -n "$_RW_GRP" ]] && _CRED_LINE=$(_smb_parse_cred "$_RW_GRP")
[[ -z "$_CRED_LINE" && -n "$_R_GRP" ]] && _CRED_LINE=$(_smb_parse_cred "$_R_GRP")
if [[ -z "$_CRED_LINE" ]]; then
warn "No credential in IPA description for share $_SMB_NAME — skipped (run ansipa-smb.service on FreeIPA container)"
continue
fi
read -r _SMB_HOST _SMB_SUSER _SMB_SPASS <<< "$_CRED_LINE"
_CREDS_FILE="$SMB_CREDS_DIR/${_SMB_NAME}.creds"
printf 'username=%s\npassword=%s\ndomain=WORKGROUP\n' "$_SMB_SUSER" "$_SMB_SPASS" \
> "$_CREDS_FILE"
chmod 600 "$_CREDS_FILE"
for _SMB_U in "${!_SMB_SESS[@]}"; do
_SMB_LVL=""
[[ -n "$_RW_GRP" ]] && _smb_member "$_SMB_U" "$_RW_GRP" && _SMB_LVL="rw"
[[ -z "$_SMB_LVL" && -n "$_R_GRP" ]] && _smb_member "$_SMB_U" "$_R_GRP" && _SMB_LVL="r"
[[ -z "$_SMB_LVL" ]] && continue
_SMB_H="${_SMB_SESS[$_SMB_U]}"
_SMB_MP="$_SMB_H/$_SMB_NAME"
_SMB_SHARE="usr-${_SMB_NAME}-${_SMB_LVL}"
if mountpoint -q "$_SMB_MP" 2>/dev/null; then
grep -qxF "${_SMB_U}:${_SMB_NAME}" "$SMB_MOUNT_STATE" 2>/dev/null || \
echo "${_SMB_U}:${_SMB_NAME}" >> "$SMB_MOUNT_STATE"
continue
fi
mkdir -p "$_SMB_MP"
chown "$_SMB_U" "$_SMB_MP" 2>/dev/null || true
if mount -t cifs "//${_SMB_HOST}/${_SMB_SHARE}" "$_SMB_MP" \
-o "credentials=${_CREDS_FILE},uid=${_SMB_U},gid=${_SMB_U},file_mode=0644,dir_mode=0755,nounix,noserverino" \
2>/dev/null; then
log "Mounted //${_SMB_HOST}/${_SMB_SHARE}$_SMB_MP for $_SMB_U"
grep -qxF "${_SMB_U}:${_SMB_NAME}" "$SMB_MOUNT_STATE" 2>/dev/null || \
echo "${_SMB_U}:${_SMB_NAME}" >> "$SMB_MOUNT_STATE"
else
warn "Failed to mount //${_SMB_HOST}/${_SMB_SHARE} for $_SMB_U"
rmdir "$_SMB_MP" 2>/dev/null || true
fi
done
done
unset _SMB_NAME _R_GRP _RW_GRP _CRED_LINE _SMB_HOST _SMB_SUSER _SMB_SPASS \
_CREDS_FILE _SMB_U _SMB_H _SMB_MP _SMB_SHARE _SMB_LVL
_NEW_SMB_MOUNTS=()
while IFS=: read -r _OLD_USER _OLD_NAME; do
[[ -z "$_OLD_USER" || -z "$_OLD_NAME" ]] && continue
_OLD_HOME=$(getent passwd "$_OLD_USER" | cut -d: -f6 2>/dev/null) || continue
_OLD_MPT="$_OLD_HOME/$_OLD_NAME"
_STILL_MEMBER=false
if [[ -n "${_SMB_R_GRP[$_OLD_NAME]+x}" ]] && \
_smb_member "$_OLD_USER" "${_SMB_R_GRP[$_OLD_NAME]}"; then
_STILL_MEMBER=true
elif [[ -n "${_SMB_RW_GRP[$_OLD_NAME]+x}" ]] && \
_smb_member "$_OLD_USER" "${_SMB_RW_GRP[$_OLD_NAME]}"; then
_STILL_MEMBER=true
fi
if [[ "$_STILL_MEMBER" == true ]]; then
_NEW_SMB_MOUNTS+=("${_OLD_USER}:${_OLD_NAME}")
else
umount -l "$_OLD_MPT" 2>/dev/null || true
rmdir "$_OLD_MPT" 2>/dev/null || true
log "Unmounted ${_OLD_MPT} for ${_OLD_USER} (left usr_smb_*_${_OLD_NAME})"
fi
done < "$SMB_MOUNT_STATE"
unset _OLD_USER _OLD_NAME _OLD_HOME _OLD_MPT _STILL_MEMBER
if [[ ${#_NEW_SMB_MOUNTS[@]} -gt 0 ]]; then
printf '%s\n' "${_NEW_SMB_MOUNTS[@]}" | sort -u > "$SMB_MOUNT_STATE"
else
> "$SMB_MOUNT_STATE"
fi
rm -f "$SMB_CREDS_DIR"/*.creds 2>/dev/null || true
unset _SMB_R_GRP _SMB_RW_GRP _SMB_NAMES _SMB_SESS _NEW_SMB_MOUNTS
else
warn "mount.cifs not found — install cifs-utils to enable usr_smb_* policies"
[[ -s "$SMB_MOUNT_STATE" ]] && \
warn "smb-mounts state is non-empty — cannot revert existing mounts without cifs-utils" || true
fi