#!/usr/bin/bash # # Author: Dmitry Razumov # Copyright (c) 2021-2025 UBLinux # # 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