You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ublinux-init/ublinux/rc.pamsession.d/04-user-locale

127 lines
6.9 KiB

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/bash
#
# Author: Dmitry Razumov <asmeron@ublinux.com>
# Copyright (c) 2021-2025 UBLinux <support@ublinux.com>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
ENABLED=yes
[[ ${ENABLED} == yes ]] || exit 0
DEFAULT_CONF=$(< /usr/lib/ublinux/default)
[[ ${DEFAULT_CONF} =~ (^|$'\n')[[:blank:]]*SYSCONF=([^$|$'\n']+)[[:blank:]]*($|$'\n') ]] && SYSCONF=${BASH_REMATCH[2]} || SYSCONF="/etc/sysconf"
SOURCE=${SYSCONF}/config; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=${SYSCONF}/users; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
# Extended pattern matching: https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching
shopt -s extglob
## Назначение модулей:
## account подтвердить личность, проверив учетные данные, такие как пароль, ключ, токен и другие
## auth проверить авторизацию для таких действий, как разрешения, ограничения и т. д.
## password обновить учетные данные
## session распределять ресурсы во время входа в систему, такие как личные данные, лимиты и другие.
##
## Выполнение из /etc/pam.d/system-login
## Тип модуля: session
## Глобальные переменные:
## PAM_RHOST Удалённый хост
## PAM_RUSER Удалённый пользователь
## PAM_SERVICE Сервис выполняющий вход /etc/pam.d/service_name
## PAM_TTY Консоль, может быть как "/dev/tty2" так и ":0"
## PAM_USER Текущий пользователь
## PAM_TYPE Тип сессии, возможные значения: account, auth, password, open_session, close_session
##
## PAM_RHOST= PAM_RUSER= PAM_SERVICE=login PAM_TTY=/dev/tty2 PAM_USER=superadmin PAM_TYPE=open_session
## PAM_RHOST= PAM_RUSER= PAM_SERVICE=login PAM_TTY=/dev/tty2 PAM_USER=superadmin PAM_TYPE=close_session
## PAM_RHOST= PAM_RUSER= PAM_SERVICE=lightdm-autologin PAM_TTY=:0 PAM_USER=superadmin PAM_TYPE=open_session
## PAM_RHOST= PAM_RUSER= PAM_SERVICE=systemd-user PAM_TTY= PAM_USER=lightdm PAM_TYPE=open_session
## PAM_RHOST= PAM_RUSER= PAM_SERVICE=systemd-user PAM_TTY= PAM_USER=user-2 PAM_TYPE=open_session
## PAM_RHOST= PAM_RUSER= PAM_SERVICE=lightdm PAM_TTY=:0 PAM_USER=user-2 PAM_TYPE=open_session
## PAM_RHOST=1.2.3.4 PAM_RUSER= PAM_SERVICE=sshd PAM_TTY=ssh PAM_USER=user-2 PAM_TYPE=open_session
if [[ ${PAM_TYPE} == "open_session" && -n ${PAM_USER} ]]; then
# Выполнение функции вызвано используя PAM, получаем имя пользователя вызвавшего PAM, будем пременять только для пользователя
SELECT_USERNAME="${PAM_USER}"
fi
declare -A USERADD
# По сокращённому имени, вернуть полное имя, пример 'get_fullname_lang en' : en_US.UTF-8
get_fullname_lang(){
local NEWLANG=$1
local SUPPORTED=$(< ${ROOTFS}/usr/share/i18n/SUPPORTED)
# Из за того, что нет en_EN, а через груб прилетает просто en, то выбираем en_US.UTF-8
[[ ${NEWLANG} == "en" ]] && NEWLANG="en_US.UTF-8"
if [[ ${SUPPORTED} =~ ($'\n'|^)"${NEWLANG} ".*($'\n'|$) ]]; then
echo "${NEWLANG}"
elif [[ ${SUPPORTED} =~ ($'\n'|^)"${NEWLANG,,}_${NEWLANG^^}.UTF-8 ".*($'\n'|$) ]]; then
echo "${NEWLANG,,}_${NEWLANG^^}.UTF-8"
elif [[ ${SUPPORTED} =~ ($'\n'|^)"${NEWLANG,,}_${NEWLANG^^} ".*($'\n'|$) ]]; then
echo "${NEWLANG,,}_${NEWLANG^^}"
elif [[ ${SUPPORTED} =~ ($'\n'|^)"${NEWLANG}.UTF-8 ".*($'\n'|$) ]]; then
echo "${NEWLANG}.UTF-8"
elif [[ ${SUPPORTED} =~ ($'\n'|^)("${NEWLANG,,}_"[:A-Z:]+".UTF-8")" ".*($'\n'|$) ]]; then
echo "${BASH_REMATCH[2]}"
elif [[ ${SUPPORTED} =~ ($'\n'|^)("${NEWLANG,,}_"[:A-Z:]+)" ".*($'\n'|$) ]]; then
echo "${BASH_REMATCH[2]}"
else
echo "en_US.UTF-8"
fi
}
## При после авторизации пользователя проверяем праметр в USERADD[*] --land у текужего пользователя, если задан,
## то под указанную локал создаём файл "${HOME}/.config/locale.conf"
exec_01_user_locale(){
[[ -n $1 ]] && SELECT_USERNAME="$1"
if [[ -n ${SELECT_USERNAME} && -n ${USERADD[${SELECT_USERNAME}]} ]]; then
local SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUP SELECT_OPTIONAL SELECT_PASSWORD NULL
local LANG=
IFS=: read -r SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS SELECT_OPTIONAL SELECT_PASSWORD NULL <<< "${USERADD[${SELECT_USERNAME}]}"
[[ ${SELECT_OPTIONAL} =~ ("--lang ")([^' ']+)(' '|$) ]] && LANG="${BASH_REMATCH[2]}"
if [[ ${LANG} == "system" ]]; then
rm -f ${HOME}/.config/locale.conf
elif [[ -n ${LANG} ]]; then
LANG=$(get_fullname_lang ${LANG})
# Проверка выбранного языка в системе, и если не совпадает, то устанавливаем
local LOCALE_FILE=$(< /etc/locale.conf)
LOCALEDEF_LIST="$(localedef --list-archive)"
LOW_LOCALEDEF_LIST="${LOCALEDEF_LIST,,}"
LOW_LANG=${LANG,,}
if [[ ${LOCALE_FILE} =~ (^|$'\n')[[:blank:]]*LANG=([^$|$'\n']+)[[:blank:]]*($|$'\n') && ! "${BASH_REMATCH[2]}" == "${LANG}" ]] \
&& [[ ${LOW_LOCALEDEF_LIST//-/} =~ (^|$'\n')"${LOW_LANG//-/}"($|$'\n') ]]; then
# Устанавливаем локаль
env LANG="${LANG}" LANGUAGE="${LANG}" LC_CTYPE="${LANG}" LC_NUMERIC="${LANG}" \
LC_TIME="${LANG}" LC_COLLATE="${LANG}" LC_MONETARY="${LANG}" LC_MESSAGES="${LANG}" LC_PAPER="${LANG}" \
LC_NAME="${LANG}" LC_ADDRESS="${LANG}" LC_TELEPHONE="${LANG}" LC_MEASUREMENT="${LANG}" \
LC_IDENTIFICATION="${LANG}" locale > ${HOME}/.config/locale.conf 2>/dev/null
chown ${SELECT_USERNAME}:${SELECT_USERNAME} "${HOME}/.config/locale.conf" 2>/dev/null
fi
fi
fi
}
################
##### MAIN #####
################
# Если файл подключен как ресурс с функциями, то выйти
return 0 2>/dev/null && return 0
if [[ -z $@ ]]; then
while read -r FUNCTION; do
$"${FUNCTION##* }"
done < <(declare -F | grep "declare -f exec_")
else
FUNCTION=
while [[ $# -gt 0 ]]; do
#[[ -z ${1} ]] || { declare -f "${1}" &>/dev/null && FUNCTION+="; ${1}" || FUNCTION+=" '${1}'"; }
# Что-бы передавать пустые параметры как аргументы, нужно для соблюдения очередности и кол-ва, отключил [[ -z ${1} ]] ||
declare -f "${1}" &>/dev/null && FUNCTION+="; ${1}" || FUNCTION+=" '${1}'"
shift
done
eval ${FUNCTION#*; }
fi
true