#!/usr/bin/env bash # policy: usr_policystore — auto-mount the ansipa policy store for admins. # When the IPA user group usr_smb_adm_policystore exists, members who are # logged in get the ansipa-policystore SMB share mounted at ~/policystore (rw). # The mount is tracked in state and removed when the group is deleted or the # user is no longer a member. # Credential: cifs://:smb-policystore: in the IPA group description, # written by ansipa-smb-setup.sh. # # This is an EDITING CONVENIENCE ONLY: files saved here are not distributed to # the fleet automatically. Distribution happens via git — commit the change, # sign it, and push to the ansipa-policy git server; ansipa-pull-apply.sh on # each node verifies the signature and applies it. See # docs/md/freeipa-ansible.md, "Git-based policy distribution". PS_MOUNT_STATE="$STATE_DIR/policystore-mounts" PS_CREDS_DIR="$STATE_DIR/smb-creds" PS_CREDS_FILE="$PS_CREDS_DIR/policystore.creds" [[ -f "$PS_MOUNT_STATE" ]] || touch "$PS_MOUNT_STATE" mkdir -p "$PS_CREDS_DIR" chmod 700 "$PS_CREDS_DIR" _ps_grp_exists=false grep -qxF "usr_smb_adm_policystore" <<< "$_ALL_USER_GROUPS" && _ps_grp_exists=true _ps_member() { id -nG "$1" 2>/dev/null | tr ' ' '\n' | grep -qxF "usr_smb_adm_policystore"; } if [[ "$_ps_grp_exists" == true ]] && command -v mount.cifs &>/dev/null; then _PS_CRED=$(_smb_parse_cred "usr_smb_adm_policystore") if [[ -z "$_PS_CRED" ]]; then warn "usr_smb_adm_policystore: no cifs:// credential in IPA group description" warn " — run ansipa-smb.service on the FreeIPA container first" else read -r _PS_HOST _PS_SUSER _PS_SPASS <<< "$_PS_CRED" printf 'username=%s\npassword=%s\ndomain=WORKGROUP\n' "$_PS_SUSER" "$_PS_SPASS" \ > "$PS_CREDS_FILE" chmod 600 "$PS_CREDS_FILE" # Collect logged-in users. declare -A _PS_SESS _ps_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" ]] && _PS_SESS["$_u"]="$_h" } if loginctl list-sessions --no-legend &>/dev/null; then while IFS= read -r _L; do _ps_add_sess "$_L" "loginctl" done < <(loginctl list-sessions --no-legend 2>/dev/null) else while IFS= read -r _L; do _ps_add_sess "$_L" "who" done < <(who 2>/dev/null) fi unset _L # Mount for logged-in members. for _PS_U in "${!_PS_SESS[@]}"; do _ps_member "$_PS_U" || continue _PS_H="${_PS_SESS[$_PS_U]}" _PS_MP="$_PS_H/policystore" if mountpoint -q "$_PS_MP" 2>/dev/null; then grep -qxF "$_PS_U" "$PS_MOUNT_STATE" 2>/dev/null || \ echo "$_PS_U" >> "$PS_MOUNT_STATE" continue fi mkdir -p "$_PS_MP" chown "$_PS_U" "$_PS_MP" 2>/dev/null || true if mount -t cifs "//${_PS_HOST}/ansipa-policystore" "$_PS_MP" \ -o "credentials=${PS_CREDS_FILE},uid=${_PS_U},gid=${_PS_U},file_mode=0664,dir_mode=02775,nounix,noserverino" \ 2>/dev/null; then log "Mounted //${_PS_HOST}/ansipa-policystore → $_PS_MP for $_PS_U" grep -qxF "$_PS_U" "$PS_MOUNT_STATE" 2>/dev/null || \ echo "$_PS_U" >> "$PS_MOUNT_STATE" else warn "Failed to mount policystore for $_PS_U" rmdir "$_PS_MP" 2>/dev/null || true fi done unset _PS_U _PS_H _PS_MP # Revert: unmount for users no longer in the group or group deleted. _NEW_PS_MOUNTS=() while IFS= read -r _OLD_PS_U; do [[ -z "$_OLD_PS_U" ]] && continue _OLD_PS_HOME=$(getent passwd "$_OLD_PS_U" | cut -d: -f6 2>/dev/null) || continue _OLD_PS_MP="$_OLD_PS_HOME/policystore" if _ps_member "$_OLD_PS_U"; then _NEW_PS_MOUNTS+=("$_OLD_PS_U") else umount -l "$_OLD_PS_MP" 2>/dev/null || true rmdir "$_OLD_PS_MP" 2>/dev/null || true log "Unmounted policystore for $_OLD_PS_U (no longer in usr_smb_adm_policystore)" fi done < "$PS_MOUNT_STATE" unset _OLD_PS_U _OLD_PS_HOME _OLD_PS_MP if [[ ${#_NEW_PS_MOUNTS[@]} -gt 0 ]]; then printf '%s\n' "${_NEW_PS_MOUNTS[@]}" | sort -u > "$PS_MOUNT_STATE" else > "$PS_MOUNT_STATE" fi unset _NEW_PS_MOUNTS _PS_SESS _PS_HOST _PS_SUSER _PS_SPASS _PS_CRED rm -f "$PS_CREDS_FILE" 2>/dev/null || true fi else # Group deleted — unmount for any previously-tracked users. if [[ -s "$PS_MOUNT_STATE" ]]; then while IFS= read -r _OLD_PS_U; do [[ -z "$_OLD_PS_U" ]] && continue _OLD_PS_HOME=$(getent passwd "$_OLD_PS_U" | cut -d: -f6 2>/dev/null) || continue umount -l "$_OLD_PS_HOME/policystore" 2>/dev/null || true rmdir "$_OLD_PS_HOME/policystore" 2>/dev/null || true log "Unmounted policystore for $_OLD_PS_U (usr_smb_adm_policystore group deleted)" done < "$PS_MOUNT_STATE" > "$PS_MOUNT_STATE" unset _OLD_PS_U _OLD_PS_HOME fi fi unset _ps_grp_exists