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.preinit/10-accounts

804 lines
53 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/env bash
#
# Initial script for UBLinux
# This script are launching before starting init from initrd script
# Current dir allways must be set to root (/)
# All system path must be relative, except initrd dirs
ENABLED=yes
[[ ${ENABLED} == "yes" ]] || exit 0
DEBUGMODE=no
PATH=.:/:/usr/bin:/usr/local/bin:/usr/local/sbin
CMD_CHROOT= ; [[ -d /usr/lib/ublinux ]] || { [[ -d /sysroot ]] && ROOTFS="/sysroot" || ROOTFS="."; CMD_CHROOT="chroot ${ROOTFS}"; }
SOURCE=${ROOTFS}/usr/lib/ublinux/functions; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null || exit 0
SOURCE=${ROOTFS}/usr/lib/ublinux/default; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null || exit 0
debug_mode "$0" "$@"
SYSCONF="${ROOTFS}${SYSCONF}"
SOURCE=${SYSCONF}/config; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=${SYSCONF}/users; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=${SYSCONF}/system; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=${SYSCONF}/locale; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
FILE_ROOT_USERS="${SYSCONF}/.users_credential"
SOURCE=${FILE_ROOT_USERS}; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
shopt -s extglob
FILE_PASSWD="${ROOTFS}/etc/passwd"
FILE_SHADOW="${ROOTFS}/etc/shadow"
FILE_GROUP="${ROOTFS}/etc/group"
FILE_GSHADOW="${ROOTFS}/etc/gshadow"
FILE_DEFAULT_USERADD="${ROOTFS}/etc/default/useradd"
DATA_FILE_DEFAULT_USERADD=$(cat ${FILE_DEFAULT_USERADD})
DEFAULT_HOME_USER="/home"
NAME_REGEX="^[a-z_][-a-z0-9_]*\$"
# Задать пароль пользователю
# $1 # Имя пользователя
# $2 # Зашифрованный пароля, если не указан, то пароль '!*' запрет авторизации
#set_passwd(){
# USER_NAME="${1}"
# USER_PASS="${2}"
# [[ ${USER_NAME} != "" ]] || return 1
# [[ ${USER_PASS} != "" ]] || USER_PASS='!*'
# if [[ -x ${ROOTFS}/usr/bin/chpasswd ]]; then
# echo "${USER_NAME}:${USER_PASS}" | ${CMD_CHROOT} /usr/bin/chpasswd --encrypted
# else
# ESC_USER_PASS=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${USER_PASS}")
# EPOCH_DAY=$(( $(${CMD_CHROOT} date +%s)/(60*60*24) )) # (60*60*24)=18400 second on day
# USER_FROM_SHADOW=$(grep "^${USER_NAME}:" "${FILE_SHADOW}")
# if [[ -z ${USER_FROM_SHADOW} ]]; then
# echo "${USER_NAME}:${USER_PASS}:${EPOCH_DAY}:0:99999:7:::" >> "${FILE_SHADOW}"
# elif [[ ! ${USER_FROM_SHADOW} =~ ^"${USER_NAME}:${USER_PASS}:" ]]; then
# sed -E "s/^${USER_NAME}:[^:]+:[0-9]+:/${USER_NAME}:${ESC_USER_PASS}:${EPOCH_DAY}:/" -i "${FILE_SHADOW}"
# sed -E "s/${USER_NAME}:[!]*:/${USER_NAME}:\!\*:/" -i "${FILE_SHADOW}"
# #sed /^${USER_NAME}:/d -i "${FILE_SHADOW}"
# #echo "${USER_NAME}:${USER_PASS}:${EPOCH_DAY}:0:99999:7:::" >> "${FILE_SHADOW}"
# fi
# fi
#}
# Задать пароль группе
# $1 # Имя группы
# $2 # Зашифрованный пароля, если не указан, то пароль '!*' запрет авторизации
#set_gpasswd(){
# GROUP_NAME="${1}"
# GROUP_PASS="${2}"
# [[ ${GROUP_NAME} != "" ]] || return 1
# [[ ${GROUP_PASS} != "" ]] || GROUP_PASS="!*"
# if [[ -x ${ROOTFS}/usr/bin/chgpasswd ]]; then
# echo "${GROUP_NAME}:${GROUP_PASS}" | ${CMD_CHROOT} /usr/bin/chgpasswd --encrypted
# else
# ESC_GROUP_PASS=$(sed 's/[^a-zA-Z0-9=",_@#%&<> -]/\\&/g' <<< "${GROUP_PASS}")
# GROUP_FROM_SHADOW=$(grep "^${GROUP_NAME}:" "${FILE_GSHADOW}")
# if [[ -z ${GROUP_FROM_SHADOW} ]]; then
# echo "${GROUP_NAME}:${GROUP_PASS}::" >> "${FILE_GSHADOW}"
# elif [[ ! ${GROUP_FROM_SHADOW} =~ ^"${GROUP_NAME}:${GROUP_PASS}:" ]]; then
# sed -E "s/^${GROUP_NAME}:[^:]*:/${GROUP_NAME}:${ESC_GROUP_PASS}:/" -i "${FILE_GSHADOW}"
# fi
# fi
#}
# Создать домашний каталог и копировать /etc/skel в домашний каталог пользователя
# $1 # Имя пользователя
# $2 # Если указано, то принудительно копировать /etc/skel в домашний каталог пользователя
create_home(){
local SELECT_USERNAME="${1}"
local SELECT_FORCESKEL="${2}"
local SELECT_GROUP="$(${CMD_CHROOT} /usr/bin/id -g ${SELECT_USERNAME})"
local SELECT_HOME="$(${CMD_CHROOT} getent passwd ${SELECT_USERNAME} | cut -d: -f6)"
[[ -n ${SELECT_USERNAME} && -n ${SELECT_GROUP} && -n ${SELECT_HOME} ]] || return 1
if [[ -d "${ROOTFS}${SELECT_HOME}" ]]; then
if [[ -n ${SELECT_FORCESKEL} ]]; then
cp -Taf ${ROOTFS}/etc/skel "${ROOTFS}${SELECT_HOME}"
${CMD_CHROOT} bash -c "cd /etc/skel && find . -exec chown -fh ${SELECT_USERNAME}:${SELECT_GROUP} ${SELECT_HOME}/{} \;"
${CMD_CHROOT} /usr/bin/chown -fh ${SELECT_USERNAME}:${SELECT_GROUP} "${SELECT_HOME}"
${CMD_CHROOT} /usr/bin/chmod -f u+rw,g-rwx,o-rwx "${SELECT_HOME}"
fi
else
${CMD_CHROOT} install -dm700 -o ${SELECT_USERNAME} -g ${SELECT_GROUP} "${SELECT_HOME}"
cp -Taf ${ROOTFS}/etc/skel "${ROOTFS}${SELECT_HOME}"
${CMD_CHROOT} /usr/bin/chown -fhRP ${SELECT_USERNAME}:${SELECT_GROUP} "${SELECT_HOME}"
${CMD_CHROOT} /usr/bin/chmod -f u+rw,g-rwx,o-rwx "${SELECT_HOME}"
fi
#rsync -rlpt --ignore-existing etc/skel/ "${ROOTFS}${DEFAULT_HOME_USER}/${SELECT_USERNAME}"
}
# Задаём пароль root пользователю
exec_01_defaultrootpasswd(){
#echo "exec_01_defaultrootpasswd"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ -n ${DEFAULTROOTPASSWD} && ! ${DEFAULTROOTPASSWD,,} == @(no|none|disable) ]]; then
# Добавить параметр в ${FILE_ROOT_USERS}=.users_credential и удалить параметр DEFAULTROOTPASSWD из '/etc/ublinux/users
if [[ -f ${FILE_ROOT_USERS} ]]; then
sed "/DEFAULTROOTPASSWD=/d" -i "${FILE_ROOT_USERS}"
echo "DEFAULTROOTPASSWD='${DEFAULTROOTPASSWD}'" >> ${FILE_ROOT_USERS}
fi
[[ -f "${SYSCONF}/users" ]] && sed "/DEFAULTROOTPASSWD=/d" -i "${SYSCONF}/users"
DEFAULTROOTPASSWD=$(return_hash_password hash ${HASHPASSWD} ${DEFAULTROOTPASSWD})
#set_passwd root "${DEFAULTROOTPASSWD}"
user_add "root:+:+:+:${DEFAULTROOTPASSWD}:+:+:+:+:+:+:+:+"
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
[[ -f ${FILE_ROOT_USERS} ]] && sed "/DEFAULTROOTPASSWD=/d" -i "${FILE_ROOT_USERS}"
[[ -f "${SYSCONF}/users" ]] && sed "/DEFAULTROOTPASSWD=/d" -i "${SYSCONF}/users"
fi
}
# Задаём пароль по умолчанию пользователю
exec_02_defaultpasswd(){
#echo "exec_02_defaultpasswd"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ -n ${DEFAULTPASSWD} ]]; then
# Добавить параметр в ${FILE_ROOT_USERS}=.users_credential и удалить параметр DEFAULTROOTPASSWD из '/etc/ublinux/users
if [[ -f ${FILE_ROOT_USERS} ]]; then
sed "/DEFAULTPASSWD=/d" -i "${FILE_ROOT_USERS}"
echo "DEFAULTPASSWD='${DEFAULTPASSWD}'" >> ${FILE_ROOT_USERS}
fi
[[ -f "${SYSCONF}/users" ]] && sed "/DEFAULTPASSWD=/d" -i "${SYSCONF}/users"
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
[[ -f ${FILE_ROOT_USERS} ]] && sed "/DEFAULTPASSWD=/d" -i "${FILE_ROOT_USERS}"
[[ -f "${SYSCONF}/users" ]] && sed "/DEFAULTPASSWD=/d" -i "${SYSCONF}/users"
fi
}
# Создаём группы из ${DEFAULTGROUP},${ADMGROUPS},${USERGROUPS} c ID из /usr/share/ublinux-sysusers/*.sysusers
exec_03_add_groups(){
#echo "exec_03_add_groups"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
local PARAM="$@"
local GROUPADD_GROUPS= SELECT_GROUP= SELECT_GID=
local DATA_FILE_GROUP=$(cat ${FILE_GROUP})
# Загрузить файлы которые совпадают в каталогах /usr/lib/sysusers.d/ и /usr/share/ublinux-sysusers/. И загрузить которые уникальные в /usr/lib/sysusers.d/
local DATA_SYSUSERS=$(cat ${ROOTFS}/usr/lib/sysusers.d/*.conf ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers)
if [[ -n ${PARAM} ]]; then
local GROUPADD_GROUPS=${PARAM}
else
local GROUPADD_GROUPS="${DEFAULTGROUP},${ADMGROUPS},${USERGROUPS}"
fi
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ -n ${GROUPADD_GROUPS} ]]; then
GROUPADD_GROUPS=${GROUPADD_GROUPS//;/,}; GROUPADD_GROUPS="${GROUPADD_GROUPS//,,/,}"
[[ ${GROUPADD_GROUPS:0:1} == ',' ]] && GROUPADD_GROUPS=${GROUPADD_GROUPS:1}
[[ ${GROUPADD_GROUPS} =~ ','$ ]] && GROUPADD_GROUPS=${GROUPADD_GROUPS%*,}
local SELECT_GROUP=
[[ -n ${GROUPADD_GROUPS} ]] && while IFS= read -u3 SELECT_GROUP; do
local SELECT_GID=
# Поиск по имени в шаблонах пользователей/групп systemd, если найдено, то GID из шаблона
[[ ${DATA_SYSUSERS} =~ ($'\n'|^)+('g'|'u')[[:blank:]]+"${SELECT_GROUP}"[[:blank:]]+([[:digit:]]+)[^$'\n']*($'\n'|$)+ ]] && SELECT_GID=${BASH_REMATCH[3]}
# Поиск по GID в шаблонах пользователей/групп systemd, если найдено, то GID=SELECT_GROUP, а SELECT_GROUP из шаблона
[[ ${SELECT_GID} != "" && ${SELECT_GROUP} =~ ^[[:digit:]]+$ && ${DATA_SYSUSERS} =~ ($'\n'|^)+('g'|'u')[[:blank:]]+([^$'\n']+)[[:blank:]]+"${SELECT_GROUP}"[^$'\n']*($'\n'|$)+ ]] \
&& SELECT_GID=${SELECT_GROUP} && SELECT_GROUP=${BASH_REMATCH[3]}
if [[ ${SELECT_GID} != "" && ${DATA_FILE_GROUP} =~ ($'\n'|^)+"${SELECT_GROUP}":[^$'\n']*:"${SELECT_GID}":[^$'\n']*($'\n'|$)+ ]]; then
# Группа найдена, имя и id совпадают, пропускаем добавление
continue
elif [[ ${SELECT_GID} != "" && ${DATA_FILE_GROUP} =~ ($'\n'|^)+"${SELECT_GROUP}":[^$'\n']*($'\n'|$)+ ]]; then
# Группа найдена, имя совпадает, но id не совпадает, меняем GID у группы, все остальные параметры группы не изменяем
#echo "WARNING: the group '${SELECT_GROUP}' has an id different from the template '/usr/share/ublinux-sysusers/*.sysusers' and the id will be changed to '${SELECT_GROUP}:${SELECT_GID}'"
group_add "${SELECT_GROUP}:${SELECT_GID}:+:+:+"
else
# Группа не найдена, добавить новую
[[ ${SELECT_GID} == @(""|"-") ]] && SELECT_GID="+"
if [[ ${SELECT_GROUP} =~ ${NAME_REGEX} ]]; then
group_add "${SELECT_GROUP}:${SELECT_GID}:+:+:+"
else
>&2 echo "ERROR: '${SELECT_GROUP}' cannot be a group name"
fi
fi
done 3< <(sort -V <<< "${GROUPADD_GROUPS//,/$'\n'}")
fi
}
# Функция добавление/удаление групп в систему. Если группа существует, то изменить под параметры
# $1 Команды set или remove с режимом, варианты: set=|set+=|set++=|set-=|set--=|remove
# $2 Для команды set=|set+=|set++= параметр со значением, пример: GROUPADD[g_department_1]=ob.ivanov,rv.smirnov
# Для команды set-=|set--=|remove параметр только с именем, пример: GROUPADD[g_department_1]
# null Если отсутствует $@, то применяем из системной конфигурации GROUPADD[*]
## GROUPADD[group_name]='group_users:gid:optional:password|x'
## group_name # Имя группы
## group_users # Пользователи группы, перечисление через запятую. Может быть пусто.
## gid # GID группы
## null|x # Если пусто или 'x', то автоматически рассчитывать
## s|system # Назначить системный свободный GID
## optional # Дополнительные параметры, например: '--system --non-unique'
## -o|--non-unique # Разрешить создание групп с повторяющимися (не уникальными) GID
## -r|--system # Cоздавать системную группу
## administrators # Администраторы группы которые могут менять пароль группы и добавлять членов
## password|x # Хеш пароля группа, если выбрано 'x' или пусто, то группа без пароля
## + # Значение "+" в любом блоке означает, что данные поля будут взяты с существующей группы
## GROUPADD[g_department_1]=ob.ivanov,rv.smirnov
## GROUPADD[g_department_2]='ob.ivanov,rv.smirnov:1001::superadmin:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60'
exec_04_groupadd(){
#echo "exec_04_groupadd"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
local PARAM="$@"
[[ $(declare -p GROUPADD 2>/dev/null) =~ ^"declare -A" ]] || declare -gA GROUPADD
local SELECT_GROUP SELECT_USERS SELECT_GID SELECT_OPTIONAL SELECT_ADMINISTRATORS SELECT_PASSWORD NULL
local ARG_SELECT_USERS ARG_SELECT_GID SELECT_OPTIONAL ARG_SELECT_PASSWORD ARG_NON_UNIQUE
local DATA_FILE_PASSWD REAL_SELECT_USERS REAL_SELECT_ADMINISTRATORS
local FILE_GROUP="${ROOTFS}/etc/group"
local DATA_FILE_GROUP=$(cat ${FILE_GROUP})
local DATA_SYSUSERS=$(cat ${ROOTFS}/usr/lib/sysusers.d/*.conf ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers)
if [[ -n ${PARAM} ]]; then
local GROUPADD=
declare -A GROUPADD
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#GROUPADD[@]} != 0 ]]; then
groupadd_local(){
get_free_gid(){
local PARAM="$@"
local GID_MIN= GID_MAX= GID_NEW=
# Свободный номер списка групп, кроме системного списка
GID_MIN=$([[ ${DATA_FILE_LOGINDEFS} =~ [^#[^:blank:]]*GID_MIN[[:blank:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}")
GID_MAX=$([[ ${DATA_FILE_LOGINDEFS} =~ [^#[^:blank:]]*GID_MAX[[:blank:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}")
# Предоставить свободный номер с начала списка
#GID_NEW=$(awk -F':' -v GROUP_MIN=${GID_MIN:=1000} -v GROUP_MAX=${GID_MAX:=6000} '{ gid[$3]=GROUP_MIN } END {for (x=GROUP_MIN; x<=GROUP_MAX; x++) if (!gid[x]) {print x; exit}}' ${FILE_GROUP}) #'
#[[ ${GID_NEW} == "" ]] && GID_NEW=${GID_MIN}
# Предоставить свободный номер с конца списка
GID_NEW=$(awk -F':' -v GROUP_MIN=${GID_MIN:=1000} -v GROUP_MAX=${GID_MAX:=60000} '{ gid[$3]=GROUP_MAX } END {for (x=GROUP_MAX; x>=GROUP_MIN; x--) if (!gid[x]) {print x; exit}}' ${FILE_GROUP}) #'
[[ ${GID_NEW} == "" ]] && GID_NEW=${GID_MAX}
printf "%d" "${GID_NEW}"
}
local SELECT_GROUP=$1
# Добавить параметр в ${FILE_ROOT_USERS}=.users_credential и удалить параметр GROUPADD[.*] из '/etc/ublinux/users
IFS=: read -r SELECT_USERS SELECT_GID SELECT_OPTIONAL SELECT_ADMINISTRATORS SELECT_PASSWORD NULL <<< "${GROUPADD[${SELECT_GROUP}]}"
[[ ${SELECT_USERS} == "x" ]] && SELECT_USERS=
# Поиск по имени в шаблонах пользователей/групп systemd, если найдено, то GID из шаблона
[[ ${DATA_SYSUSERS} =~ ($'\n'|^)+('g'|'u')[[:blank:]]+"${SELECT_GROUP}"[[:blank:]]+([[:digit:]]+)[^$'\n']*($'\n'|$)+ ]] \
&& SELECT_GID=${BASH_REMATCH[3]}
# Поиск по GID в шаблонах пользователей/групп systemd, если найдено, то GID=SELECT_GROUP, а SELECT_GROUP из шаблона
[[ ${SELECT_GROUP} =~ ^[[:digit:]]+$ && ${DATA_SYSUSERS} =~ ($'\n'|^)+('g'|'u')[[:blank:]]+([^$'\n']+)[[:blank:]]+"${SELECT_GROUP}"[^$'\n']*($'\n'|$)+ ]] \
&& SELECT_GID=${SELECT_GROUP} && SELECT_GROUP=${BASH_REMATCH[3]}
[[ ${SELECT_GID,,} == 'x' ]] && SELECT_GID=$(get_free_gid)
[[ ${SELECT_GID} =~ ^([[:digit:]]+|'s'|'system')$ ]] || SELECT_GID=$(get_free_gid)
[[ ${SELECT_OPTIONAL} == 'x' ]] && SELECT_OPTIONAL=
[[ ${SELECT_OPTIONAL} =~ ('-r'|'--system') ]] && SELECT_GID="system"
#[[ ! ${SELECT_OPTIONAL} =~ ('-o'|'--non-unique') && ${DATA_FILE_GROUP} =~ ($'\n'|^)+[^:]*:[^:]*:"${SELECT_GID}": ]] && { >&2 echo "ERROR: '${SELECT_GROUP}' non unique a group ID (GID)"; return 1; }
[[ ${SELECT_PASSWORD} == @(""|"x") ]] && SELECT_PASSWORD=
[[ ${SELECT_PASSWORD} != @(""|'!*'|'!'|'*') ]] && SELECT_PASSWORD=$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD})
#echo "==> exec_04_groupadd: ${SELECT_GROUP}:${SELECT_USERS}:${SELECT_GID}:${SELECT_OPTIONAL}:${SELECT_ADMINISTRATORS}:${SELECT_PASSWORD}"
group_add "${SELECT_GROUP}:${SELECT_GID}:${SELECT_USERS}:${SELECT_PASSWORD}:${SELECT_ADMINISTRATORS}"
if [[ -n ${PARAM} && -z ${ROOTFS} ]]; then
if [[ -f ${FILE_ROOT_USERS} ]]; then
sed "/GROUPADD\[${SELECT_GROUP}\]=/d" -i "${FILE_ROOT_USERS}"
echo "GROUPADD[${SELECT_GROUP}]='${GROUPADD[${SELECT_GROUP}]}'" >> ${FILE_ROOT_USERS}
fi
[[ -f "${SYSCONF}/users" ]] && sed -E "s/(GROUPADD\[${SELECT_GROUP}\]=[\'\"]?)([^:]*:[^:]*:[^:]*:[^:]*:)[^\'\"]*([\'\"]?)/\1\2\3/g" -i "${SYSCONF}/users"
fi
}
local SELECT_GROUP= LIST_GROUPADD_GID= LIST_GROUPADD_NOGID=
while IFS= read -ru3 SELECT_GROUP; do
[[ ${SELECT_GROUP} =~ ${NAME_REGEX} ]] || { >&2 echo "ERROR: '${SELECT_GROUP}' cannot be a group name"; continue; }
IFS=: read -r SELECT_USERS SELECT_GID SELECT_OPTIONAL SELECT_ADMINISTRATORS SELECT_PASSWORD NULL <<< "${GROUPADD[${SELECT_GROUP}]}"
if [[ ${SELECT_GID} =~ ^[0-9]+$ ]] ; then
LIST_GROUPADD_GID+="groupadd_local ${SELECT_GROUP}; "
else
LIST_GROUPADD_NOGID+="groupadd_local ${SELECT_GROUP}; "
fi
done 3< <(printf "%s\n" "${!GROUPADD[@]}" | sort -V)
[[ -n ${LIST_GROUPADD_GID} ]] && eval "${LIST_GROUPADD_GID}"
[[ -n ${LIST_GROUPADD_NOGID} ]] && eval "${LIST_GROUPADD_NOGID}"
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then
SELECT_GROUP=${BASH_REMATCH[1]}
if [[ ${SELECT_GROUP} == @("*"|"**"|"/"|"//") ]]; then
while IFS= read -ru3 SELECT_GROUP; do
group_del ${SELECT_GROUP}
[[ -f ${FILE_ROOT_USERS} ]] && sed "/GROUPADD\[${SELECT_GROUP}\]/d" -i "${FILE_ROOT_USERS}" 2>/dev/null
done 3< <(printf "%s\n" "${!GROUPADD[@]}")
else
group_del ${SELECT_GROUP}
[[ -f ${FILE_ROOT_USERS} ]] && sed "/GROUPADD\[${SELECT_GROUP}\]/d" -i "${FILE_ROOT_USERS}" 2>/dev/null
fi
fi
fi
}
# Создаем пользователей из ${NEEDEDUSERS} и добавляем в группы
# $1 Команды set или remove с режимом, варианты: set=|set+=|set++=|set-=|set--=|remove
# $2 Для команды set=|set+=|set++= параметр со значением, пример:
# Для команды set-=|set--=|remove параметр только с именем, пример:
# null Если отсутствует $@, то применяем из системной конфигурации
exec_05_neededusers(){
#echo "exec_05_neededusers"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
local PARAM="$@"
local SELECT_USERNAME SELECT_UID SELECT_PASSWORD SELECT_GECOS NULL ADDGROUPS
local ARG_DEFAULTGROUP ARG_SELECT_UID ARG_SELECT_GECOS
if [[ -n ${PARAM} ]]; then
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
# Если по умолчанию нет ни одного пользователя, то создаём администратора
#[[ -z ${NEEDEDUSERS} ]] && NEEDEDUSERS="${DEFAULTUSER}:${ADMUID}:${DEFAULTPASSWD}:Administrator"
[[ -n ${ROOTFS} ]] && { [[ -z $(cmdline_value users) ]] || NEEDEDUSERS=$(cmdline_value users); }
[[ ${NOSECUREROOTPASSWD} == ${DEFAULTROOTPASSWD} ]] && ADDADM=yes
if [[ -n ${NEEDEDUSERS} ]]; then
while IFS= read -ru3 SELECT_USER; do
# Добавить параметр в ${FILE_ROOT_USERS}=.users_credential и удалить параметр NEEDEDUSERS из '/etc/ublinux/users
if [[ -n ${PARAM} && -z ${ROOTFS} ]]; then
if [[ -f ${FILE_ROOT_USERS} ]]; then
sed "/NEEDEDUSERS=/d" -i "${FILE_ROOT_USERS}"
echo "NEEDEDUSERS='${SELECT_USER}'" >> ${FILE_ROOT_USERS}
fi
[[ -f "${SYSCONF}/users" ]] && sed "/NEEDEDUSERS=/d" -i "${SYSCONF}/users"
fi
IFS=: read -r SELECT_USERNAME SELECT_UID SELECT_PASSWORD SELECT_GECOS NULL <<< "${SELECT_USER}"
[[ ${SELECT_PASSWORD} == "x" ]] && SELECT_PASSWORD="${DEFAULTPASSWD}"
ADDGROUPS="${USERGROUPS}"
[[ ${SELECT_UID} == ${ADMUID} && ${ADDADM} == "yes" ]] && ADDGROUPS="${USERGROUPS},${ADMGROUPS}"
# Если указана обязательная синхронизация при каждом запуске, то пользователя удалить и создать нового
if [[ ${USERADD_SYNC} =~ 'boot' || ${USERADD_SYNC[${SELECT_USERNAME}]} =~ 'boot' ]]; then
if [[ -x ${ROOTFS}/usr/bin/userdel ]]; then
${CMD_CHROOT} /usr/bin/userdel -f ${SELECT_USERNAME}
elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then
# busybox deluser
${CMD_CHROOT} /usr/bin/busybox deluser ${SELECT_USERNAME}
fi
fi
# Создаём пользователя
if ! grep -q ^"${SELECT_USERNAME}": ${FILE_PASSWD} 2>/dev/null; then
[[ -n ${SELECT_UID} ]] && ARG_SELECT_UID="-u ${SELECT_UID}" || ARG_SELECT_UID=
if [[ -x ${ROOTFS}/usr/bin/useradd ]]; then
[[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="-c '${SELECT_GECOS}'" || ARG_SELECT_GECOS=
[[ -n ${DEFAULTGROUP} ]] && ARG_DEFAULTGROUP="-G ${DEFAULTGROUP}" || ARG_DEFAULTGROUP=
eval "${CMD_CHROOT} /usr/bin/useradd -M ${ARG_DEFAULTGROUP} ${ARG_SELECT_UID} ${ARG_SELECT_GECOS} ${SELECT_USERNAME}" #>/dev/null 2>&1
elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then
# busybox adduser
[[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="-g '${SELECT_GECOS}'" || ARG_SELECT_GECOS=
[[ -n ${SELECT_GROUP} ]] && ARG_SELECT_GROUP="-G ${SELECT_GROUP}" || ARG_SELECT_GROUP="-G ${SELECT_USERNAME}"
eval "${CMD_CHROOT} /usr/bin/busybox adduser -D -H ${ARG_DEFAULTGROUP} ${ARG_SELECT_UID} ${ARG_SELECT_GECOS} ${SELECT_USERNAME}" #>/dev/null 2>&1
fi
# Добавляем пользователя в группу
USER_GROUPS="${ADDGROUPS//;/,}"
${CMD_CHROOT} /usr/bin/usermod -a -G ${USER_GROUPS%*,} ${SELECT_USERNAME} #>/dev/null 2>&1
# Задаём пароль пользователю
#[[ -n ${SELECT_PASSWORD} ]] && return_hash_password "${SELECT_PASSWORD}" && [[ -n ${HASH_PASSWORD_NEW} ]] && SELECT_PASSWORD="${HASH_PASSWORD_NEW}"
[[ -n ${SELECT_PASSWORD} ]] && SELECT_PASSWORD=$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD})
#set_passwd "${SELECT_USERNAME}" "${SELECT_PASSWORD}"
user_add "${SELECT_USERNAME}:+:+:+:${SELECT_PASSWORD}:+:+:+:+:+:+:+:+"
fi
# Создаём домашний каталог принудительно и копируем /etc/skel
if [[ ! -d ${ROOTFS}${DEFAULT_HOME_USER}/"${SELECT_USERNAME}" \
|| ${UPDATEHOME[${SELECT_USERNAME}],,} == @(yes|y|enable) \
|| ${UPDATEHOME,,} == @(yes|y|enable) ]]; then
create_home "${SELECT_USERNAME}" force
fi
done 3< <(tr ",;" "\n" <<< "${NEEDEDUSERS}")
fi
}
# Добавить пользователя системы в /etc/passwd. Если пользователь существует, то без изменений
# $1 Команды set или remove с режимом, варианты: set=|set+=|set++=|set-=|set--=|remove
# $2 Для команды set=|set+=|set++= параметр со значением, пример: USERADD[user-1]='Пользователь-1:x:x:vboxusers,libvirt:-s /usr/bin/bash:%%plain_password'
# Для команды set-=|set--=|remove параметр только с именем, пример: USERADD[superadmin]
# null Если отсутствует $@, то применяем из системной конфигурации USERADD[*]
##
## USERADD=no|none|disable # Отключить управление прользователями конфигурации
## USERADD[user_name]='gecos:uid:user_group:extra_groups:optional:password|x'
## user_name # Имя пользователя, обязательное поле
## gecos # Поле GECOS, с подробным описанием пользователя, можно локализованное, не обязательное
## uid # UID пользователя, если необходимо автоматически рассчитывать, то оставить пустым или 'x'
## user_group # Основная группа пользователя, номер или имя, если выбрано пусто или 'x', то 'user_group=user_name'
## extra_groups # Дополнительные группы пользователя. Дополнительные к USERGROUPS
## # Если группа отсутствует или 'x', то 'extra_groups=users'. Если группа не существует, то будет создана. Перечисление через запятую.
## optional # Дополнительные параметры, например: '--shell /usr/bin/bash --create-home --no-create-home --no-user-group --non-unique'
## --home-dir <ДОМ_КАТ> # Домашний каталог новой учётной записи
## -s, --shell /usr/bin/bash # Регистрационная оболочка новой учётной записи
## -r, --system # Создавать системную группу
## -M, --no-create-home # Не создавать домашний каталог пользователя
## -N, --no-user-group # Не создавать группу с тем же именем что и у пользователя
## -o, --non-unique # Разрешить создание пользователей с повторяющимися (не уникальными) UID, использовать только совместно с параметром <uid>
## --badnames # Не проверять имя на несоответствие правилам использования символов
## password|x # Хеш пароля пользователя, если пусто или 'x', то 'password=${DEFAULTPASSWD}',
## # Если первые символы (%%), то пароль хранится в нешифрованном виде
## # Если первые символы (!*), то аутентификация запрещена
## # Если первый символ (*) или (!), то аутентификация по паролю заблокирована. Но другие методы входа,
## # такие как аутентификация на основе ключей или переключение на пользователя, по-прежнему разрешены
## USERADD[superadmin]='Администратор:1000:x:x:x:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60'
## USERADD[user-1]=x
## USERADD[user-1]='Пользователь-1:x:x:vboxusers,libvirt:-s /usr/bin/bash:%%plain_password'
##
## Синхронизация пользователей системы /etc/passwd с глобальной конфигурацией
## USERADD_SYNC[user_name]='boot,shutdown'
## user_name # Имя пользователя, необязательное поле. Если не указано, то применяется для всех пользователей
## boot # При загрузке системы принудительно применить глобальную конфигурацию на пользователя
## shutdown # При завершении работы системы синхронизировать указанных пользователей в системе с глобальной конфигурацией
exec_06_useradd(){
#echo "exec_06_useradd"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
[[ ${USERADD} != @(none|no|disable) ]] || return 0
[[ $(declare -p USERADD_SYNC 2>/dev/null) =~ ^"declare -A" ]] || declare -gA USERADD_SYNC
[[ $(declare -p UPDATEHOME 2>/dev/null) =~ ^"declare -A" ]] || declare -gA UPDATEHOME
[[ $(declare -p USERADD 2>/dev/null) =~ ^"declare -A" ]] || declare -gA USERADD
[[ $(declare -p USERSHADOW 2>/dev/null) =~ ^"declare -A" ]] || declare -gA USERSHADOW
local SELECT_USERNAME SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUP SELECT_OPTIONAL SELECT_PASSWORD NULL
local ARG_SELECT_UID ARG_SELECT_GROUP ARG_SELECT_GECOS ARG_SELECT_PASSWORD ARG_SELECT_OPTIONAL
local ARG_GROUPADD_GID ARG_GROUPADD_GROUPNAME
local STATUS=
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
local USERADD=
declare -A USERADD
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
# Если в GRUB указан параметр useradd, то создать пользователя
[[ -n ${ROOTFS} ]] && while IFS=':' read -u3 SELECT_USERNAME SELECT_UID SELECT_GROUP SELECT_EXTRAGROUP SELECT_PASSWORD NULL; do
[[ ${SELECT_USERNAME} != "" ]] && USERADD[${SELECT_USERNAME}]=":${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUP}::${SELECT_PASSWORD}"
done 3< <(tr ';' '\n' <<< $(cmdline_value useradd))
if [[ ${#USERADD[@]} == 0 ]]; then
local DEFAULTUSER_GECOS="Administrator"
[[ ${LANG} =~ "ru_RU" ]] && DEFAULTUSER_GECOS="Администратор"
USERADD[${DEFAULTUSER}]="${DEFAULTUSER_GECOS}:${ADMUID}::::${DEFAULTPASSWD}"
fi
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#USERADD[@]} -ne 0 ]]; then
[[ ${NOSECUREROOTPASSWD} == ${DEFAULTROOTPASSWD} ]] && ADDADM=yes
local DATA_FILE_PASSWD=$(cat ${FILE_PASSWD})
local DATA_FILE_GROUP=$(cat ${FILE_GROUP})
useradd_local(){
local SELECT_USERNAME=$1
local SELECT_GECOS= SELECT_UID= SELECT_GROUP= SELECT_EXTRAGROUPS= SELECT_OPTIONAL= SELECT_PASSWORD= NULL=
local SELECT_HOME= SELECT_SHELL= SELECT_MKHOME=
# Проверяем существует ли пользователь в системе
[[ ${DATA_FILE_PASSWD} =~ ($'\n'|^)+"${SELECT_USERNAME}": ]] && IS_USERNAME_PASSWD=yes || IS_USERNAME_PASSWD=
# Проверяем отсутствие пользователя в системе или параметр принудительного обновления
if [[ ${IS_USERNAME_PASSWD} == "" || ${USERADD_SYNC} =~ 'boot' || ${USERADD_SYNC[${SELECT_USERNAME}]} =~ 'boot' ]]; then
IFS=: read -r SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS SELECT_OPTIONAL SELECT_PASSWORD NULL <<< "${USERADD[${SELECT_USERNAME}]}"
[[ ${NULL} == "" ]] || { >&2 echo "WARNING: Unnecessary processing of the ':' character. USERADD[${SELECT_USERNAME}]"; }
#echo -e "\n===> exec_06_useradd: ${SELECT_USERNAME}=${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}:${SELECT_PASSWORD}"
# -----------
[[ ${SELECT_OPTIONAL,,} == "x" ]] && SELECT_OPTIONAL=
[[ ${SELECT_OPTIONAL} =~ ("--home-dir "|"-d ")([^' ']*)(' '|$) ]] && SELECT_HOME="${BASH_REMATCH[2]}" || SELECT_HOME="${DEFAULT_HOME_USER}/${SELECT_USERNAME}"
[[ ${SELECT_OPTIONAL} =~ ("--shell "|"-s ")([^' ']*)(' '|$) ]] && SELECT_SHELL="${BASH_REMATCH[2]}" || SELECT_SHELL="+"
[[ ${SELECT_OPTIONAL} =~ ("--no-create-home"|"-M") ]] && SELECT_MKHOME= || SELECT_MKHOME="yes"
# -----------
[[ ${SELECT_PASSWORD} == @(""|"x") ]] && SELECT_PASSWORD="${DEFAULTPASSWD}"
[[ ${SELECT_PASSWORD} != @(""|'!*'|'!'|'!!'|'*') ]] && SELECT_PASSWORD="$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD})"
# -----------
[[ ${SELECT_GECOS,,} == "x" ]] && SELECT_GECOS=
# -----------
[[ ${SELECT_UID,,} == "x" || ${SELECT_UID} =~ ^[^0-9]+$ ]] && SELECT_UID=
# Если существует домашний каталог пользователя, то UID берём от каталога
if [[ -z ${SELECT_UID} && -d "${ROOTFS}${SELECT_HOME}" ]]; then
SELECT_UID=$(stat -c %u "${ROOTFS}${SELECT_HOME}")
[[ ! ${DATA_FILE_PASSWD} =~ ($'\n'|^)+"${SELECT_USERNAME}":[^:]*:"${SELECT_UID}": ]] \
&& [[ ${DATA_FILE_PASSWD} =~ ($'\n'|^)+[^:]*:[^:]*:"${SELECT_UID}": ]] && SELECT_UID=
fi
if [[ -z ${SELECT_UID} && ${DATA_FILE_PASSWD} =~ ($'\n'|^)+"${SELECT_USERNAME}":[^:]*:([[:digit:]]+): ]]; then
# Если пользователь присутствует в списке, то берём его UID
SELECT_UID=${BASH_REMATCH[2]}
fi
# -----------
[[ ${SELECT_GROUP,,} == "x" ]] && SELECT_GROUP=
# Если существует домашний каталог пользователя, то GID берём от каталога
if [[ -z ${SELECT_GROUP} && -d "${ROOTFS}${SELECT_HOME}" ]]; then
SELECT_GROUP=$(stat -c %g "${ROOTFS}${SELECT_HOME}")
[[ ! ${DATA_FILE_PASSWD} =~ ($'\n'|^)+"${SELECT_USERNAME}":[^:]*:[^:]*:"${SELECT_GROUP}": ]] \
&& [[ ${DATA_FILE_PASSWD} =~ ($'\n'|^)+[^:]*:[^:]*:[^:]*:"${SELECT_GROUP}": ]] && SELECT_GROUP=
fi
# Если указана основная группа, но она не создана, то создать
if [[ -n ${SELECT_GROUP} && ${DATA_FILE_GROUP} =~ ($'\n'|^)+"${SELECT_GROUP}":[^$'\n']+:([[:digit:]]+):.*($'\n'|$) ]]; then
# Если группа имеет буквенное имя и присутствует в списке, то берём её GUID
SELECT_GROUP=${BASH_REMATCH[2]}
elif [[ -n ${SELECT_GROUP} && ${DATA_FILE_GROUP} =~ ($'\n'|^)+[^$'\n']+:[^$'\n']+:"${SELECT_GROUP}":.*($'\n'|$) ]]; then
# Если группа имеет цифровое имя и присутствует в списке, то берём её GUID
SELECT_GROUP=${SELECT_GROUP}
elif [[ ${SELECT_OPTIONAL} =~ ("--no-user-group"|"-N") && ${DATA_FILE_GROUP} =~ ($'\n'|^)+"users":[^$'\n']+:([[:digit:]]+):.*($'\n'|$) ]]; then
# Если указан параметр не создавать группу по имени пользователя, то задаём GID группы users
SELECT_GROUP=${BASH_REMATCH[2]}
elif [[ ${SELECT_OPTIONAL} =~ ("--system"|"-r") ]]; then
# Если указан параметр создавать системную группу
SELECT_GROUP="system"
else
if [[ -n ${SELECT_GROUP} && -n ${GROUPADD[${SELECT_GROUP}]} ]]; then
# Если группа указана и присутствует в списке групп GROUPADD[.]
exec_04_groupadd "GROUPADD[${SELECT_GROUP}]=${GROUPADD[${SELECT_GROUP}]}"
DATA_FILE_GROUP=$(cat ${FILE_GROUP})
[[ ${DATA_FILE_GROUP} =~ ($'\n'|^)+"${SELECT_GROUP}":[^$'\n']+:([[:digit:]]+):.*($'\n'|$) ]] \
&& SELECT_GROUP=${BASH_REMATCH[2]}
elif [[ ${SELECT_GROUP} =~ ^[[:digit:]]+$ && ${SELECT_GROUP} == ${SELECT_UID} ]]; then
# Группа имет цифровой GID и номер GID=UID
IFS=: read -r NULL SELECT_GROUP NULL NULL NULL NULL <<< $(group_add --verbose "${SELECT_USERNAME}:${SELECT_GROUP}:+:+:+")
elif [[ ${SELECT_GROUP} =~ ^[[:digit:]]+$ && ${SELECT_GROUP} != ${SELECT_UID} ]]; then
# Группа имет цифровой GID и номер GID!=UID
IFS=: read -r NULL SELECT_GROUP NULL NULL NULL NULL <<< $(group_add --verbose "${SELECT_USERNAME}:${SELECT_GROUP}:+:+:+")
elif [[ ${SELECT_GROUP} =~ ${NAME_REGEX} ]]; then
# Группа имет буквенный GID
IFS=: read -r NULL SELECT_GROUP NULL NULL NULL NULL <<< $(group_add --verbose "${SELECT_GROUP}:+:+:+:+")
else
# Если группа не имеет цифры или не имеет букв или не по шаблону разрешённых
SELECT_GROUP=
fi
fi
# -----------
# Создаём/Изменяем пользователя
user_add "${SELECT_USERNAME}:${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_PASSWORD}:${SELECT_HOME}:${SELECT_SHELL}:+:+:+:+:+:+"
# -----------
# Проверим права на домашнем каталоге пользователя, если не совпадают с указанным пользователем, то переназначим
if [[ -d ${ROOTFS}${SELECT_HOME} ]]; then
GET_UID_GID_HOME=$(stat -c "%u:%g" "${ROOTFS}${SELECT_HOME}")
GET_UID_GID_SELECT="$(${CMD_CHROOT} /usr/bin/id -u ${SELECT_USERNAME} 2>/dev/null):$(${CMD_CHROOT} /usr/bin/id -g ${SELECT_USERNAME} 2>/dev/null)"
if [[ ${GET_UID_GID_HOME} != ${GET_UID_GID_SELECT} ]]; then
eval ${CMD_CHROOT} /usr/bin/chown -f -h "${GET_UID_GID_SELECT}" \
$(${CMD_CHROOT} find ${SELECT_HOME} -maxdepth 1 -printf '"%p"\n') \
$(cat ${ROOTFS}/etc/xdg/user-dirs.defaults 2>/dev/null | grep -v "^\s*#" | sed -E "s|.*=(.*)|${SELECT_HOME}/\1|") \
$(cat ${ROOTFS}${SELECT_HOME}/.config/user-dirs.dirs 2>/dev/null | grep -v "^\s*#"| sed -E "s|.*HOME/(.*)|${SELECT_HOME}/\"\1|")
ARG_RECURSIVE="-hRP"
# Все скрытые файлы глубиной 1
eval ${CMD_CHROOT} /usr/bin/chown -f ${ARG_RECURSIVE} "${GET_UID_GID_SELECT}" \
$(${CMD_CHROOT} find ${SELECT_HOME} -maxdepth 1 -name ".*" -printf '"%p"\n')
fi
fi
# -----------
# Вызов как исполнителя после ubconfig
if [[ -n ${PARAM} && -z ${ROOTFS} ]]; then
# Добавим пользователя в дополнительные группы
exec_08_user_members "USERADD[${SELECT_USERNAME}]=${USERADD[${SELECT_USERNAME}]}"
# Задаём параметры пароля пользователю /etc/shadow из USERSHADOW[user]
[[ -n ${USERSHADOW[${SELECT_USERNAME}]} ]] && exec_07_usershadow "USERSHADOW[${SELECT_USERNAME}]=${USERSHADOW[${SELECT_USERNAME}]}"
# Добавить параметр в ${FILE_ROOT_USERS}=.users_credential и удалить хеш пароля параметра USERADD[.*] в /etc/ublinux/users
if [[ -f ${FILE_ROOT_USERS} ]]; then
sed "/USERADD\[${SELECT_USERNAME}\]=/d" -i "${FILE_ROOT_USERS}"
echo "USERADD[${SELECT_USERNAME}]='${USERADD[${SELECT_USERNAME}]}'" >> ${FILE_ROOT_USERS}
fi
[[ -f "${SYSCONF}/users" ]] && sed -E "s/(USERADD\[${SELECT_USERNAME}\]=[\'\"]?)([^:]*:[^:]*:[^:]*:[^:]*:[^:]*:)[^\'\"]*([\'\"]?)/\1\2\3/g" -i "${SYSCONF}/users"
fi
else
[[ -n ${ROOTFS} ]] || echo "INFO: The user '${SELECT_USERNAME}' exists in the system, the settings are not applied. To force the settings, enable the '[users] USERADD_SYNC[${SELECT_USERNAME}]=boot' option"
fi
# Создаём домашний каталог принудительно и копируем /etc/skel
[[ ! -d "${ROOTFS}${DEFAULT_HOME_USER}/${SELECT_USERNAME}" && ${SELECT_MKHOME} == "yes" ]] && UPDATEHOME[${SELECT_USERNAME}]="yes"
if [[ ${UPDATEHOME,,} == @(yes|y|enable) || ${UPDATEHOME[${SELECT_USERNAME}],,} == @(yes|y|enable) ]]; then
create_home "${SELECT_USERNAME}" force
fi
}
# Обработать всех пользователей у которых указан UID в первую очередь
local LIST_USERADD_UID= LIST_USERADD_NOUID=
while IFS= read -ru3 SELECT_USERNAME; do
local SELECT_GECOS= SELECT_UID= SELECT_GROUP= SELECT_EXTRAGROUPS= SELECT_OPTIONAL= SELECT_PASSWORD= NULL=
IFS=: read -r SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS SELECT_OPTIONAL SELECT_PASSWORD NULL <<< "${USERADD[${SELECT_USERNAME}]}"
if [[ ${SELECT_UID} =~ ^[0-9]+$ ]] ; then
LIST_USERADD_UID+="useradd_local ${SELECT_USERNAME}; "
else
LIST_USERADD_NOUID+="useradd_local ${SELECT_USERNAME}; "
fi
done 3< <(printf "%s\n" "${!USERADD[@]}" | sort -V)
eval "${LIST_USERADD_UID}"
eval "${LIST_USERADD_NOUID}"
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]] && [[ ${#USERADD[@]} -ne 0 ]]; then
if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then
# Удалим пользователей
local SELECT_USERNAME=${BASH_REMATCH[1]}
delete_select_username(){
local SELECT_USERNAME=$1
user_del "${SELECT_USERNAME}"
exec_07_usershadow remove "USERSHADOW[${SELECT_USERNAME}]"
#${CMD_CHROOT} /usr/bin/ubconfig --target system --noexecute remove [users] "USERSHADOW[${SELECT_USERNAME}]"
[[ -f ${FILE_ROOT_USERS} ]] && sed "/USERADD\[${SELECT_USERNAME}\]/d" -i "${FILE_ROOT_USERS}"
[[ -f "${SYSCONF}/users" ]] && sed "/USERADD\[${SELECT_USERNAME}\]/d" -i "${SYSCONF}/users"
}
if [[ ${SELECT_USERNAME} == @("*"|"**"|"/"|"//") ]]; then
[[ -f ${SYSCONF}/users ]] && while IFS= read -ru3 LINE_USERADD; do
[[ ${LINE_USERADD} =~ ^.*'['(.*)']' ]] && delete_select_username "${BASH_REMATCH[1]}"
done 3< <(printf "%s\n" "${!USERADD[@]}")
else
delete_select_username "${SELECT_USERNAME}"
fi
fi
fi
}
# Параметры пользователя системы /etc/shadow. Если пользователь существует, то без изменений
# $1 Команды set или remove с режимом, варианты: set=|set+=|set++=|set-=|set--=|remove
# $2 Для команды set=|set+=|set++= параметр со значением, пример: USERSHADOW[superadmin]=2023-01-01:0:99999:7::2025-01-01
# Для команды set-=|set--=|remove параметр только с именем, пример: USERSHADOW[superadmin]
# null Если отсутствует $@, то применяем из системной конфигурации USERSHADOW[*]
## USERSHADOW[user_name]='lastchanged:minday:maxday:warn:inactive:expire'
## user_name # Имя пользователя, обязательное поле
## lastchanged # Дата последнего изменения пароля. Указывается количество дней, исчисляется с 1 января 1970 года (дата эпохи). Возможно указать дату формата: YYYY-MM-DD
## minday # Минимальное количество дней действия пароля, прежде чем пароль пользователя может быть изменен. По умолчанию 0 означает отсутствие минимального срока действия парол
## maxday # Максимальное количество дней действия пароля после смены пароля пользователя. По умолчанию этот номер установлен на 99999
## warn # Количество дней предупреждения, в течение которого пользователь получает предупреждение о необходимости изменения пароля. По умолчанию 7
## inactive # Количество дней не активности пароля до отключения учетной записи пользователя. По умолчанию пустое
## expire # Дата, когда учетная запись была отключена. Указывается количество дней, исчисляется с 1 января 1970 года (дата эпохи). Возможно указать дату формата: YYYY-MM-DD
## <null> # Если один из параметров не задан, содержит пустое значение, то исходное значение не изменяется
## # Конвертировать кол-во дней от эпохи в понятную дату: date --date=@$(( DDDDD*(60*60*24) )); date --date=@EPOCH
## USERSHADOW[superadmin]=2023-01-01:0:99999:7::2025-01-01
## USERSHADOW[superadmin]=18009:0:120:7:14:
exec_07_usershadow(){
#echo "exec_07_usershadow"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
[[ $(declare -p USERSHADOW 2>/dev/null) =~ ^"declare -A" ]] || declare -gA USERSHADOW
local SELECT_USERNAME= SELECT_LASTCHANGED= SELECT_MINDAY= SELECT_MAXDAY= SELECT_WARN= SELECT_INACTIVE= SELECT_EXPIRE= NULL=
local PARAM="$@"
local DATA_FILE_SHADOW=$(cat ${FILE_SHADOW})
if [[ -n ${PARAM} ]]; then
local USERSHADOW
declare -A USERSHADOW
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#USERSHADOW[@]} -ne 0 ]]; then
while IFS= read -ru3 SELECT_USERNAME; do
[[ -n ${SELECT_USERNAME} ]] || continue
# Если пользователь не существует, то пропустить
if [[ ! ${DATA_FILE_SHADOW} =~ ($'\n'|^)+"${SELECT_USERNAME}":([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*)($'\n'|$)+ ]]; then
#${CMD_CHROOT} /usr/bin/ubconfig --quiet --noexecute remove [users] "USERSHADOW[${SELECT_USERNAME}]"
continue
fi
IFS=: read -r SELECT_LASTCHANGED SELECT_MINDAY SELECT_MAXDAY SELECT_WARN SELECT_INACTIVE SELECT_EXPIRE NULL <<< "${USERSHADOW[${SELECT_USERNAME}]}"
[[ ${SELECT_LASTCHANGED} =~ (^[0-9]*$|^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$) ]] || SELECT_LASTCHANGED=
[[ ${SELECT_MINDAY} =~ ^[0-9]*$ ]] || SELECT_MINDAY=
[[ ${SELECT_MAXDAY} =~ ^[0-9]*$ ]] || SELECT_MAXDAY=
[[ ${SELECT_WARN} =~ ^[0-9]*$ ]] || SELECT_WARN=
[[ ${SELECT_INACTIVE} =~ (-1|^[0-9]*$) ]] || SELECT_INACTIVE=
[[ ${SELECT_EXPIRE} =~ (^[0-9]*$|^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$) ]] || SELECT_EXPIRE=
user_add "${SELECT_USERNAME}:+:+:+:+:+:+:${SELECT_LASTCHANGED}:${SELECT_MINDAY}:${SELECT_MAXDAY}:${SELECT_WARN}:${SELECT_INACTIVE}:${SELECT_EXPIRE}"
done 3< <(printf "%s\n" "${!USERSHADOW[@]}" | sort -V)
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]] && [[ ${#USERSHADOW[@]} -ne 0 ]]; then
if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then
local SELECT_USERNAME=${BASH_REMATCH[1]}
delete_select_usershadow(){
local SELECT_USERNAME=$1
if [[ ${DATA_FILE_SHADOW} =~ ($'\n'|^)+"${SELECT_USERNAME}":([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*):([^$'\n']*)($'\n'|$)+ ]]; then
user_add "${SELECT_USERNAME}:+:+:+:+:+:+::::::"
fi
[[ -f "${SYSCONF}/users" ]] && sed "/USERSHADOW\[${SELECT_USERNAME}\]/d" -i "${SYSCONF}/users"
}
if [[ ${SELECT_USERNAME} == @("*"|"**"|"/"|"//") ]]; then
[[ -f ${SYSCONF}/users ]] && while IFS= read -ru3 LINE_USERSHADOW; do
[[ ${LINE_USERSHADOW} =~ ^.*'['(.*)']' ]] && delete_select_usershadow "${BASH_REMATCH[1]}"
done 3< <(printf "%s\n" "${!USERSHADOW[@]}")
else
delete_select_usershadow "${SELECT_USERNAME}"
fi
fi
fi
}
exec_08_user_members(){
#echo "exec_08_user_members"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
[[ $(declare -p USERADD 2>/dev/null) =~ ^"declare -A" ]] || declare -gA USERADD
[[ $(declare -p GROUPADD 2>/dev/null) =~ ^"declare -A" ]] || declare -gA GROUPADD
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
local USERADD=
declare -A USERADD
local GROUPADD=
declare -A GROUPADD
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
local SELECT_USERNAME= SELECT_UID= SELECT_GROUP= SELECT_EXTRAGROUP= SELECT_PASSWORD= NULL=
# Если в GRUB указан параметр useradd, то создать пользователя
[[ -n ${ROOTFS} ]] && while IFS=':' read -u3 SELECT_USERNAME SELECT_UID SELECT_GROUP SELECT_EXTRAGROUP SELECT_PASSWORD NULL; do
[[ ${SELECT_USERNAME} != "" ]] && USERADD[${SELECT_USERNAME}]=":${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUP}::${SELECT_PASSWORD}"
done 3< <(tr ';' '\n' <<< $(cmdline_value useradd))
## USERADD[@]
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#USERADD[@]} -ne 0 ]]; then
[[ ${NOSECUREROOTPASSWD} == ${DEFAULTROOTPASSWD} ]] && ADDADM=yes
local FILE_SHADOW="${ROOTFS}/etc/shadow"
useradd_local(){
local SELECT_USERNAME=$1
local SELECT_UID= SELECT_GROUP= SELECT_EXTRAGROUPS= NULL=
IFS=: read -r NULL SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS NULL NULL NULL <<< "${USERADD[${SELECT_USERNAME}]}"
[[ ${SELECT_EXTRAGROUPS} == @(""|"x") ]] && SELECT_EXTRAGROUPS="${USERGROUPS},${DEFAULTGROUP}" || SELECT_EXTRAGROUPS+=",${USERGROUPS},${DEFAULTGROUP}"
[[ ${SELECT_UID} == ${ADMUID} && ${ADDADM} == "yes" ]] && SELECT_EXTRAGROUPS+=",${ADMGROUPS}"
SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS//;/,}"; SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS//,,/,}"
[[ ${SELECT_EXTRAGROUPS} =~ ','$ ]] && SELECT_EXTRAGROUPS=${SELECT_EXTRAGROUPS%*,}
[[ ${SELECT_EXTRAGROUPS:0:1} == "," ]] && SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS:1}"
# Создавать группы из параметра SELECT_EXTRAGROUPS
exec_03_add_groups "${SELECT_EXTRAGROUPS}"
# Добавляем пользователя в дополнительные группы
[[ -n ${SELECT_EXTRAGROUPS} ]] && user_add_group "${SELECT_USERNAME}" "${SELECT_EXTRAGROUPS}"
}
# Удалить пользователей из всех групп
user_remove_group "$(printf "%s," "${!USERADD[@]}")" "%all"
# Добавить пользователей в группы
while IFS= read -ru3 SELECT_USERNAME; do
useradd_local ${SELECT_USERNAME}
done 3< <(printf "%s\n" "${!USERADD[@]}" | sort -V)
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]] && [[ ${#USERADD[@]} -ne 0 ]]; then
if [[ ${PARAM%%=*} =~ ^'USERADD['(.*)']' ]]; then
local SELECT_USERNAME=${BASH_REMATCH[1]}
local SELECT_UID= SELECT_GROUP= SELECT_EXTRAGROUPS= NULL=
IFS=: read -r NULL SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS NULL NULL NULL <<< "${USERADD[${SELECT_USERNAME}]}"
[[ ${SELECT_EXTRAGROUPS,,} == @(""|"x") ]] && return 0
# Удалить пользователя из групп
user_remove_group "${SELECT_USERNAME}" "${SELECT_EXTRAGROUPS}"
fi
fi
## GROUPADD[@]
if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#GROUPADD[@]} -ne 0 ]]; then
groupadd_local(){
local SELECT_GROUP=$1
local SELECT_USERS= SELECT_GID= NULL=
IFS=: read -r SELECT_USERS SELECT_GID NULL NULL NULL NULL <<< "${GROUPADD[${SELECT_GROUP}]}"
[[ ${SELECT_USERS} == @(""|"x") ]] && return 0
# Создавать группы из параметра SELECT_GROUP
exec_03_add_groups "${SELECT_GROUPS}"
# Добавляем пользователя в дополнительные группы
user_add_group "${SELECT_USERS}" "${SELECT_GROUP}"
}
while IFS= read -ru3 SELECT_GROUP; do
groupadd_local "${SELECT_GROUP}"
done 3< <(printf "%s\n" "${!GROUPADD[@]}" | sort -V)
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]] && [[ ${#GROUPADD[@]} -ne 0 ]]; then
if [[ ${PARAM%%=*} =~ ^'GROUPADD['(.*)']' ]]; then
local SELECT_GROUP=${BASH_REMATCH[1]}
local SELECT_USERS= SELECT_GID= NULL=
IFS=: read -r SELECT_USERS SELECT_GID NULL NULL NULL NULL <<< "${GROUPADD[${SELECT_GROUP}]}"
[[ ${SELECT_USERS} == @(""|"x") ]] && return 0
# Удалить пользователя из группы
user_remove_group "${SELECT_USERS}" "${SELECT_GROUP}"
fi
fi
}
# Autodetect DM_HINT_PASSWORD
# Если пароли по умолчанию, то DM_HINT_PASSWORD=yes
exec_99_dm_hint_password(){
#echo "exec_99_dm_hint_password"
[[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
[[ -n ${COMMAND} ]] || local COMMAND="set="
local PARAM="$@"
if [[ -n ${PARAM} ]]; then
local DM_HINT_PASSWORD=
[[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}"
fi
if [[ -n ${ROOTFS} ]]; then
if grep -q "^root:${DEFAULTROOTPASSWD}:" ${ROOTFS}/etc/shadow \
&& grep -q "^$(grep ".*:x:${ADMUID}:" ${ROOTFS}/etc/passwd | cut -d: -f1):${DEFAULTPASSWD}:" ${ROOTFS}/etc/shadow; then
[[ $(cat ${SYSCONF}/config 2>/dev/null) =~ ($'\n'|^)+'DM_HINT_PASSWORD=' ]] || echo "DM_HINT_PASSWORD=yes" >> ${SYSCONF}/config
else
sed "/DM_HINT_PASSWORD=/d" -i ${SYSCONF}/config
fi
elif [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ -n ${DM_HINT_PASSWORD} ]]; then
true
elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
true
fi
}
################
##### MAIN #####
################
# Если файл подключен как ресурс с функциями, то выйти
return 0 2>/dev/null && return 0
#rm -f "${FILE_ROOT_USERS}"
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}'"; }
shift
done
eval ${FUNCTION#*; }
fi