Improve domain enrollment and desktop personalization
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
set -Eeuo pipefail
|
||||
IFS=$'\n\t'
|
||||
SCRIPT_DIRECTORY=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
DOMAIN_NAME='lci.lasalle.mx'
|
||||
DOMAIN_CONTROLLER=''
|
||||
@@ -18,6 +19,7 @@ DOMAIN_ADDRESS=''
|
||||
COMPUTER_NAME=''
|
||||
ALLOW_GROUP=''
|
||||
ENABLE_SSH=false
|
||||
ENABLE_HYPERV_ENHANCED_SESSION=false
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
@@ -37,6 +39,8 @@ Options:
|
||||
--domain-address CIDR Static IPv4 address for --domain-interface, e.g. 192.168.50.12/24.
|
||||
--allow-group GROUP Restrict Linux sign-in to this AD group after joining.
|
||||
--enable-ssh Install, enable, and (when active) permit OpenSSH in the local firewall.
|
||||
--enable-hyperv-enhanced-session
|
||||
Install and configure XRDP over Hyper-V sockets for VMConnect.
|
||||
--help Show this help.
|
||||
|
||||
Network safety:
|
||||
@@ -70,6 +74,7 @@ while (($#)); do
|
||||
--domain-address) DOMAIN_ADDRESS=${2:?Missing value for --domain-address}; shift 2 ;;
|
||||
--allow-group) ALLOW_GROUP=${2:?Missing value for --allow-group}; shift 2 ;;
|
||||
--enable-ssh) ENABLE_SSH=true; shift ;;
|
||||
--enable-hyperv-enhanced-session) ENABLE_HYPERV_ENHANCED_SESSION=true; shift ;;
|
||||
--help|-h) usage; exit 0 ;;
|
||||
*) fail "Unknown argument: $1. Use --help for usage." ;;
|
||||
esac
|
||||
@@ -100,6 +105,19 @@ install_prerequisites() {
|
||||
if [[ $ENABLE_SSH == true ]]; then
|
||||
packages+=(openssh-server)
|
||||
fi
|
||||
if [[ $ENABLE_HYPERV_ENHANCED_SESSION == true ]]; then
|
||||
packages+=(xrdp xorgxrdp ssl-cert)
|
||||
|
||||
# XRDP's Debian post-install script cannot replace a dangling
|
||||
# certificate symlink left by an interrupted/older installation.
|
||||
# Remove only dangling links so dpkg can recreate them safely.
|
||||
local xrdp_link
|
||||
for xrdp_link in /etc/xrdp/cert.pem /etc/xrdp/key.pem; do
|
||||
if [[ -L $xrdp_link && ! -e $xrdp_link ]]; then
|
||||
rm -f -- "$xrdp_link"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y "${packages[@]}"
|
||||
@@ -121,7 +139,7 @@ install_prerequisites() {
|
||||
}
|
||||
|
||||
configure_private_ad_interface() {
|
||||
[[ -n $DOMAIN_INTERFACE ]] || return
|
||||
[[ -n $DOMAIN_INTERFACE ]] || return 0
|
||||
need_command nmcli
|
||||
ip link show "$DOMAIN_INTERFACE" >/dev/null 2>&1 || \
|
||||
fail "Network interface does not exist: $DOMAIN_INTERFACE"
|
||||
@@ -148,7 +166,7 @@ configure_private_ad_interface() {
|
||||
}
|
||||
|
||||
enable_sssd_dyndns() {
|
||||
[[ -n $DOMAIN_INTERFACE ]] || return
|
||||
[[ -n $DOMAIN_INTERFACE ]] || return 0
|
||||
local configuration_directory='/etc/sssd/conf.d'
|
||||
local configuration_path="${configuration_directory}/90-sgu-dyndns.conf"
|
||||
local temporary_path
|
||||
@@ -165,8 +183,76 @@ enable_sssd_dyndns() {
|
||||
rm -f "$temporary_path"
|
||||
}
|
||||
|
||||
enable_short_domain_login_names() {
|
||||
local configuration_path='/etc/sssd/sssd.conf'
|
||||
[[ -f $configuration_path ]] || return 0
|
||||
|
||||
# Institutional account names (AL/AD/DO) are unique in this lab and are
|
||||
# the identifiers users already know. Keep UPN logins valid while also
|
||||
# allowing the short form in PAM applications such as XRDP/VMConnect.
|
||||
if grep -Eq '^[[:space:]]*use_fully_qualified_names[[:space:]]*=' "$configuration_path"; then
|
||||
sed -Ei 's/^[[:space:]]*use_fully_qualified_names[[:space:]]*=.*/use_fully_qualified_names = False/' \
|
||||
"$configuration_path"
|
||||
else
|
||||
sed -Ei "/^\[domain\/${DOMAIN_NAME//./\\.}\]$/a use_fully_qualified_names = False" \
|
||||
"$configuration_path"
|
||||
fi
|
||||
chmod 600 "$configuration_path"
|
||||
}
|
||||
|
||||
configure_sssd_responder_mode() {
|
||||
local configuration_path='/etc/sssd/sssd.conf'
|
||||
[[ -f $configuration_path ]] || return 0
|
||||
|
||||
# realmd writes a persistent responder list, while recent Debian-family
|
||||
# packages can enable the same NSS/PAM responders through systemd sockets.
|
||||
# Running both modes makes the sockets fail at boot and can leave graphical
|
||||
# PAM clients unable to contact SSSD reliably. Keep realmd's persistent
|
||||
# responders and disable only the duplicate socket units when they exist.
|
||||
local unit
|
||||
for unit in sssd-nss.socket sssd-pam.socket sssd-pam-priv.socket; do
|
||||
if systemctl list-unit-files "$unit" --no-legend 2>/dev/null | grep -q "^${unit}"; then
|
||||
systemctl disable --now "$unit" >/dev/null 2>&1 || true
|
||||
systemctl reset-failed "$unit" >/dev/null 2>&1 || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
configure_graphical_domain_login() {
|
||||
local sssd_configuration_directory='/etc/sssd/conf.d'
|
||||
local temporary_sssd_configuration
|
||||
local interactive_services='+lightdm,+cinnamon-screensaver'
|
||||
if [[ $ENABLE_HYPERV_ENHANCED_SESSION == true ]]; then
|
||||
interactive_services+=',+xrdp-sesman'
|
||||
fi
|
||||
|
||||
temporary_sssd_configuration=$(mktemp)
|
||||
printf '%s\n' \
|
||||
"[domain/${DOMAIN_NAME,,}]" \
|
||||
"ad_gpo_map_interactive = ${interactive_services}" >"$temporary_sssd_configuration"
|
||||
install -d -o root -g root -m 700 "$sssd_configuration_directory"
|
||||
install -o root -g root -m 600 "$temporary_sssd_configuration" \
|
||||
"${sssd_configuration_directory}/91-sgu-graphical-login.conf"
|
||||
rm -f "$temporary_sssd_configuration"
|
||||
rm -f "${sssd_configuration_directory}/91-sgu-xrdp.conf"
|
||||
|
||||
# Slick Greeter normally shows only the last/local account tile. Expose a
|
||||
# manual user-name prompt so a first-time AD user can enter AL/AD/DO IDs.
|
||||
if [[ -d /etc/lightdm/lightdm.conf.d ]]; then
|
||||
local temporary_lightdm_configuration
|
||||
temporary_lightdm_configuration=$(mktemp)
|
||||
printf '%s\n' \
|
||||
'[Seat:*]' \
|
||||
'greeter-show-manual-login=true' \
|
||||
'greeter-hide-users=false' >"$temporary_lightdm_configuration"
|
||||
install -o root -g root -m 644 "$temporary_lightdm_configuration" \
|
||||
'/etc/lightdm/lightdm.conf.d/91-sgu-domain-login.conf'
|
||||
rm -f "$temporary_lightdm_configuration"
|
||||
fi
|
||||
}
|
||||
|
||||
enable_ssh() {
|
||||
[[ $ENABLE_SSH == true ]] || return
|
||||
[[ $ENABLE_SSH == true ]] || return 0
|
||||
local service_name='sshd'
|
||||
if systemctl list-unit-files ssh.service >/dev/null 2>&1; then
|
||||
service_name='ssh'
|
||||
@@ -180,6 +266,137 @@ enable_ssh() {
|
||||
fi
|
||||
}
|
||||
|
||||
configure_hyperv_enhanced_session() {
|
||||
[[ $ENABLE_HYPERV_ENHANCED_SESSION == true ]] || return 0
|
||||
|
||||
command -v xrdp >/dev/null 2>&1 || {
|
||||
printf 'WARNING: XRDP is unavailable; Hyper-V Enhanced Session was not enabled.\n' >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
local xrdp_configuration='/etc/xrdp/xrdp.ini'
|
||||
[[ -f $xrdp_configuration ]] || {
|
||||
printf 'WARNING: %s is missing; Hyper-V Enhanced Session was not enabled.\n' "$xrdp_configuration" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
# VMConnect uses AF_VSOCK rather than TCP. Only change the first occurrence,
|
||||
# which belongs to [Globals]; later port entries describe XRDP backends.
|
||||
sed -Ei '0,/^port=.*/s|^port=.*|port=vsock://-1:3389|' "$xrdp_configuration"
|
||||
if grep -q '^use_vsock=' "$xrdp_configuration"; then
|
||||
sed -Ei '0,/^use_vsock=.*/s|^use_vsock=.*|use_vsock=true|' "$xrdp_configuration"
|
||||
else
|
||||
sed -Ei '/^port=vsock:\/\/-1:3389/a use_vsock=true' "$xrdp_configuration"
|
||||
fi
|
||||
sed -Ei '0,/^security_layer=.*/s|^security_layer=.*|security_layer=rdp|' "$xrdp_configuration"
|
||||
sed -Ei '0,/^crypt_level=.*/s|^crypt_level=.*|crypt_level=none|' "$xrdp_configuration"
|
||||
|
||||
# A clean Ubuntu installation can contain XRDP symlinks before the
|
||||
# snake-oil certificate has actually been generated.
|
||||
if [[ ! -s /etc/ssl/certs/ssl-cert-snakeoil.pem || \
|
||||
! -s /etc/ssl/private/ssl-cert-snakeoil.key ]]; then
|
||||
if command -v make-ssl-cert >/dev/null 2>&1; then
|
||||
make-ssl-cert generate-default-snakeoil --force-overwrite
|
||||
else
|
||||
printf 'WARNING: make-ssl-cert is unavailable; XRDP certificate generation was skipped.\n' >&2
|
||||
fi
|
||||
fi
|
||||
usermod -aG ssl-cert xrdp
|
||||
|
||||
# xrdp-sesman (root) and xrdp (the xrdp account) share /run/xrdp. Give the
|
||||
# directory the shared group/mode so the second service can create its PID
|
||||
# file instead of timing out while VMConnect remains at "Connecting".
|
||||
local override_directory='/etc/systemd/system/xrdp-sesman.service.d'
|
||||
local temporary_override
|
||||
temporary_override=$(mktemp)
|
||||
printf '%s\n' \
|
||||
'[Service]' \
|
||||
'Group=xrdp' \
|
||||
'RuntimeDirectory=xrdp' \
|
||||
'RuntimeDirectoryMode=0775' >"$temporary_override"
|
||||
install -d -o root -g root -m 755 "$override_directory"
|
||||
install -o root -g root -m 644 "$temporary_override" \
|
||||
"${override_directory}/sgu-runtime.conf"
|
||||
rm -f "$temporary_override"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable xrdp xrdp-sesman
|
||||
systemctl restart xrdp
|
||||
systemctl is-active --quiet xrdp
|
||||
systemctl is-active --quiet xrdp-sesman
|
||||
}
|
||||
|
||||
install_welcome_wallpaper() {
|
||||
local source_directory="${SCRIPT_DIRECTORY}/welcome-wallpaper"
|
||||
local source_script="${source_directory}/Set-SguWelcomeWallpaper.sh"
|
||||
local source_image="${source_directory}/darkblue.jpg"
|
||||
local install_directory='/usr/local/lib/sgu-welcome-wallpaper'
|
||||
local configuration_directory='/etc/sgu'
|
||||
local autostart_directory='/etc/xdg/autostart'
|
||||
|
||||
if [[ ! -r $source_script || ! -r $source_image ]]; then
|
||||
printf 'WARNING: Welcome wallpaper assets are absent; domain enrollment will continue without desktop branding.\n' >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Desktop branding is optional and must never invalidate an otherwise valid
|
||||
# domain join. Install its distribution-specific dependencies best-effort.
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
if ! apt-get install -y imagemagick ldap-utils fontconfig; then
|
||||
printf 'WARNING: Could not install welcome wallpaper dependencies; enrollment remains valid.\n' >&2
|
||||
return 0
|
||||
fi
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
if ! dnf install -y ImageMagick openldap-clients fontconfig; then
|
||||
printf 'WARNING: Could not install welcome wallpaper dependencies; enrollment remains valid.\n' >&2
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
install -d -o root -g root -m 755 "$install_directory" "$configuration_directory" "$autostart_directory"
|
||||
install -o root -g root -m 755 "$source_script" "${install_directory}/Set-SguWelcomeWallpaper.sh"
|
||||
install -o root -g root -m 644 "$source_image" "${install_directory}/darkblue.jpg"
|
||||
if compgen -G "${source_directory}/fonts/*.[ot]tf" >/dev/null; then
|
||||
install -d -o root -g root -m 755 "${install_directory}/fonts"
|
||||
install -o root -g root -m 644 "${source_directory}"/fonts/*.[ot]tf "${install_directory}/fonts/"
|
||||
fi
|
||||
|
||||
local base_dn=''
|
||||
local component
|
||||
IFS='.' read -ra domain_components <<<"$DOMAIN_NAME"
|
||||
for component in "${domain_components[@]}"; do
|
||||
if [[ -n $base_dn ]]; then
|
||||
base_dn+=','
|
||||
fi
|
||||
base_dn+="DC=${component}"
|
||||
done
|
||||
|
||||
local temporary_configuration
|
||||
temporary_configuration=$(mktemp)
|
||||
printf 'DOMAIN_CONTROLLER=%q\nDOMAIN_NAME=%q\nBASE_DN=%q\n' \
|
||||
"$DOMAIN_CONTROLLER" "$DOMAIN_NAME" "$base_dn" >"$temporary_configuration"
|
||||
install -o root -g root -m 644 "$temporary_configuration" \
|
||||
"${configuration_directory}/welcome-wallpaper.conf"
|
||||
rm -f "$temporary_configuration"
|
||||
|
||||
local temporary_autostart
|
||||
temporary_autostart=$(mktemp)
|
||||
cat >"$temporary_autostart" <<'EOF'
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=SGU welcome wallpaper
|
||||
Comment=Generate a personalized La Salle laboratory welcome wallpaper
|
||||
Exec=/usr/local/lib/sgu-welcome-wallpaper/Set-SguWelcomeWallpaper.sh
|
||||
Terminal=false
|
||||
NoDisplay=true
|
||||
X-GNOME-Autostart-enabled=true
|
||||
X-Cinnamon-Autostart-enabled=true
|
||||
EOF
|
||||
install -o root -g root -m 644 "$temporary_autostart" \
|
||||
"${autostart_directory}/sgu-welcome-wallpaper.desktop"
|
||||
rm -f "$temporary_autostart"
|
||||
}
|
||||
|
||||
verify_domain_connectivity() {
|
||||
need_command getent
|
||||
getent ahostsv4 "$DOMAIN_CONTROLLER" >/dev/null || \
|
||||
@@ -212,6 +429,9 @@ else
|
||||
fi
|
||||
|
||||
enable_sssd_dyndns
|
||||
enable_short_domain_login_names
|
||||
configure_sssd_responder_mode
|
||||
configure_graphical_domain_login
|
||||
systemctl enable --now sssd
|
||||
sssctl config-check
|
||||
systemctl restart sssd
|
||||
@@ -224,10 +444,13 @@ if [[ -n $ALLOW_GROUP ]]; then
|
||||
fi
|
||||
|
||||
enable_ssh
|
||||
configure_hyperv_enhanced_session
|
||||
install_welcome_wallpaper
|
||||
|
||||
printf '\nLinux enrollment completed.\n'
|
||||
printf ' Host: %s\n' "$HOST_FQDN"
|
||||
printf ' Domain: %s\n' "$DOMAIN_NAME"
|
||||
printf ' OU: %s\n' "$COMPUTER_OU"
|
||||
printf ' Login format: %%U@%s\n' "$DOMAIN_NAME"
|
||||
printf ' Welcome wallpaper: generated at each graphical sign-in when the desktop is supported.\n'
|
||||
realm list
|
||||
|
||||
Reference in New Issue
Block a user