Improve domain enrollment and desktop personalization
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generates and applies the SGU welcome wallpaper inside a Linux desktop session.
|
||||
# It is intentionally best-effort: unavailable AD metadata or desktop APIs must
|
||||
# never delay or prevent the user's session from opening.
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
CONFIG_PATH=${SGU_WELCOME_CONFIG:-/etc/sgu/welcome-wallpaper.conf}
|
||||
INSTALL_ROOT=${SGU_WELCOME_ROOT:-/usr/local/lib/sgu-welcome-wallpaper}
|
||||
BASE_IMAGE=${SGU_WELCOME_BASE_IMAGE:-${INSTALL_ROOT}/darkblue.jpg}
|
||||
|
||||
if [[ -r $CONFIG_PATH ]]; then
|
||||
# The root-owned file contains only deployment metadata, never credentials.
|
||||
# shellcheck source=/dev/null
|
||||
source "$CONFIG_PATH"
|
||||
fi
|
||||
|
||||
DOMAIN_CONTROLLER=${DOMAIN_CONTROLLER:-}
|
||||
DOMAIN_NAME=${DOMAIN_NAME:-}
|
||||
BASE_DN=${BASE_DN:-}
|
||||
state_root=${XDG_STATE_HOME:-${HOME}/.local/state}
|
||||
wallpaper_root=${XDG_CACHE_HOME:-${HOME}/.cache}/sgu/wallpapers
|
||||
log_path="${state_root}/sgu/welcome-wallpaper.log"
|
||||
|
||||
log_message() {
|
||||
mkdir -p "$(dirname "$log_path")" 2>/dev/null || true
|
||||
printf '%s %s\n' "$(date --iso-8601=seconds 2>/dev/null || date)" "$*" >>"$log_path" 2>/dev/null || true
|
||||
}
|
||||
|
||||
fail_softly() {
|
||||
log_message "ERROR $*"
|
||||
exit 0
|
||||
}
|
||||
|
||||
[[ -r $BASE_IMAGE ]] || fail_softly "Missing base image: $BASE_IMAGE"
|
||||
|
||||
if command -v magick >/dev/null 2>&1; then
|
||||
image_command=(magick)
|
||||
elif command -v convert >/dev/null 2>&1; then
|
||||
image_command=(convert)
|
||||
else
|
||||
fail_softly 'ImageMagick is unavailable.'
|
||||
fi
|
||||
|
||||
raw_user=${USER:-$(id -un 2>/dev/null || printf user)}
|
||||
account_name=${raw_user%@*}
|
||||
account_name=${account_name##*\\}
|
||||
display_name=$(getent passwd "$raw_user" 2>/dev/null | awk -F: 'NR == 1 { split($5,a,","); print a[1] }')
|
||||
[[ -n $display_name ]] || display_name=$account_name
|
||||
|
||||
computer_name=$(hostname -s 2>/dev/null || true)
|
||||
computer_name=${computer_name^^}
|
||||
location=''
|
||||
distinguished_name=''
|
||||
organizational_unit=''
|
||||
|
||||
read_ldif_value() {
|
||||
local attribute=$1
|
||||
local content=$2
|
||||
local line value
|
||||
line=$(printf '%s\n' "$content" | awk -v name="$attribute" '
|
||||
BEGIN { IGNORECASE=1 }
|
||||
index(tolower($0), tolower(name) ":") == 1 { print; exit }
|
||||
')
|
||||
[[ -n $line ]] || return 0
|
||||
if [[ $line == "${attribute}:: "* || ${line,,} == "${attribute,,}:: "* ]]; then
|
||||
value=${line#*:: }
|
||||
printf '%s' "$value" | base64 --decode 2>/dev/null || true
|
||||
else
|
||||
printf '%s' "${line#*: }"
|
||||
fi
|
||||
}
|
||||
|
||||
# SSSD normally obtains a Kerberos ticket during PAM authentication. Use that
|
||||
# ticket for a read-only AD query; never embed a bind password in this helper.
|
||||
if [[ -n $DOMAIN_CONTROLLER && -n $BASE_DN ]] &&
|
||||
command -v ldapsearch >/dev/null 2>&1 &&
|
||||
command -v klist >/dev/null 2>&1 && klist -s; then
|
||||
ldap_server=$DOMAIN_CONTROLLER
|
||||
if [[ -n $DOMAIN_NAME ]] && command -v resolvectl >/dev/null 2>&1; then
|
||||
discovered_server=$(resolvectl query --type=SRV \
|
||||
"_ldap._tcp.dc._msdcs.${DOMAIN_NAME}" 2>/dev/null |
|
||||
awk '/ IN SRV / { for (i=1; i<=NF; i++) if ($i == "SRV") { print $(i+4); exit } }' |
|
||||
sed 's/\.$//' || true)
|
||||
[[ -n $discovered_server ]] && ldap_server=$discovered_server
|
||||
elif [[ -n $DOMAIN_NAME ]] && command -v dig >/dev/null 2>&1; then
|
||||
discovered_server=$(dig +short SRV "_ldap._tcp.dc._msdcs.${DOMAIN_NAME}" 2>/dev/null |
|
||||
awk 'NR == 1 { print $4 }' | sed 's/\.$//' || true)
|
||||
[[ -n $discovered_server ]] && ldap_server=$discovered_server
|
||||
fi
|
||||
ldap_result=$(ldapsearch -LLL -N -o ldif-wrap=no -Y GSSAPI \
|
||||
-H "ldap://${ldap_server}" -b "$BASE_DN" \
|
||||
"(&(objectCategory=computer)(sAMAccountName=${computer_name}\\24))" \
|
||||
location distinguishedName 2>/dev/null || true)
|
||||
location=$(read_ldif_value location "$ldap_result")
|
||||
distinguished_name=$(read_ldif_value distinguishedName "$ldap_result")
|
||||
if [[ $distinguished_name =~ ,OU=([^,]+) ]]; then
|
||||
organizational_unit=${BASH_REMATCH[1]}
|
||||
organizational_unit=${organizational_unit//\\,/,}
|
||||
organizational_unit=${organizational_unit//\\=/=}
|
||||
organizational_unit=${organizational_unit//\\+/+}
|
||||
fi
|
||||
|
||||
# SSSD's GECOS field is not guaranteed to expose AD displayName. Query it
|
||||
# through the same authenticated LDAP session and retain the account-name
|
||||
# fallback when the institutional identifier contains unexpected symbols.
|
||||
if [[ $account_name =~ ^[A-Za-z0-9._-]+$ ]]; then
|
||||
user_result=$(ldapsearch -LLL -N -o ldif-wrap=no -Y GSSAPI \
|
||||
-H "ldap://${ldap_server}" -b "$BASE_DN" \
|
||||
"(&(objectCategory=person)(objectClass=user)(sAMAccountName=${account_name}))" \
|
||||
displayName 2>/dev/null || true)
|
||||
directory_display_name=$(read_ldif_value displayName "$user_result")
|
||||
[[ -n $directory_display_name ]] && display_name=$directory_display_name
|
||||
fi
|
||||
else
|
||||
log_message 'WARN AD metadata query skipped because Kerberos or LDAP session data was unavailable.'
|
||||
fi
|
||||
|
||||
article_for() {
|
||||
local value=${1,,}
|
||||
case "$value" in
|
||||
sala*|aula*|facultad*|unidad*|biblioteca*|oficina*|coordinación*) printf la ;;
|
||||
laboratorio*|centro*|edificio*|campus*|taller*|auditorio*) printf el ;;
|
||||
*) printf '' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
with_article() {
|
||||
local value=$1
|
||||
local article
|
||||
article=$(article_for "$value")
|
||||
if [[ -n $article ]]; then
|
||||
printf '%s %s' "$article" "$value"
|
||||
else
|
||||
printf '%s' "$value"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ -n $location && -n $organizational_unit ]]; then
|
||||
room_phrase=$(with_article "$location")
|
||||
ou_article=$(article_for "$organizational_unit")
|
||||
if [[ $ou_article == el ]]; then
|
||||
ou_phrase="del ${organizational_unit}"
|
||||
elif [[ -n $ou_article ]]; then
|
||||
ou_phrase="de ${ou_article} ${organizational_unit}"
|
||||
else
|
||||
ou_phrase="de ${organizational_unit}"
|
||||
fi
|
||||
location_text="Estás ubicado en ${room_phrase} ${ou_phrase}."
|
||||
elif [[ -n $location ]]; then
|
||||
location_text="Estás ubicado en $(with_article "$location")."
|
||||
elif [[ -n $organizational_unit ]]; then
|
||||
location_text="Estás ubicado en $(with_article "$organizational_unit")."
|
||||
else
|
||||
location_text='Bienvenido al Laboratorio de Cómputo de Ingeniería.'
|
||||
fi
|
||||
|
||||
width=1600
|
||||
height=1000
|
||||
if command -v xrandr >/dev/null 2>&1; then
|
||||
geometry=$(xrandr --current 2>/dev/null | awk '/\*/ { print $1; exit }')
|
||||
if [[ $geometry =~ ^([0-9]+)x([0-9]+)$ ]]; then
|
||||
width=${BASH_REMATCH[1]}
|
||||
height=${BASH_REMATCH[2]}
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$wallpaper_root" "$(dirname "$log_path")" ||
|
||||
fail_softly "Cannot create welcome wallpaper state directories."
|
||||
safe_computer=${computer_name//[^A-Za-z0-9_.-]/_}
|
||||
output_path="${wallpaper_root}/welcome-${safe_computer}.jpg"
|
||||
scale=$(( height * 100 / 1000 ))
|
||||
(( scale > 45 )) || scale=45
|
||||
welcome_size=$(( 34 * scale / 100 ))
|
||||
name_size=$(( 70 * scale / 100 ))
|
||||
location_size=$(( 27 * scale / 100 ))
|
||||
panel_width=$(( width * 76 / 100 ))
|
||||
panel_height=$(( 310 * scale / 100 ))
|
||||
panel_x1=$(( (width - panel_width) / 2 ))
|
||||
panel_y1=$(( height / 2 - panel_height / 2 ))
|
||||
panel_x2=$(( panel_x1 + panel_width ))
|
||||
panel_y2=$(( panel_y1 + panel_height ))
|
||||
|
||||
sans_font='DejaVu-Sans'
|
||||
serif_font='DejaVu-Serif'
|
||||
if [[ -r ${INSTALL_ROOT}/fonts/IndivisaTextSans-Bold.otf ]]; then
|
||||
sans_font="${INSTALL_ROOT}/fonts/IndivisaTextSans-Bold.otf"
|
||||
fi
|
||||
if [[ -r ${INSTALL_ROOT}/fonts/IndivisaTextSerif-BoldItalic.otf ]]; then
|
||||
serif_font="${INSTALL_ROOT}/fonts/IndivisaTextSerif-BoldItalic.otf"
|
||||
fi
|
||||
if [[ $sans_font == DejaVu-Sans ]] && command -v fc-list >/dev/null 2>&1; then
|
||||
if fc-list : family | grep -Fqi 'Indivisa Text Sans'; then
|
||||
sans_font='Indivisa Text Sans'
|
||||
elif fc-list : family | grep -Fqi 'Indivisa Text'; then
|
||||
sans_font='Indivisa Text'
|
||||
fi
|
||||
fi
|
||||
if [[ $serif_font == DejaVu-Serif ]] && command -v fc-list >/dev/null 2>&1; then
|
||||
if fc-list : family | grep -Fqi 'Indivisa Text Serif'; then
|
||||
serif_font='Indivisa Text Serif'
|
||||
elif fc-list : family | grep -Fqi 'Indivisa Serif'; then
|
||||
serif_font='Indivisa Serif'
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! "${image_command[@]}" "$BASE_IMAGE" \
|
||||
-resize "${width}x${height}^" -gravity center -extent "${width}x${height}" \
|
||||
-fill 'rgba(0,13,58,0.30)' -draw "rectangle ${panel_x1},${panel_y1} ${panel_x2},${panel_y2}" \
|
||||
-gravity center \
|
||||
-font "$sans_font" -weight 700 -style Normal -pointsize "$welcome_size" \
|
||||
-fill '#D3E2FF' -stroke 'rgba(0,0,0,0.48)' -strokewidth 1 \
|
||||
-annotate "+0-$(( 92 * scale / 100 ))" 'Bienvenido,' \
|
||||
-font "$serif_font" -weight 700 -style Italic -pointsize "$name_size" \
|
||||
-fill white -annotate "+0-$(( 22 * scale / 100 ))" "$display_name" \
|
||||
-font "$sans_font" -weight 400 -style Normal -pointsize "$location_size" \
|
||||
-fill '#D3E2FF' -annotate "+0+$(( 88 * scale / 100 ))" "$location_text" \
|
||||
-quality 94 "$output_path" 2>>"$log_path"; then
|
||||
fail_softly 'ImageMagick could not render the welcome wallpaper.'
|
||||
fi
|
||||
|
||||
applied=false
|
||||
if command -v gsettings >/dev/null 2>&1; then
|
||||
if gsettings list-schemas 2>/dev/null | grep -Fxq 'org.cinnamon.desktop.background'; then
|
||||
gsettings set org.cinnamon.desktop.background picture-uri "file://${output_path}" >/dev/null 2>&1 || true
|
||||
gsettings set org.cinnamon.desktop.background picture-options zoom >/dev/null 2>&1 || true
|
||||
applied=true
|
||||
fi
|
||||
if gsettings list-schemas 2>/dev/null | grep -Fxq 'org.gnome.desktop.background'; then
|
||||
gsettings set org.gnome.desktop.background picture-uri "file://${output_path}" >/dev/null 2>&1 || true
|
||||
gsettings set org.gnome.desktop.background picture-uri-dark "file://${output_path}" >/dev/null 2>&1 || true
|
||||
gsettings set org.gnome.desktop.background picture-options zoom >/dev/null 2>&1 || true
|
||||
applied=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $applied == false ]] && command -v xfconf-query >/dev/null 2>&1; then
|
||||
while IFS= read -r property; do
|
||||
xfconf-query -c xfce4-desktop -p "$property" -s "$output_path" >/dev/null 2>&1 || true
|
||||
applied=true
|
||||
done < <(xfconf-query -c xfce4-desktop -l 2>/dev/null | grep '/last-image$' || true)
|
||||
fi
|
||||
|
||||
if [[ $applied == true ]]; then
|
||||
log_message "OK computer=${computer_name}; location=$([[ -n $location ]] && printf true || printf false); ou=$([[ -n $organizational_unit ]] && printf true || printf false); output=${output_path}"
|
||||
else
|
||||
log_message 'WARN Wallpaper rendered, but no supported desktop background API was found.'
|
||||
fi
|
||||
exit 0
|
||||
Reference in New Issue
Block a user