#!/usr/bin/env bash # policy: usr_smb — auto-mount network shares in user home directories. # usr_smb_r_ mount read-only share ~/‹name› for logged-in members # usr_smb_rw_ 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://:: # 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