From 1af4743af68dda354bac1a08c5863f590e0cfd1a Mon Sep 17 00:00:00 2001 From: asmeron Date: Mon, 29 Jan 2024 14:08:42 +0600 Subject: [PATCH] Add new options --- ublinux/default | 8 + ublinux/functions | 255 +++++++--- ublinux/rc.halt.pre/20-grub | 15 +- ublinux/rc.halt.pre/25-accounts-sync | 124 +++++ ublinux/rc.local.d/20-pwgr_check | 57 +++ ublinux/rc.preinit.d/20-services | 38 +- ublinux/rc.preinit.d/24-logging | 287 +++++++++++ ublinux/rc.preinit.d/40-authpam | 2 +- ublinux/rc.preinit.d/51-autologin | 18 +- ublinux/rc.preinit.d/90-apparmor | 8 +- ublinux/rc.preinit/01-inifile | 49 +- ublinux/rc.preinit/03-initvars | 3 +- ublinux/rc.preinit/10-accounts | 719 +++++++++++++++++++++------ ublinux/templates/ublinux-data.ini | 125 ++++- 14 files changed, 1394 insertions(+), 314 deletions(-) create mode 100755 ublinux/rc.halt.pre/25-accounts-sync create mode 100755 ublinux/rc.local.d/20-pwgr_check create mode 100755 ublinux/rc.preinit.d/24-logging diff --git a/ublinux/default b/ublinux/default index 445fe14..637ba92 100644 --- a/ublinux/default +++ b/ublinux/default @@ -7,6 +7,7 @@ declare -A AUTHPAM declare -A JOURNALD declare -A SYSTEMD_COREDUMP declare -A DOMAIN +declare -A REPOSITORY ##rc.desktop/all/* is launching when desktop is ready @@ -227,3 +228,10 @@ SYSTEMD_COREDUMP[Storage]=none SYSTEMD_COREDUMP[ProcessSizeMax]=0 DOMAIN[client]=realmd_sssd + +REPOSITORY[core]=::/etc/pacman.d/mirrorlist +REPOSITORY[extra]=::/etc/pacman.d/mirrorlist +REPOSITORY[community]=::/etc/pacman.d/mirrorlist +REPOSITORY[multilib]=::/etc/pacman.d/mirrorlist +REPOSITORY[ublinux]=::/etc/pacman.d/mirrorlist +REPOSITORY[modules]=::/etc/pacman.d/mirrorlist diff --git a/ublinux/functions b/ublinux/functions index fa68f4e..6cf45a9 100755 --- a/ublinux/functions +++ b/ublinux/functions @@ -1,87 +1,171 @@ #!/usr/bin/env bash +[[ -d /usr/lib/ublinux ]] && { unset ROOTFS; unset CMD_CHROOT; } || { ROOTFS="/sysroot"; CMD_CHROOT="chroot ${ROOTFS}"; } +SOURCE=${ROOTFS}/usr/lib/ublinux/default; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null || exit 0 +SYSCONF="${ROOTFS}/${SYSCONF}" + export TEXTDOMAINDIR=/usr/share/locale export TEXTDOMAIN=ublinux_functions -# Make from ini file text file with strings like [SECTION]Name=Value -# $1 - input filename -# stdout - result file -function ini2simple(){ - SECTION='[]' - cat $1 | while read a ;do - [ "$a" = "" ] && continue - if [ "${a#\[*\]}" = "" -a "$a" != "" ] ;then - SECTION=$a - else - echo "$SECTION$a" - fi - done -} - -# Restore ini file from text file with strings like [SECTION]Name=Value -# $1 - input filename -# stdout - result file -function simple2ini(){ - LASTSECTION='[]' - cat $1 | while read a ;do - SECTION=${a%%\]*}']' - if [ "$SECTION" != "$LASTSECTION" ] ;then - [ "LASTSECTION" != "[]" ] && echo - echo "$SECTION" - LASTSECTION=$SECTION - fi - echo ${a#\[*\]} - done + # https://en.wikipedia.org/wiki/Crypt_(C) + # https://man.archlinux.org/man/core/libxcrypt/crypt.5.en # /etc/shadow file format + # user:$6$.n.:17736:0:99999:7::: + # [--] [----] [---] - [---] ---- + # | | | | | |||+-----------> 9. Неиспользованный + # | | | | | ||+------------> 8. Срок годности + # | | | | | |+-------------> 7. Период бездействия + # | | | | | +--------------> 6. Период предупреждения + # | | | | +------------------> 5. Максимальный возраст пароля + # | | | +----------------------> 4. Минимальный возраст пароля + # | | +--------------------------> 3. Последнее изменение пароля + # | +---------------------------------> 2. Зашифрованный пароль + # +----------------------------------------> 1. Имя пользователя + # Если поле пароля содержит первый символ звездочку (*), то пользователь не сможет войти по паролю, но сможет другим способом (например по ключу через ssh) + # Если поле пароля содержит первый символ восклицательный знак (!), то пользователь вообще не сможет войти, даже по ключу + # Алгоритмы хеширования пароля: + # (empty) # DES + # $_$ # BSDi + # $1$ # MD5 + # $2$ # bcrypt based on Blowfish + # $2a$ # Blowfish + # $2b$ # OpenBSD blowfish + # $2x$ # blowfish + # $2y$ # Eksblowfish + # $3$ # NTHASH + # $5$ # SHA-256 + # $6$ # SHA-512 + # $7$ # scrypt + # $md5$ # Solaris MD5 + # $sha1$ # PBKDF1 with SHA1 + # $gy$ # gost-yescrypt + # $y$ # yescrypt + # $argon2d$ # Argon2d + # $argon2i$ # Argon2i + # $argon2ds$ # Argon2ds + # $argon2id$ # Argon2id +# Получить хеш пароля, тип хеша +# $1 # Режим получения хеша, значения: hash, phash +# hash # Вернуть хеш, если первые символы %%, то удалить их и вернуть хеш +# phash # Если первые символы %%, то убрать %% и вернуть не шифрованный пароль, в остальных случаях вернуть хеш +# $2 # Тип хеша, поддерживаются yescrypt|gost-yescrypt|scrypt|bcrypt|bcrypt-a|sha512crypt|sha256crypt|sunmd5|md5crypt|bsdicrypt|descrypt|nt +# # В разработке argon2d|argon2i|argon2ds|argon2id +# $3 # Пароль пользователя шифрованный или не шифрованный. Если шифрованный, то вернётся как есть +return_hash_password(){ + SOURCE=${SYSCONF}/users; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null + [[ $1 == @(hash|phash) ]] && local ARG_MODE=$1 && shift + [[ -n ${ARG_MODE} ]] || ARG_MODE='hash' + [[ $1 == @(yescrypt|gost-yescrypt|scrypt|bcrypt|bcrypt-a|sha512crypt|sha256crypt|sunmd5|md5crypt|bsdicrypt|descrypt|nt|argon2d|argon2i|argon2ds|argon2id) ]] && local ARG_HASH=$1 && shift + [[ -n ${ARG_HASH} ]] || ARG_HASH=${HASHPASSWD} + [[ -n ${ARG_HASH} ]] || ARG_HASH=$(${ROOTFS}/usr/bin/ubconfig --raw --default get users HASHPASSWD) + [[ -n ${ARG_HASH} && ${ARG_HASH} != "(null)" ]] || ARG_HASH='yescrypt' + local ARG_PASSWORD="$1" + local HASH_PASSWORD=${ARG_PASSWORD} + [[ -n ${ARG_PASSWORD} ]] || return 0 + if [[ ! ${ARG_PASSWORD} =~ ^('!*'|'!'|'*')*'$'(_|1|2|2a|2b|2x|2y|3|4|5|6|7|md5|sha1|gy|y|argon2d|argon2i|argon2ds|argon2id)'$' ]]; then + [[ ${ARG_PASSWORD} =~ ^'%%' ]] && ARG_PASSWORD=${ARG_PASSWORD:2} && HASH_PASSWORD=${ARG_PASSWORD} || ARG_MODE='hash' + if [[ ${ARG_MODE} == 'hash' && ${ARG_HASH} =~ (yescrypt|gost-yescrypt|scrypt|bcrypt|bcrypt-a|sha512crypt|sha256crypt|sunmd5|md5crypt|bsdicrypt|descrypt|nt) ]]; then + HASH_PASSWORD=$(echo "${ARG_PASSWORD}" | ${ROOTFS}/usr/bin/mkpasswd2 -sm ${ARG_HASH}) + elif [[ ${ARG_HASH} =~ (argon2d|argon2i|argon2ds|argon2id) ]]; then + true + fi + fi + echo "${HASH_PASSWORD}" } -# It include string from $2 file and apply to $1 file -# $1 - base file -# $2 - included file -function apply2simple(){ - cat "$2" | while read a ;do - SECTION=${a%%\]*} - SECTION=${SECTION#\[} - STR=${a#\[*\]} - PNAME=${STR%%=*} - PVAL=${a#*=} -# echo $SECTION $PNAME $PVAL - echo -ne >"$1.tmp" - echo -ne >"$1.lck" - FOUNDS= - cat "$1" | while read b ;do - BSECTION=${b%%\]*} - BSECTION=${BSECTION#\[} - BSTR=${b#\[*\]} - BPNAME=${BSTR%%=*} - BPVAL=${b#*=} - - [ "$BSECTION" = "$SECTION" ] && FOUNDS=1 - if [ "$BSECTION" = "$SECTION" -a "$BPNAME" = "$PNAME" ] ;then - b="$a" - rm -f "$1.lck" - fi - if [ "$BSECTION" != "$SECTION" -a "$FOUNDS" != "" -a -f "$1.lck" ] ;then - echo "$a" >> "$1.tmp" - rm -f "$1.lck" - fi - echo "$b" >> "$1.tmp" - done - [ -f "$1.lck" ] && echo "$a" >> "$1.tmp" - mv -f "$1.tmp" "$1" - rm -f "$1.lck" - done +# Remove user home directories. Used ubl-settings-usergroup +# $1 # Users name a comma separated list +remove_userhome(){ + local LIST_USERNAME="$@" + [[ ${LIST_USERNAME} != "" ]] || return 1 + while IFS= read -r SELECT_USERNAME; do + rm -rdf ${ROOTFS}/home/"${SELECT_USERNAME}" + done < <(tr ',;' '\n' <<< ${LIST_USERNAME}) } -# It include string from $2 ini file and apply to $1 ini file -# $1 - base file -# $2 - included file -function concatenate_ini(){ - [ -f "$1" -a -f "$2" ] || return 1 - ini2simple "$1" >"$1.tmp" - ini2simple "$2" >"$2.tmp" - apply2simple "$1.tmp" "$2.tmp" - simple2ini "$1.tmp" >"$1" - rm -f "$1.tmp" "$2.tmp" +# Convert plain passwords to a hash in the global configuration +# Конвертировать не шифрованные пароли в шифрованные для глобальных переменных USERADD GROUPADD DEFAULTPASSWD DEFAULTROOTPASSWD +# $1 # Параметр конфигурации, где содержится пароль который нужно конвертировать, если первые символы %%, то пароль останется не шифрованным +# Если запущенно без параметра, то все пароли зашифровать в переменных USERADD GROUPADD DEFAULTPASSWD DEFAULTROOTPASSWD +globalconf_convert_pass_plain_to_hash(){ + [[ -z ${ROOTFS} ]] || return 0 + SOURCE=${SYSCONF}/users; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null + SOURCE=${ROOTFS}/root/.ublinux/users; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null + local PARAM="$@" + local -A USERADD + local -A GROUPADD + local DEFAULTPASSWD + local DEFAULTROOTPASSWD + [[ -n ${HASHPASSWD} ]] || HASHPASSWD=$(/usr/bin/ubconfig --raw --default get users HASHPASSWD) + [[ -n ${HASHPASSWD} && ${HASHPASSWD} != "(null)" ]] || HASHPASSWD='yescrypt' + if [[ -n ${PARAM} ]]; then + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + # Проверим DEFAULTPASSWD, если не указан в $1, то подгрузить из глобальной конфигурации + [[ -n ${PARAM} ]] || DEFAULTPASSWD=$(ubconfig --raw --source global get [users] DEFAULTPASSWD) + if [[ -n ${DEFAULTPASSWD} && ${DEFAULTPASSWD} != "(null)" ]]; then + if [[ -n ${PARAM} && ${DEFAULTPASSWD} =~ ^'%%'(.*)$ ]]; then + ubconfig --noexecute --target global set [users] DEFAULTPASSWD="${BASH_REMATCH[1]}" + else + #return_hash_password "${DEFAULTPASSWD}" + #[[ -n ${HASH_PASSWORD_NEW} ]] && ubconfig --noexecute --target global set [users] DEFAULTPASSWD="${HASH_PASSWORD_NEW}" + ubconfig --noexecute --target global set [users] DEFAULTPASSWD="$(return_hash_password hash ${HASHPASSWD} ${DEFAULTPASSWD})" + fi + fi + # Проверим DEFAULTROOTPASSWD, если не указан в $1, то подгрузить из глобальной конфигурации + [[ -n ${PARAM} ]] || DEFAULTROOTPASSWD=$(ubconfig --raw --source global get [users] DEFAULTROOTPASSWD) + if [[ -n ${DEFAULTROOTPASSWD} && ${DEFAULTROOTPASSWD} != "(null)" ]]; then + if [[ -n ${PARAM} && ${DEFAULTROOTPASSWD} =~ ^'%%'(.*)$ ]]; then + ubconfig --noexecute --target global set [users] DEFAULTROOTPASSWD="${BASH_REMATCH[1]}" + else + #return_hash_password "${DEFAULTROOTPASSWD}" + #[[ -n ${HASH_PASSWORD_NEW} ]] && ubconfig --noexecute --target global set [users] DEFAULTROOTPASSWD="${HASH_PASSWORD_NEW}" + ubconfig --noexecute --target global set [users] DEFAULTROOTPASSWD="$(return_hash_password hash ${HASHPASSWD} ${DEFAULTROOTPASSWD})" + fi + fi + # Проверим USERADD, если не указан в $1, то подгрузить из глобальной конфигурации + [[ -n ${PARAM} ]] || while IFS= read -r SELECT_USERADD; do + if [[ ! ${SELECT_USERADD%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]]; then + VAR_NAME=${SELECT_USERADD%%=*} + VAR_VALUE=${SELECT_USERADD#*=}; VAR_VALUE=${VAR_VALUE//\'/} + eval "${VAR_NAME}=\${VAR_VALUE}" + fi + done < <(ubconfig --source global get [users] USERADD[*]) + if [[ ${#USERADD[@]} != 0 ]]; then + while IFS= read -u3 SELECT_USERNAME; do + IFS=: read -r SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS SELECT_OPTIONAL SELECT_PASSWORD NULL <<< "${USERADD[${SELECT_USERNAME}]}" + if [[ ${SELECT_PASSWORD} != "" ]]; then + if [[ -n ${PARAM} && ${SELECT_PASSWORD} =~ ^'%%'(.*)$ ]]; then + ubconfig --noexecute --target global set [users] USERADD[${SELECT_USERNAME}]="${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}:${BASH_REMATCH[1]}" + else + #return_hash_password "${SELECT_PASSWORD}" + #[[ -n ${HASH_PASSWORD_NEW} ]] && ubconfig --noexecute --target global set [users] USERADD[${SELECT_USERNAME}]="${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}:${HASH_PASSWORD_NEW}" + ubconfig --noexecute --target global set [users] USERADD[${SELECT_USERNAME}]="${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}:$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD})" + fi + fi + done 3< <(printf "%s\n" "${!USERADD[@]}") + fi + # Проверим GROUPADD, если не указан в $1, то подгрузить из глобальной конфигурации + [[ -n ${PARAM} ]] || while IFS= read -r SELECT_GROUPADD; do + if [[ ! ${SELECT_GROUPADD%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]]; then + VAR_NAME=${SELECT_GROUPADD%%=*} + VAR_VALUE=${SELECT_GROUPADD#*=}; VAR_VALUE=${VAR_VALUE//\'/} + eval "${VAR_NAME}=\${VAR_VALUE}" + fi + done < <(ubconfig --source global get [users] GROUPADD[*]) + if [[ ${#GROUPADD[@]} != 0 ]]; then + while IFS= read -u3 SELECT_GROUP; do + IFS=: read -r SELECT_USERS SELECT_GID SELECT_OPTIONAL SELECT_ADMINISTRATORS SELECT_PASSWORD NULL <<< "${GROUPADD[${SELECT_GROUP}]}" + if [[ ${SELECT_PASSWORD} != "" ]]; then + if [[ -n ${PARAM} && ${SELECT_PASSWORD} =~ ^'%%'(.*)$ ]]; then + ubconfig --noexecute --target global set [users] GROUPADD[${SELECT_GROUP}]="${SELECT_USERS}:${SELECT_GID}:${SELECT_OPTIONAL}:${SELECT_ADMINISTRATORS}:${BASH_REMATCH[1]}" + else + #return_hash_password "${SELECT_PASSWORD}" + #[[ -n ${HASH_PASSWORD_NEW} ]] && ubconfig --noexecute --target global set [users] GROUPADD[${SELECT_GROUP}]="${SELECT_USERS}:${SELECT_GID}:${SELECT_OPTIONAL}:${SELECT_ADMINISTRATORS}:${HASH_PASSWORD_NEW}" + ubconfig --noexecute --target global set [users] GROUPADD[${SELECT_GROUP}]="${SELECT_USERS}:${SELECT_GID}:${SELECT_OPTIONAL}:${SELECT_ADMINISTRATORS}:$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD})" + fi + fi + done 3< <(printf "%s\n" "${!GROUPADD[@]}") + fi } detectDE(){ @@ -126,7 +210,7 @@ debug_log(){ } log(){ - echo "$@" 2>/dev/null >>/var/log/ublinuxlog + echo "$@" 2>/dev/null >>/var/log/ublinux.log } debug_mode(){ @@ -227,7 +311,7 @@ allow_only_root(){ # Hotkeys functions # ##################### -notify-send(){ +notify_send(){ local FIND_DISPLAY=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)" local FIND_USER=$(who | grep '('${FIND_DISPLAY}')' | awk '{print $1}' | head -n 1) #' local FIND_UID=$(id -u ${FIND_USER}) @@ -416,4 +500,19 @@ screen_scale(){ fi } -[[ $(basename $0) == functions ]] && $@ || true +################ +##### 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 + while [[ $# -gt 0 ]]; do + declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" '${1}'" && shift; } + done + eval ${FUNCTION#*; } + fi + diff --git a/ublinux/rc.halt.pre/20-grub b/ublinux/rc.halt.pre/20-grub index 6f87001..774509a 100755 --- a/ublinux/rc.halt.pre/20-grub +++ b/ublinux/rc.halt.pre/20-grub @@ -13,8 +13,6 @@ SYSCONF="${ROOTFS}/${SYSCONF}" SOURCE=${SYSCONF}/config; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null SOURCE=${SYSCONF}/boot; [ -f ${SOURCE} ] && . ${SOURCE} 2>/dev/null -SELF_NAME="20-grub" - get_path_grub2(){ NAME_GRUB_CFG="grub.cfg" PATH_GRUB=$(find ${ROOTFS}/memory/data/from/*/boot/grub/ -maxdepth 1 -type f -name "${NAME_GRUB_CFG}" | head -1) @@ -162,21 +160,22 @@ exec_grub_cmdline_linux(){ ################ ##### MAIN ##### ################ - # Возможность подключить как source из любого скрипта и вызов встроенных функций + get_path_grub2 || exit 1 FILE_GRUB_VAR_USER="${PATH_GRUB}/ublinux/grub_var_user.cfg" [[ -f ${FILE_GRUB_VAR_USER} ]] || touch ${FILE_GRUB_VAR_USER} - if [[ ${0##*/} == ${SELF_NAME} && -z $@ ]]; then + # Если файл подключен как ресурс с функциями, то выйти + return 0 2>/dev/null && return 0 + if [[ -z $@ ]]; then while read -r FUNCTION; do $"${FUNCTION##* }" done < <(declare -F | grep "declare -f exec_") - elif [[ ${0##*/} == ${SELF_NAME} ]]; then + else while [[ $# -gt 0 ]]; do - declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" ${1}" && shift; } + declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" \"${1}\"" && shift; } done eval ${FUNCTION#*; } - else - true fi + diff --git a/ublinux/rc.halt.pre/25-accounts-sync b/ublinux/rc.halt.pre/25-accounts-sync new file mode 100755 index 0000000..43f2fed --- /dev/null +++ b/ublinux/rc.halt.pre/25-accounts-sync @@ -0,0 +1,124 @@ +#!/usr/bin/env bash + +ENABLED=yes +[[ ${ENABLED} == "yes" ]] || exit 0 +DEBUGMODE=no + +unset ROOTFS; [[ -d /usr/lib/ublinux ]] || 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 + +# Синхронизировать пользователе системы в глобальную конфигурацию USERADD и USERSHADOW +## Синхронизация пользователей системы /etc/passwd с глобальной конфигурацией +## USERADD_SYNC[user_name]='boot,shutdown' +## user_name # Имя пользователя, необязательное поле. Если не указано, то применяется для всех пользователей +## boot # При загрузке системы принудительно применить глобальную конфигурацию на пользователя +## shutdown # При завершении работы системы синхронизировать указанных пользователей в системе с глобальной конфигурацией +exec_useradd_sync(){ + FILE_PASSWD="${ROOTFS}/etc/passwd" + FILE_SHADOW="${ROOTFS}/etc/shadow" + sync_user(){ + local SELECT_USER="$1" + local SELECT_OPTIONAL= + local SELECT_EXTRAGROUPS= + [[ $(grep ^"${SELECT_USER}:" ${FILE_PASSWD}) =~ ^(.*):(.*):(.*):(.*):(.*):(.*):(.*)$ ]] \ + && SELECT_PLAINPASSWORD=${BASH_REMATCH[2]} \ + && SELECT_UID=${BASH_REMATCH[3]} \ + && SELECT_GROUP=${BASH_REMATCH[4]} \ + && SELECT_GECOS=${BASH_REMATCH[5]} \ + && SELECT_HOMEDIR=${BASH_REMATCH[6]} \ + && SELECT_SHELL=${BASH_REMATCH[7]} + + [[ $(grep ^"${SELECT_USER}:" ${FILE_SHADOW}) =~ ^(.*):(.*):(.*):(.*):(.*):(.*):(.*):(.*):(.*)$ ]] \ + && SELECT_PASSWORD=${BASH_REMATCH[2]} \ + && SELECT_LASTCHANGED=${BASH_REMATCH[3]} \ + && SELECT_MINDAY=${BASH_REMATCH[4]} \ + && SELECT_MAXDAY=${BASH_REMATCH[5]} \ + && SELECT_WARN=${BASH_REMATCH[6]} \ + && SELECT_INACTIVE=${BASH_REMATCH[7]} \ + && SELECT_EXPIRE=${BASH_REMATCH[8]} \ + && SELECT_NOUSE=${BASH_REMATCH[9]} + + [[ -n ${SELECT_LASTCHANGED} ]] && SELECT_LASTCHANGED=$(date -d @$((${SELECT_LASTCHANGED}*24*60*60)) +'%Y-%m-%d') + [[ -n ${SELECT_EXPIRE} ]] && SELECT_LASTCHANGED=$(date -d @$((${SELECT_EXPIRE}*24*60*60)) +'%Y-%m-%d') + while IFS= read -r EXTRAGROUP; do [[ "${USERGROUPS},nobody" =~ ${EXTRAGROUP} ]] || SELECT_EXTRAGROUPS+=",${EXTRAGROUP}"; done < <(tr ' ' '\n' <<< $(id -nrG ${SELECT_USER})) + SELECT_EXTRAGROUPS=${SELECT_EXTRAGROUPS:1} + [[ -n ${SELECT_HOMEDIR} && ${SELECT_HOMEDIR} != "/home/${SELECT_USER}" ]] && SELECT_OPTIONAL+=" --home-dir ${SELECT_HOMEDIR}" + [[ -n ${SELECT_SHELL} && ${SELECT_SHELL} != "/bin/bash" ]] && SELECT_OPTIONAL+=" --shell ${SELECT_SHELL}" + ${ROOTFS}/usr/bin/ubconfig --quiet --target global set [users] USERADD[${SELECT_USER}]="${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}:${SELECT_PASSWORD}" + ${ROOTFS}/usr/bin/ubconfig --quiet --target global set [users] USERSHADOW[${SELECT_USER}]="${SELECT_LASTCHANGED}:${SELECT_MINDAY}:${SELECT_MAXDAY}:${SELECT_WARN}:${SELECT_INACTIVE}:${SELECT_EXPIRE}" + } + if [[ ${USERADD_SYNC} =~ 'shutdown' ]]; then + # Все пользователи + UID_MIN=$([[ $(cat "${ROOTFS}/etc/login.defs") =~ [^#[^:space:]]*UID_MIN[[:space:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}") + while IFS= read -r SELECT_USER; do + sync_user "${SELECT_USER}" + done < <(awk -F':' -v USER_MIN=${UID_MIN} '$3 >= USER_MIN && $1 != "nobody" { print $1}' ${FILE_PASSWD}) + elif [[ ${#USERADD_SYNC[@]} != 0 ]]; then + while IFS= read -u3 SELECT_USER; do + [[ ${USERADD_SYNC[${SELECT_USER}]} =~ 'shutdown' ]] && sync_user ${SELECT_USER} + done 3< <(printf "%s\n" "${!USERADD_SYNC[@]}") + fi +} + +# Синхронизировать группы системы в глобальную конфигурацию GROUPADD +## Синхронизация группы системы /etc/groups и их параметры /etc/gshadow с глобальной конфигурацией +## GROUPADD_SYNC[group_name]='boot,shutdown' +## group_name # Имя группы, необязательное поле. Если не указано, то применяется для всех групп +## boot # При загрузке системы принудительно применить глобальную конфигурацию на группу +## shutdown # При завершении работы системы синхронизировать указанные группы в системе с глобальной конфигурацией +exec_groupadd_sync(){ + FILE_GROUP="${ROOTFS}/etc/group" + FILE_GSHADOW="${ROOTFS}/etc/gshadow" + sync_group(){ + local SELECT_GROUP="$1" + local SELECT_OPTIONAL= + [[ $(grep ^"${SELECT_GROUP}:" ${FILE_GROUP}) =~ ^(.*):(.*):(.*):(.*)$ ]] \ + && SELECT_GPASSWORD=${BASH_REMATCH[2]} \ + && SELECT_GID=${BASH_REMATCH[3]} \ + && SELECT_GUSERS=${BASH_REMATCH[4]} + + [[ $(grep ^"${SELECT_GROUP}:" ${FILE_GSHADOW}) =~ ^(.*):(.*):(.*):(.*)$ ]] \ + && SELECT_PASSWORD=${BASH_REMATCH[2]} \ + && SELECT_ADMINISTRATORS=${BASH_REMATCH[3]} \ + && SELECT_SUSERS=${BASH_REMATCH[4]} \ + + ${ROOTFS}/usr/bin/ubconfig --quiet --target global set [users] GROUPADD[${SELECT_GROUP}]="${SELECT_GUSERS}:${SELECT_GID}::${SELECT_ADMINISTRATORS}:${SELECT_PASSWORD}" + } + if [[ ${GROUPADD_SYNC} =~ 'shutdown' ]]; then + # Все группы + GID_MIN=$([[ $(cat "${ROOTFS}/etc/login.defs") =~ [^#[^:space:]]*GID_MIN[[:space:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}") + while IFS= read -r SELECT_GROUP; do + sync_group "${SELECT_GROUP}" + done < <(awk -F':' -v GROUP_MIN=${GID_MIN} '$3 >= GROUP_MIN && $1 != "nobody" { print $1}' ${FILE_GROUP}) + elif [[ ${#GROUPADD_SYNC[@]} != 0 ]]; then + while IFS= read -u3 SELECT_GROUP; do + [[ ${GROUPADD_SYNC[${SELECT_GROUP}]} =~ 'shutdown' ]] && sync_group ${SELECT_GROUP} + done 3< <(printf "%s\n" "${!GROUPADD_SYNC[@]}") + 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 + while [[ $# -gt 0 ]]; do + declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" \"${1}\"" && shift; } + done + eval ${FUNCTION#*; } + fi + diff --git a/ublinux/rc.local.d/20-pwgr_check b/ublinux/rc.local.d/20-pwgr_check new file mode 100755 index 0000000..1267754 --- /dev/null +++ b/ublinux/rc.local.d/20-pwgr_check @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +ENABLED=yes +[[ ${ENABLED} == "yes" ]] || exit 0 +DEBUGMODE=no + +. /usr/lib/ublinux/functions +. /usr/lib/ublinux/default +debug_mode "$0" "$@" + +SOURCE=${SYSCONF}/config; [ -f ${SOURCE} ] && . ${SOURCE} 2>/dev/null + +# Проверка файлов на ошибки /etc/passwd /etc/shadow /etc/group /etc/gshadow +exec_check_user_group(){ + local CHECK_MODE=$@ + [[ -z ${CHECK_MODE} ]] && CHECK_MODE="user,group" + if [[ ${CHECK_MODE} =~ "user" ]]; then + # Проверка файлов /etc/passwd /etc/shadow + if [[ -x /usr/bin/pwck ]]; then + # Сортировать файл passwd и shadow + /usr/bin/pwck -qs + # Вывести только предупреждение, если файл passwd или shadow повреждён + # /usr/bin/pwck -r + # Вывести предупреждение и исправить, если файл passwd или shadow повреждён + yes | /usr/bin/pwck -q + fi + fi + if [[ ${CHECK_MODE} =~ "group" ]]; then + # Проверка файлов /etc/group /etc/gshadow + if [[ -x /usr/bin/grpck ]]; then + # Сортировать файл group и gshadow + /usr/bin/grpck -qs + # Вывести предупреждение, если файл group или gshadow повреждён + # /usr/bin/grpck -r + # Вывести предупреждение и исправить, если файл group или gshadow повреждён + yes | /usr/bin/grpck -q + fi + 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 + while [[ $# -gt 0 ]]; do + declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" '${1}'" && shift; } + done + eval ${FUNCTION#*; } + fi diff --git a/ublinux/rc.preinit.d/20-services b/ublinux/rc.preinit.d/20-services index d8ff4fa..7b4f2ba 100755 --- a/ublinux/rc.preinit.d/20-services +++ b/ublinux/rc.preinit.d/20-services @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Initial script for UBLinux # This script are launching before starting init from initrd script @@ -40,7 +40,7 @@ exec_services_enabledisable(){ if [[ -n ${PARAM} ]]; then unset SERVICESSTART SERVICESNOSTART SERVICESMASK SERVICESUNMASK unset SERVICES_ENABLE SERVICES_DISABLE SERVICES_MASK SERVICES_UNMASK - eval "${PARAM%%=*}='${PARAM#*=}'" + eval "${PARAM%%=*}=\${PARAM#*=}" else SERVICESSTART_KERNEL=$(cmdline_value servicesstart) SERVICES_ENABLE_KERNEL=$(cmdline_value services_enable) @@ -59,26 +59,26 @@ exec_services_enabledisable(){ while IFS= read -ru3 SELECT_SERVICE; do [[ -n ${SELECT_SERVICE} ]] || continue if [[ -n ${ISSYSTEMD} ]]; then - ${CMD_CHROOT} systemctl --quiet unmask ${SELECT_SERVICE} + ${CMD_CHROOT} /usr/bin/systemctl --quiet unmask ${SELECT_SERVICE} fi done 3< <(tr ',; ' '\n' <<< "${SERVICESUNMASK},${SERVICESSTART},${SERVICES_UNMASK},${SERVICES_ENABLE}" | tr -s '\n') while IFS= read -ru3 SELECT_SERVICE; do [[ -n ${SELECT_SERVICE} ]] || continue if [[ -n ${ISSYSTEMD} ]]; then - ${CMD_CHROOT} systemctl --quiet enable ${SELECT_SERVICE} + ${CMD_CHROOT} /usr/bin/systemctl --quiet enable ${SELECT_SERVICE} fi done 3< <(tr ',; ' '\n' <<< "${SERVICESSTART},${SERVICES_ENABLE}" | tr -s '\n') while IFS= read -ru3 SELECT_SERVICE; do [[ -n ${SELECT_SERVICE} ]] || continue if [[ -n ${ISSYSTEMD} ]]; then - ${CMD_CHROOT} systemctl --quiet disable ${SELECT_SERVICE} + ${CMD_CHROOT} /usr/bin/systemctl --quiet disable ${SELECT_SERVICE} fi done 3< <(tr ',; ' '\n' <<< "${SERVICESNOSTART},${SERVICES_DISABLE}" | tr -s '\n') while IFS= read -ru3 SELECT_SERVICE; do [[ -n ${SELECT_SERVICE} ]] || continue if [[ -n ${ISSYSTEMD} ]]; then - ${CMD_CHROOT} systemctl --quiet disable ${SELECT_SERVICE} - ${CMD_CHROOT} systemctl --quiet mask ${SELECT_SERVICE} + ${CMD_CHROOT} /usr/bin/systemctl --quiet disable ${SELECT_SERVICE} + ${CMD_CHROOT} /usr/bin/systemctl --quiet mask ${SELECT_SERVICE} fi done 3< <(tr ',; ' '\n' <<< "${SERVICESMASK},${SERVICES_MASK}" | tr -s '\n') [[ -n ${ROOTFS} ]] && umount proc @@ -99,7 +99,7 @@ exec_services_startstop_live(){ if [[ -n ${PARAM} ]]; then unset SERVICESSTART SERVICESNOSTART SERVICESMASK SERVICESUNMASK unset SERVICES_ENABLE SERVICES_DISABLE SERVICES_MASK SERVICES_UNMASK - [[ ${PARAM%%=*} =~ [!\$%\&()*+,./:\;\<\=\>?\@\^\{|\}~-] ]] || eval "${PARAM%%=*}='${PARAM#*=}'" + [[ ${PARAM%%=*} =~ [!\$%\&()*+,./:\;\<\=\>?\@\^\{|\}~-] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" fi while IFS= read -ru3 SELECT_SERVICE; do [[ -n ${SELECT_SERVICE} ]] || continue @@ -136,7 +136,7 @@ exec_services_startstop_live(){ # if [[ -n ${PARAM} ]]; then # unset SERVICE # declare -A SERVICE -# eval "${PARAM%%=*}='${PARAM#*=}'" +# eval "${PARAM%%=*}=\${PARAM#*=}" # else # SERVICES_ENABLE_KERNEL=$(cmdline_value services_enable) # [[ -z ${SERVICES_ENABLE_KERNEL} ]] || while read -u3 SELECT_SERVICE; do @@ -159,21 +159,21 @@ exec_services_startstop_live(){ # [[ -n ${SELECT_SERVICE} ]] || continue # if [[ ${SERVICE[${SELECT_SERVICE}]} == @(start|enable|on) ]]; then # if [[ -n ${ISSYSTEMD} ]]; then -# echo ${CMD_CHROOT} systemctl --quiet unmask ${SELECT_SERVICE} -# echo ${CMD_CHROOT} systemctl --quiet enable ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet unmask ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet enable ${SELECT_SERVICE} # fi # elif [[ ${SERVICE[${SELECT_SERVICE}]} == @(stop|disable|off) ]]; then # if [[ -n ${ISSYSTEMD} ]]; then -# echo ${CMD_CHROOT} systemctl --quiet disable ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet disable ${SELECT_SERVICE} # fi # elif [[ ${SERVICE[${SELECT_SERVICE}]} == @(mask) ]]; then # if [[ -n ${ISSYSTEMD} ]]; then -# echo ${CMD_CHROOT} systemctl --quiet disable ${SELECT_SERVICE} -# echo ${CMD_CHROOT} systemctl --quiet mask ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet disable ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet mask ${SELECT_SERVICE} # fi # elif [[ ${SERVICE[${SELECT_SERVICE}]} == @(unmask) ]]; then # if [[ -n ${ISSYSTEMD} ]]; then -# echo ${CMD_CHROOT} systemctl --quiet unmask ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet unmask ${SELECT_SERVICE} # fi # fi # done 3< <(printf "%s\n" "${!SERVICE[@]}") @@ -194,18 +194,18 @@ exec_services_startstop_live(){ # [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && shift # local PARAM="$@" # if [[ -n ${PARAM} ]]; then -# unset SERVICE +# local SERVICE= # declare -A SERVICE -# [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~-] ]] || eval "${PARAM%%=*}='${PARAM#*=}'" +# [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~-] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" # fi # while read -u3 SELECT_SERVICE; do # if [[ ${SERVICE[${SELECT_SERVICE}]} == @(start|enable|on) ]]; then # if [[ -n ${ISSYSTEMD} ]]; then -# echo ${CMD_CHROOT} systemctl --quiet start ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet start ${SELECT_SERVICE} # fi # elif [[ ${SERVICE[${SELECT_SERVICE}]} == @(stop|disable|off) ]]; then # if [[ -n ${ISSYSTEMD} ]]; then -# echo ${CMD_CHROOT} systemctl --quiet stop ${SELECT_SERVICE} +# echo ${CMD_CHROOT} /usr/bin/systemctl --quiet stop ${SELECT_SERVICE} # fi # fi # done 3< <(printf "%s\n" "${!SERVICE[@]}") diff --git a/ublinux/rc.preinit.d/24-logging b/ublinux/rc.preinit.d/24-logging new file mode 100755 index 0000000..f2372db --- /dev/null +++ b/ublinux/rc.preinit.d/24-logging @@ -0,0 +1,287 @@ +#!/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 + +[[ -d /usr/lib/ublinux ]] && { unset ROOTFS; unset CMD_CHROOT; } || { ROOTFS="/sysroot"; 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}/logging; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null + +## Настройка мониторинга и сбора системных событий и записи их в журналы для аудита +## AUDITD=disable|no|none|off # Отключить все созданные правила из конфигурации +## AUDITD[]= +## # Уникальное имя правила +## # Правило +#AUDITD[event_chmod]="-a always,exit -F arch=x86_64 -S chmod,fchmod,fchmodat -F key=event_chmod" +#AUDITD[passwd_changes]="-w /etc/passwd -p wa -k passwd_changes" +exec_auditd(){ + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + FILE_PATTERN_AUDITD_CONF="${ROOTFS}/etc/audit/rules.d/00-ubconfig.rules" + local PARAM="$@" + if [[ -n ${PARAM} ]]; then + AUDITD_NAME=${PARAM%%=*} + AUDITD_VAR=${PARAM#*=} + fi + [[ -d ${FILE_PATTERN_AUDITD_CONF%/*} ]] || mkdir -p ${FILE_PATTERN_AUDITD_CONF%/*} + [[ -f ${FILE_PATTERN_AUDITD_CONF} ]] || true > "${FILE_PATTERN_AUDITD_CONF}" + if [[ -z ${PARAM} ]]; then + true > "${FILE_PATTERN_AUDITD_CONF}" + while IFS='=' read -u3 AUDITD_NAME AUDITD_VAR; do + [[ ${AUDITD_NAME} =~ ^.*'['(.*)']' ]] && AUDITD_NAME=${BASH_REMATCH[1]} + [[ ${AUDITD_VAR} =~ ^\"(.*)\"$ ]] && AUDITD_VAR=${BASH_REMATCH[1]} + echo "${AUDITD_VAR}" >> "${FILE_PATTERN_AUDITD_CONF}" + done 3< <(grep -E "^[[:space:]]*AUDITD\[" ${SYSCONF}/logging 2>/dev/null) + elif [[ ${COMMAND} == @("set="|"set+="|"set++=") ]]; then + [[ ${AUDITD_NAME} =~ ^.*'['(.*)']' ]] && AUDITD_NAME=${BASH_REMATCH[1]} + [[ ${AUDITD_VAR} =~ ^\"(.*)\"$ ]] && AUDITD_VAR=${BASH_REMATCH[1]} + echo "${AUDITD_VAR}" >> "${FILE_PATTERN_AUDITD_CONF}" + elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then + if [[ -n ${AUDITD_NAME} && ${AUDITD_VAR} != "" ]]; then + [[ ${AUDITD_NAME} =~ ^.*'['(.*)']' ]] && AUDITD_NAME=${BASH_REMATCH[1]} + AUDITD_VAR=${AUDITD[${AUDITD_NAME}]} + fi + [[ ${AUDITD_VAR} =~ ^\"(.*)\"$ ]] && AUDITD_VAR=${BASH_REMATCH[1]} + ESC_AUDITD_VAR=$(sed 's/[^a-zA-Z0-9,_@%-]/\\&/g' <<< "${AUDITD_VAR}") + sed "/^${ESC_AUDITD_VAR}$/d" -i "${FILE_PATTERN_AUDITD_CONF}" + fi +} + +exec_auditd_live(){ + [[ -z ${ROOTFS} ]] || return 0 + SERVICE_NAME="auditd.service" + if [[ $(pgrep -fc "exec_audit_live") == 1 ]]; then + if systemctl --quiet is-enabled ${SERVICE_NAME} 2>/dev/null; then + sleep 5 + systemctl --quiet reset-failed ${SERVICE_NAME} + systemctl --quiet restart ${SERVICE_NAME} 2>/dev/null + fi + fi +} + +## Настройка журналов +## https://www.freedesktop.org/software/systemd/man/journald.conf.html +## JOURNALD[]= +## # Имя переменной настройки журнала +## Storage # Указывает, где хранить журнал. Доступны следующие параметры: +## # "volatile" - Журнал хранится в оперативной памяти, т.е. в каталоге /run/log/journal +## # "persistent" - Данные хранятся на диске, т.е. в каталоге /var/log/journal +## # "auto" - используется по-умолчанию +## # "none" - Журнал не ведётся +## Compress # Пороговое значение данных для сжатия и записи в ФС. Может принимать yes, no, цифра. Суффиксы, такие как K, M и G +## SplitMode # Определяет, следует ли разделять файлы журнала для каждого пользователя: «uid» или «none» +## RateLimitIntervalSec # Настраивает ограничение скорости, которое применяется ко всем сообщениям, интервал времени применения =30 +## RateLimitBurst # Настраивает ограничение скорости, которое применяется ко всем сообщениям, лимит сообщений =10000 +## SystemMaxUse # Указывает максимальное дисковое пространство, которое может использовать журнал в постоянном хранилище +## SystemKeepFree # Указывает объем места, которое журнал должен оставить свободным при добавлении записей журнала в постоянное хранилище +## SystemMaxFileSize # Определяет, до какого размера могут вырасти отдельные файлы журнала в постоянном хранилище перед ротацией +## RuntimeMaxUse # Указывает максимальное дисковое пространство, которое можно использовать в энергозависимом хранилище (в файловой системе /run) +## RuntimeKeepFree # Указывает объем пространства, которое будет выделено для других целей при записи данных в энергозависимое хранилище (в файловой системе /run) +## RuntimeMaxFileSize # Указывает объем места, которое отдельный файл журнала может занимать в энергозависимом хранилище (в файловой системе /run) перед ротацией +## ForwardToConsole # Перенаправить журнал на консоль, yes|no +## TTYPath # Измените используемый консольный TTY, если используется ForwardToConsole=yes. По умолчанию /dev/console. +## MaxLevelConsole # Тип сообщений перенаправляемые в журнал, варианты: emerg|alert|crit|err|warning|notice|info|debug или целочисленные значения в диапазоне 0–7 +## # Значение переменной настройки журнала +#JOURNALD[Storage]=persistent +#JOURNALD[Compress]=yes +#JOURNALD[SystemMaxUse]=8M +#JOURNALD[RuntimeMaxUse]=8M +exec_journald(){ + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + FILE_JOURNALD_CONF="${ROOTFS}/etc/systemd/journald.conf.d/00-ubconfig.conf" + local PARAM="$@" + if [[ -n ${PARAM} ]]; then + local JOURNALD= + declare -A JOURNALD + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + [[ ! -f ${FILE_JOURNALD_CONF} ]] && mkdir -p "${FILE_JOURNALD_CONF%/*}" && touch ${FILE_JOURNALD_CONF} + [[ $(cat ${FILE_JOURNALD_CONF}) =~ "[Journal]" ]] || echo "[Journal]" > ${FILE_JOURNALD_CONF} + if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#JOURNALD[@]} != 0 ]]; then + while IFS= read -u3 NAME_VAR; do + if [[ $(cat ${FILE_JOURNALD_CONF}) =~ "${NAME_VAR}=" ]]; then + sed "s/^${NAME_VAR}=.*/${NAME_VAR}=${JOURNALD[${NAME_VAR}]}/g" -i ${FILE_JOURNALD_CONF} + else + echo "${NAME_VAR}=${JOURNALD[${NAME_VAR}]}" >> ${FILE_JOURNALD_CONF} + fi + done 3< <(printf "%s\n" "${!JOURNALD[@]}") + elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then + if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then + NAME_VAR=${BASH_REMATCH[1]} + sed "/${NAME_VAR}=/d" -i ${FILE_JOURNALD_CONF} + fi + fi +} + +exec_journald_live(){ + [[ -z ${ROOTFS} ]] || return 0 + SERVICE_NAME="systemd-journald.service" + if [[ $(pgrep -fc "exec_journald_live") == 1 ]]; then + sleep 5 + systemctl reset-failed ${SERVICE_NAME} + systemctl --quiet restart ${SERVICE_NAME} + fi +} + +## Настройка дампа ядра +## https://www.freedesktop.org/software/systemd/man/latest/systemd-coredump.html +## SYSTEMD_COREDUMP[]= +## # Имя переменной настройки журнала +## Storage # Указывает, где хранить дамп ядра. Доступны следующие параметры: +## journal # Дампы будут храниться в журнале и перезаписываться в соответствии со стандартными принципами ротации журналов +## external # Значение по умолчанию, дампы сохраняются в каталоге /var/lib/systemd/coredump/ +## none # Дампы ядра записываются (включая обратную трассировку, если возможно), но не сохраняются +## Compress # Используется для сжатия дампов ядра. Принимает логический аргумент - *yes или no +## *yes # Дампы сжимаются при сохранении (значение по умолчанию) +## no # Дампы сохраняются без сжатия. +## ProcessSizeMax # Максимальный размер дампа процесса, который может быть сохранен. Если размер дампа превышает значение этого параметра, то дамп сохранен не будет. Суфиксы: B +## # Параметры Storage=none и ProcessSizeMax=0 отключает всю обработку дампа памяти, за исключением записи журнала +## ExternalSizeMax # Максимальный (сжатый или несжатый) размер дампа процесса, который будет сохранен на диске +## JournalSizeMax # Максимальный (сжатый или несжатый) размер дампа процесса, который будет сохранен в журнале системы +## MaxUse # Максимальный объем общего дискового пространства, который может быть использован для хранения дампов процессов. Суфиксы: B,K,M,G,T,P,E +## KeepFree # Минимальный объем свободного дискового пространства, который должен оставаться на диске при хранении дампов. Суфиксы: B,K,M,G,T,P,E +## # Значение переменной настройки журнала +#SYSTEMD_COREDUMP[Storage]=none +#SYSTEMD_COREDUMP[ProcessSizeMax]=0 +exec_systemd_coredump(){ + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + FILE_SYSTEMD_COREDUMP_CONF="${ROOTFS}/etc/systemd/coredump.conf.d/00-ubconfig.conf" + local PARAM="$@" + if [[ -n ${PARAM} ]]; then + local SYSTEMD_COREDUMP= + declare -A SYSTEMD_COREDUMP + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + [[ ! -f ${FILE_SYSTEMD_COREDUMP_CONF} ]] && mkdir -p "${FILE_SYSTEMD_COREDUMP_CONF%/*}" && touch ${FILE_SYSTEMD_COREDUMP_CONF} + [[ $(cat ${FILE_SYSTEMD_COREDUMP_CONF}) =~ "[Coredump]" ]] || echo "[Coredump]" > ${FILE_SYSTEMD_COREDUMP_CONF} + if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#SYSTEMD_COREDUMP[@]} != 0 ]]; then + while IFS= read -u3 NAME_VAR; do + if [[ $(cat ${FILE_SYSTEMD_COREDUMP_CONF}) =~ "${NAME_VAR}=" ]]; then + sed "s/^${NAME_VAR}=.*/${NAME_VAR}=${SYSTEMD_COREDUMP[${NAME_VAR}]}/g" -i ${FILE_SYSTEMD_COREDUMP_CONF} + else + echo "${NAME_VAR}=${SYSTEMD_COREDUMP[${NAME_VAR}]}" >> ${FILE_SYSTEMD_COREDUMP_CONF} + fi + done 3< <(printf "%s\n" "${!SYSTEMD_COREDUMP[@]}") + elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then + if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then + NAME_VAR=${BASH_REMATCH[1]} + sed "/${NAME_VAR}=/d" -i ${FILE_SYSTEMD_COREDUMP_CONF} + fi + fi +} + +## Настройка ротации файлов логов утилитой logrotate +## https://man.archlinux.org/man/logrotate.conf.5 +## LOGROTATE[]=",,:,," +#LOGROTATE[samba]="/var/log/samba/log.smbd,/var/log/samba/log.nmbd,/var/log/samba/*.log:notifempty,missingok,copytruncate" +#LOGROTATE[chrony]="/var/log/chrony/*.log:missingok,nocreate,sharedscripts,postrotate,/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true,endscript" +#LOGROTATE[clamav]="/var/log/clamav/clamd.log,/var/log/clamav/freshclam.log,/var/log/clamav/clamav-milter.log:create 644 clamav clamav,sharedscripts,missingok,notifempty,postrotate,/bin/kill -HUP \`cat /run/clamav/clamd.pid 2>/dev/null\` 2> /dev/null || true,/bin/kill -HUP \`cat /run/clamav/freshclam.pid 2>/dev/null\` 2> /dev/null || true,/bin/kill -HUP \`cat /run/clamav/clamav-milter.pid 2>/dev/null\` 2> /dev/null || true,endscript" +exec_logrotate(){ + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + FILE_PATTERN_LOGROTATE_CONF="${ROOTFS}/etc/logrotate.d/ubconfig-" + local PARAM="$@" + if [[ -n ${PARAM} ]]; then + local LOGROTATE= + declare -A LOGROTATE + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + [[ -d ${FILE_PATTERN_LOGROTATE_CONF%/*} ]] || mkdir -p ${PATH_LOGROTATE_CONF%/*} + if [[ ${COMMAND} == "set=" ]] && [[ ${#LOGROTATE[@]} != 0 ]]; then + while IFS= read -u3 NAME_FILE; do + FILES_LOG="${LOGROTATE[${NAME_FILE}]%%:*}"; FILES_LOG="${FILES_LOG//,/ }" + RULES_LOG="${LOGROTATE[${NAME_FILE}]#*:}" + TAB_COUNT='\t' + # Вставляем список файлов логов + echo "${FILES_LOG} {" > "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + # Вставляем правила для вращения логов + while IFS= read -r SELECT_RULES_LOG; do + [[ ${SELECT_RULES_LOG} == "endscript" ]] && TAB_COUNT='\t' + echo -e "${TAB_COUNT}${SELECT_RULES_LOG}" >> "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + [[ ${SELECT_RULES_LOG} == "postrotate" ]] && TAB_COUNT='\t\t' + done < <(tr ',' '\n' <<< ${RULES_LOG}) + echo "}" >> "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + done 3< <(printf "%s\n" "${!LOGROTATE[@]}") + elif [[ ${COMMAND} == @("set+="|"set++=") ]] && [[ ${#LOGROTATE[@]} != 0 ]]; then + while IFS= read -u3 NAME_FILE; do + [[ -f ${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE} ]] || return 0 + FILES_LOG="${LOGROTATE[${NAME_FILE}]%%:*}" + RULES_LOG="${LOGROTATE[${NAME_FILE}]#*:}" + [[ ${FILES_LOG} == ${RULES_LOG} ]] && unset RULES_LOG + FILES_LOG="${FILES_LOG//,/ }" + # Вставить в список файлов последним + [[ -n ${FILES_LOG} ]] && ESC_FILES_LOG=$(sed 's/[^a-zA-Z0-9,_@%-]/\\&/g' <<< "${FILES_LOG}") + [[ -n ${FILES_LOG} ]] && [[ ! $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${FILES_LOG} ]] \ + && sed -E "0,/ \{/s/ \{/ ${ESC_FILES_LOG} \{/" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + # Вставить в список правил последним + [[ -n ${RULES_LOG} ]] && ESC_RULES_LOG=$(sed 's/[^a-zA-Z0-9,_@%-]/\\&/g' <<< "${RULES_LOG}") + [[ -n ${RULES_LOG} ]] && [[ ! $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${RULES_LOG} ]] \ + && sed -E "/^\}$/i\\\t${ESC_RULES_LOG}" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + done 3< <(printf "%s\n" "${!LOGROTATE[@]}") + elif [[ ${COMMAND} == @("set-="|"set--=") ]]; then + while IFS= read -u3 NAME_FILE; do + FILES_LOG="${LOGROTATE[${NAME_FILE}]%%:*}" + RULES_LOG="${LOGROTATE[${NAME_FILE}]#*:}" + [[ ${FILES_LOG} == ${RULES_LOG} ]] && unset RULES_LOG + FILES_LOG="${FILES_LOG//,/ }" + # Если удаляемая часть относится к файлу, то просто вырезать, если к тексту, то удалить строку + [[ -n ${FILES_LOG} ]] && ESC_FILES_LOG=$(sed 's/[^a-zA-Z0-9,_@%-]/\\&/g' <<< "${FILES_LOG}") + [[ -n ${FILES_LOG} ]] && [[ $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${FILES_LOG} ]] \ + && sed -E "0,/ \{/s/${ESC_FILES_LOG}//" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + [[ -n ${RULES_LOG} ]] && ESC_RULES_LOG=$(sed 's/[^a-zA-Z0-9,_@%-]/\\&/g' <<< "${RULES_LOG}") + [[ -n ${RULES_LOG} ]] && [[ $(cat "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}") =~ ${RULES_LOG} ]] \ + && sed "/${ESC_RULES_LOG}/d" -i "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + done 3< <(printf "%s\n" "${!LOGROTATE[@]}") + elif [[ ${COMMAND} == "remove" ]]; then + while IFS= read -u3 NAME_FILE; do + [[ -f ${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE} ]] || return 0 + rm -f "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + done 3< <(printf "%s\n" "${!LOGROTATE[@]}") + fi +} + +# Применить ротцию принудительно на указанный файл +# $1 # Имя переменной с файлом, пример: LOGROTATE[clamav] +exec_logrotate_live(){ + [[ -z ${ROOTFS} ]] || return 0 + NAME_FILE=$1 + [[ ${NAME_FILE%%=*} =~ ^.*'['(.*)']' ]] && NAME_FILE=${BASH_REMATCH[1]} + [[ -n ${NAME_FILE} ]] || return 0 + FILE_PATTERN_LOGROTATE_CONF="${ROOTFS}/etc/logrotate.d/ubconfig-" + if [[ $(pgrep -fc "exec_logrotate_live") == 1 ]]; then + sleep 2 + logrotate -f "${FILE_PATTERN_LOGROTATE_CONF}${NAME_FILE}" + 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 + while [[ $# -gt 0 ]]; do + declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" \"${1}\"" && shift; } + done + eval ${FUNCTION#*; } + fi diff --git a/ublinux/rc.preinit.d/40-authpam b/ublinux/rc.preinit.d/40-authpam index 97f39ec..8181e10 100755 --- a/ublinux/rc.preinit.d/40-authpam +++ b/ublinux/rc.preinit.d/40-authpam @@ -25,7 +25,7 @@ SOURCE=${SYSCONF}/system; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null # TODO: Сделать отработку по параметру загруженному, убрать парсинг AUTHPAM_PROFILE=$(grep -h '^AUTHPAM\[' ${ROOTFS}/usr/lib/ublinux/default ${ROOTFS}/etc/ublinux/system | tail -1 | sed -E 's/AUTHPAM\[([a-z]*)\].*/\1/') #' PROFILE_FEATURE=$(tr ',;' " " <<< ${AUTHPAM[${AUTHPAM_PROFILE}]}) - ${CMD_CHROOT} ${ROOTFS}/usr/bin/authselect select ${AUTHPAM_PROFILE} ${PROFILE_FEATURE} --force --nobackup --quiet + ${CMD_CHROOT} /usr/bin/authselect select ${AUTHPAM_PROFILE} ${PROFILE_FEATURE} --force --nobackup --quiet fi # if [[ -n ${AUTHPAM[@]} && ${AUTHPAM[@],,} != "disable" && ${AUTHPAM} != "-" && ${AUTHPAM,} != "no" && ${AUTHPAM,,} != "off" && ${SYSTEMBOOT_STATEMODE,,} =~ ^"sandbox" ]]; then diff --git a/ublinux/rc.preinit.d/51-autologin b/ublinux/rc.preinit.d/51-autologin index 1965e5d..c32ac5b 100755 --- a/ublinux/rc.preinit.d/51-autologin +++ b/ublinux/rc.preinit.d/51-autologin @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Initial script for UBLinux # This script are launching before starting init from initrd script @@ -18,18 +18,18 @@ 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}/desktop; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null AUTOLOGINUSER_CMDLINE=$(cmdline_value autologin) && [[ -n ${AUTOLOGINUSER_CMDLINE} ]] && AUTOLOGINUSER=${AUTOLOGINUSER_CMDLINE} if [[ -z ${AUTOLOGINUSER} ]]; then - PASS_ADMUID=$(grep "^$(grep ":${ADMUID}:${ADMUID}:" ${ROOTFS}/etc/passwd | cut -d: -f1):" ${ROOTFS}/etc/shadow | cut -d: -f2) #" + #PASS_ADMUID=$(grep "^$(grep ":${ADMUID}:${ADMUID}:" ${ROOTFS}/etc/passwd | cut -d: -f1):" ${ROOTFS}/etc/shadow | cut -d: -f2) #" #UID_MIN=$(grep "^UID_MIN" ${ROOTFS}/etc/login.defs | cut -d' ' -f2) - UID_MIN=$(read -d '' < "${ROOTFS}/etc/login.defs"; [[ "${REPLY}" =~ [^#[^:space:]]*UID_MIN[[:space:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}") - ONLY_ONE_USER=$(awk -F':' -v USER_MIN=${UID_MIN} '$3 > USER_MIN && $1 != "nobody" { print $1}' ${ROOTFS}/etc/passwd) - # Если в системе всего один пользователь и пароль пользователя = паролю по умолчанию = паролю по умолчанию рута ublinux, то автологин - [[ -z ${ONLY_ONE_USER} && ${PASS_ADMUID} == ${NOSECUREROOTPASSWD} && ${PASS_ADMUID} == ${DEFAULTPASSWD} ]] && AUTOLOGINUSER=yes + #UID_MIN=$(read -d '' < "${ROOTFS}/etc/login.defs"; [[ "${REPLY}" =~ [^#[^:space:]]*UID_MIN[[:space:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}") + UID_MIN=$([[ $(cat "${ROOTFS}/etc/login.defs") =~ [^#[^:space:]]*UID_MIN[[:space:]]+([[:digit:]]+) ]]; echo -n "${BASH_REMATCH[1]}") + MORE_ONE_USER=$(awk -F':' -v USER_MIN=${UID_MIN} '$3 > USER_MIN && $1 != "nobody" { print $1}' ${ROOTFS}/etc/passwd) + # Если в системе всего один пользователь и FIRSTSATART, то автологин + [[ -z ${MORE_ONE_USER} && -n ${FIRSTSTART} ]] && AUTOLOGINUSER=yes fi FILE_LIGHTDM_CONF="${ROOTFS}/etc/lightdm/lightdm.conf" @@ -70,8 +70,8 @@ SOURCE=${SYSCONF}/desktop; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null EOF AUTOLOGIN_IDGROUP=$(grep -i "g\s*autologin\s*[[:digit:]]\s*" ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers | cut -d: -f2 | xargs | cut -d " " -f3 | head -1) [[ -n ${AUTOLOGIN_IDGROUP} ]] && ARG_AUTOLOGIN_IDGROUP="-g ${AUTOLOGIN_IDGROUP}" - ${CMD_CHROOT} ${ROOTFS}/usr/bin/groupadd -f ${ARG_AUTOLOGIN_IDGROUP} autologin >/dev/null 2>&1 - ${CMD_CHROOT} ${ROOTFS}/usr/bin/gpasswd -M ${AUTOLOGINUSER} autologin >/dev/null 2>&1 + ${CMD_CHROOT} /usr/bin/groupadd -f ${ARG_AUTOLOGIN_IDGROUP} autologin >/dev/null 2>&1 + ${CMD_CHROOT} /usr/bin/gpasswd -M ${AUTOLOGINUSER} autologin >/dev/null 2>&1 fi fi diff --git a/ublinux/rc.preinit.d/90-apparmor b/ublinux/rc.preinit.d/90-apparmor index 9441de0..19970c2 100755 --- a/ublinux/rc.preinit.d/90-apparmor +++ b/ublinux/rc.preinit.d/90-apparmor @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Initial script for UBLinux # This script are launching before starting init from initrd script @@ -26,10 +26,10 @@ SERVICEAPPARMOR="apparmor.service" mkdir -p proc mount -o rbind /proc proc if readlink -fq ${ROOTFS}/usr/bin/init | grep -q "lib/systemd/systemd$"; then - ${CMD_CHROOT} ${ROOTFS}/usr/bin/systemctl unmask ${SERVICEAPPARMOR} - ${CMD_CHROOT} ${ROOTFS}/usr/bin/systemctl enable ${SERVICEAPPARMOR} || ${CMD_CHROOT} ${ROOTFS}/usr/bin/chkconfig --add ${SERVICEAPPARMOR} + ${CMD_CHROOT} /usr/bin/systemctl unmask ${SERVICEAPPARMOR} + ${CMD_CHROOT} /usr/bin/systemctl enable ${SERVICEAPPARMOR} || ${CMD_CHROOT} ${ROOTFS}/usr/bin/chkconfig --add ${SERVICEAPPARMOR} else - ${CMD_CHROOT} ${ROOTFS}/usr/bin/chkconfig --add ${SERVICEAPPARMOR} + ${CMD_CHROOT} /usr/bin/chkconfig --add ${SERVICEAPPARMOR} fi umount proc diff --git a/ublinux/rc.preinit/01-inifile b/ublinux/rc.preinit/01-inifile index 75a7843..07a053c 100755 --- a/ublinux/rc.preinit/01-inifile +++ b/ublinux/rc.preinit/01-inifile @@ -11,7 +11,7 @@ DEBUGMODE=no PATH=.:/:/usr/bin:/usr/local/bin:/usr/local/sbin -unset ROOTFS; [[ -d /usr/lib/ublinux ]] || ROOTFS=. +unset ROOTFS 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" "$@" @@ -19,43 +19,42 @@ debug_mode "$0" "$@" SYSCONF="${ROOTFS}${SYSCONF}" INIGZFILE=$(find /memory -maxdepth 1 -iname "*.ini.gz") + [[ -f ${INIGZFILE} ]] || INIGZFILE=$(find ${ROOTFS}/memory -maxdepth 1 -iname "*.ini.gz") [[ -f ${INIGZFILE} ]] || INIGZFILE=$(find /tmp -maxdepth 1 -iname "*.ini.gz") - [[ -f ${INIGZFILE} ]] || echo "Config file '*.ini.gz' not found!" + [[ -f ${INIGZFILE} ]] || { echo "Config file '*.ini.gz' not found!"; return 1; } [[ -d ${SYSCONF} ]] || mkdir -p "${SYSCONF}" rm -rf ${SYSCONF}/{..?*,.[!.]*,*} 2>/dev/null ## Парсим файл ublinux.ini.gz и создаём конфигурацию системы в ${SYSCONF} FILE_CONFIG="${SYSCONF}/config" - touch ${FILE_CONFIG} - zcat ${INIGZFILE} | grep -E '^DEFAULTPASSWD|^DEFAULTROOTPASSWD|^NEEDEDUSERS|^USERADD|^GROUPADD' > /tmp/.ublinux_accounts_credential + [[ -f ${FILE_CONFIG} ]] || install -Dm0644 /dev/null ${FILE_CONFIG} + FILE_ROOT_USERS="${SYSCONF}/.users_credential" + [[ -f ${FILE_ROOT_USERS} ]] || install -Dm0600 /dev/null ${FILE_ROOT_USERS} + zcat ${INIGZFILE} | grep -E '^DEFAULTPASSWD|^DEFAULTROOTPASSWD|^NEEDEDUSERS|^USERADD|^GROUPADD' > ${FILE_ROOT_USERS} while read LINE; do - if [[ ${LINE} =~ ^'['.*']' ]]; then - FILE_CONFIG=$(tr '[]' '|' <<< "${LINE}" | cut -d'|' -f2) - FILE_CONFIG_MOD=$(tr '[]' '|' <<< "${LINE}" | cut -d'|' -f3 | tr -d ' ') - PATH_FILE_CONFIG=${FILE_CONFIG%/*} + if [[ ${LINE} =~ ^'['([^[]*|[^]]*)']'[[:space:]]*([0-9]+|[augo]+[=+-]+[augorstwxX,=+-]*)?[[:space:]]*('['+(.*)']'+)?$ ]]; then + FILE_CONFIG=${BASH_REMATCH[1]} + FILE_CONFIG_MOD=${BASH_REMATCH[2]} + FILE_CONFIG_EXEC=${BASH_REMATCH[4]} # Если указан файл без пути, то добавить путь по умолчанию ${SYSCONF} - [[ ${PATH_FILE_CONFIG} =~ "/" ]] && FILE_CONFIG="${ROOTFS}${FILE_CONFIG}" || FILE_CONFIG="${SYSCONF}/${FILE_CONFIG}" - if [[ -n ${FILE_CONFIG_MOD} ]]; then - mkdir -p "${PATH_FILE_CONFIG}" - [[ -e ${FILE_CONFIG} ]] || touch "${FILE_CONFIG}" - chmod "${FILE_CONFIG_MOD}" "${FILE_CONFIG}" - fi + [[ ${FILE_CONFIG} =~ "/" ]] && FILE_CONFIG="${ROOTFS}/${FILE_CONFIG}" || FILE_CONFIG="${SYSCONF}/${FILE_CONFIG}" + if [[ -n ${FILE_CONFIG_MOD} ]]; then + [[ -d ${FILE_CONFIG%/*} ]] || install -d "${FILE_CONFIG%/*}" + [[ -e ${FILE_CONFIG} ]] || touch "${FILE_CONFIG}" + chmod "${FILE_CONFIG_MOD}" "${FILE_CONFIG}" + fi elif [[ ${LINE:0:1} == '-' ]]; then - sed -E "/^${LINE:1}$/d" -i "${FILE_CONFIG}" + [[ -e ${FILE_CONFIG} ]] && sed -E "/^${LINE:1}$/d" -i "${FILE_CONFIG}" elif [[ ${LINE:0:1} == '|' ]]; then echo "${LINE:1}" >> "${FILE_CONFIG}" elif [[ ${LINE:0:1} == '+' ]]; then - ESC_LINE_NEW=$(sed 's/[^a-zA-Z0-9,_@%]/\\&/g' <<< "${LINE:1}") - grep -Eq "^${ESC_LINE_NEW}$" "${FILE_CONFIG}" || echo "${LINE:1}" >> "${FILE_CONFIG}" + [[ $(cat "${FILE_CONFIG}" 2>/dev/null) =~ ($'\n'|^)+"${LINE:1}"($'\n'|$)+ ]] || echo "${LINE:1}" >> "${FILE_CONFIG}" else - NAME_VAR=$(cut -d= -f1 <<< "${LINE}") - [[ -z ${NAME_VAR} ]] && continue - ESC_NAME_VAR=$(sed 's/[^a-zA-Z0-9,_@%]/\\&/g' <<< "${NAME_VAR}") - [[ -f ${FILE_CONFIG} ]] \ - && grep -Eq "^\s*${ESC_NAME_VAR}=" "${FILE_CONFIG}" 2>/dev/null \ - && sed -E "/^\s*${ESC_NAME_VAR}=/d" -i "${FILE_CONFIG}" - echo "${LINE}" >> "${FILE_CONFIG}" + NAME_VAR=${LINE%%=*} + [[ ${LINE} != ${NAME_VAR} ]] || continue + [[ -f ${FILE_CONFIG} && $(cat -n ${FILE_CONFIG}) =~ ($'\n'|^)+[[:blank:]]*([[:digit:]]+)[[:blank:]]*"${NAME_VAR}="[^$'\n']*($'\n'|$)+ ]] && sed "${BASH_REMATCH[2]}d" -i "${FILE_CONFIG}" + echo "${LINE}" >> "${FILE_CONFIG}" fi done < <(zcat ${INIGZFILE} | grep -Ev '^DEFAULTPASSWD|^DEFAULTROOTPASSWD|^NEEDEDUSERS|^USERADD|^GROUPADD|^\s*#|^\s*$') @@ -64,4 +63,4 @@ SYSCONF="${ROOTFS}${SYSCONF}" grep -q "^declare -A" "${FILE_CONFIG}" 2>/dev/null && sed "/^declare -A/d" -i "${FILE_CONFIG}" DECLARE_A=$(grep -E "^[A-z0-9_]*\[.*\]=.*" "${FILE_CONFIG}" | sed -E "s/\[.*//" | sort -u | tr "\n" " ") [[ -z ${DECLARE_A} ]] || sed "1i declare -A ${DECLARE_A}" -i "${FILE_CONFIG}" - done < <(find ${SYSCONF} -type f -print) + done < <(find ${SYSCONF} -type f -print; echo "${FILE_ROOT_USERS}") diff --git a/ublinux/rc.preinit/03-initvars b/ublinux/rc.preinit/03-initvars index 4239421..bd9f0ef 100755 --- a/ublinux/rc.preinit/03-initvars +++ b/ublinux/rc.preinit/03-initvars @@ -11,7 +11,8 @@ DEBUGMODE=no PATH=.:/:/usr/bin:/usr/local/bin:/usr/local/sbin -[[ -d /usr/lib/ublinux ]] && { unset ROOTFS; unset CMD_CHROOT; } || { ROOTFS='.'; CMD_CHROOT='chroot . '; } +unset ROOTFS 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 debug_mode "$0" "$@" # Filter not variable sell symbols from param kernel diff --git a/ublinux/rc.preinit/10-accounts b/ublinux/rc.preinit/10-accounts index 071268a..b805f3f 100755 --- a/ublinux/rc.preinit/10-accounts +++ b/ublinux/rc.preinit/10-accounts @@ -11,187 +11,622 @@ DEBUGMODE=no PATH=.:/:/usr/bin:/usr/local/bin:/usr/local/sbin -[[ -d /usr/lib/ublinux ]] && { unset ROOTFS; unset CMD_CHROOT; } || { ROOTFS='.'; CMD_CHROOT='chroot . '; } +unset ROOTFS 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 +FILE_ROOT_USERS="${SYSCONF}/.users_credential" +SOURCE=${FILE_ROOT_USERS}; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null + FILE_PASSWD="${ROOTFS}/etc/passwd" FILE_SHADOW="${ROOTFS}/etc/shadow" FILE_GROUP="${ROOTFS}/etc/group" FILE_GSHADOW="${ROOTFS}/etc/gshadow" - FILE_ACCOUNTS_CREDENTIAL="/tmp/.ublinux_accounts_credential" - - # https://en.wikipedia.org/wiki/Crypt_(C) - # https://man.archlinux.org/man/core/libxcrypt/crypt.5.en # /etc/shadow file format - # user:$6$.n.:17736:0:99999:7::: - # [--] [----] [---] - [---] ---- - # | | | | | |||+-----------> 9. Неиспользованный - # | | | | | ||+------------> 8. Срок годности - # | | | | | |+-------------> 7. Период бездействия - # | | | | | +--------------> 6. Период предупреждения - # | | | | +------------------> 5. Максимальный возраст пароля - # | | | +----------------------> 4. Минимальный возраст пароля - # | | +--------------------------> 3. Последнее изменение пароля - # | +---------------------------------> 2. Зашифрованный пароль - # +----------------------------------------> 1. Имя пользователя - # Если поле пароля содержит первый символ звездочку (*), то пользователь не сможет войти по паролю, но сможет другим способом (например по ключу через ssh) - # Если поле пароля содержит первый символ восклицательный знак (!), то пользователь вообще не сможет войти, даже по ключу - # Алгоритмы хеширования пароля: - # (empty) # DES - # $_$ # BSDi - # $1$ # MD5 - # $2$ # bcrypt based on Blowfish - # $2a$ # Blowfish - # $2b$ # OpenBSD blowfish - # $2x$ # blowfish - # $2y$ # Eksblowfish - # $3$ # NTHASH - # $5$ # SHA-256 - # $6$ # SHA-512 - # $7$ # scrypt - # $md5$ # Solaris MD5 - # $sha1$ # PBKDF1 with SHA1 - # $gy$ # gost-yescrypt - # $y$ # yescrypt - # $argon2d$ # Argon2d - # $argon2i$ # Argon2i - # $argon2ds$ # Argon2ds - # $argon2id$ # Argon2id + PATH_HOME="/home" + +# Задать пароль пользователю +# $1 # Имя пользователя +# $2 # Зашифрованный пароля, если не указан, то пароль '!*' запрет авторизации set_passwd(){ USER_NAME="${1}" USER_PASS="${2}" - [[ -n ${USER_NAME} ]] || return 1 - [[ -n ${USER_PASS} ]] || USER_PASS="x" - ESC_USER_PASS=$(sed 's/[^a-zA-Z0-9,._@%-]/\\&/g' <<< "${USER_PASS}") - EPOCH_DAY=$(( $(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 - } - -copy_skel_home(){ - local SELECT_USERNAME="${1}" - [[ -n ${SELECT_USERNAME} ]] || return 1 - cp -af ${ROOTFS}/etc/skel ${ROOTFS}/home/"${SELECT_USERNAME}" - #rsync -rlpt --ignore-existing etc/skel/ home/"${SELECT_USERNAME}" - ${CMD_CHROOT} ${ROOTFS}/usr/bin/chown -R "${SELECT_USERNAME}":"${SELECT_USERNAME}" ${ROOTFS}/home/"${SELECT_USERNAME}" - ${CMD_CHROOT} ${ROOTFS}/usr/bin/chmod -fR u+rw,g-rwx,o-rwx ${ROOTFS}/home/"${SELECT_USERNAME}"/ - ${CMD_CHROOT} ${ROOTFS}/usr/bin/chmod -f 700 ${ROOTFS}/home/"${SELECT_USERNAME}" + [[ ${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=$(( $(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 } -exec_get_users(){ - if [[ -f ${FILE_ACCOUNTS_CREDENTIAL} ]]; then - GET_DEFAULTPASSWD=$(grep "DEFAULTPASSWD=" "${FILE_ACCOUNTS_CREDENTIAL}" | tail -1 | tr -d "\'\"") - [[ -n ${GET_DEFAULTPASSWD} ]] && DEFAULTPASSWD=${GET_DEFAULTPASSWD#*=} - GET_DEFAULTROOTPASSWD=$(grep "DEFAULTROOTPASSWD=" "${FILE_ACCOUNTS_CREDENTIAL}" | tail -1 | tr -d "\'\"") - [[ -n ${GET_DEFAULTROOTPASSWD} ]] && DEFAULTROOTPASSWD=${GET_DEFAULTROOTPASSWD#*=} - GET_NEEDEDUSERS=$(grep "NEEDEDUSERS=" "${FILE_ACCOUNTS_CREDENTIAL}" | tail -1 | tr -d "\'\"") - [[ -n ${GET_NEEDEDUSERS} ]] && NEEDEDUSERS=${GET_NEEDEDUSERS#*=} - rm -f "${FILE_ACCOUNTS_CREDENTIAL}" - fi - [[ -z ${NEEDEDUSERS} ]] && NEEDEDUSERS="${DEFAULTUSER}:${ADMUID}:${DEFAULTPASSWD}:Администратор" - [[ -z $(cmdline_value users) ]] || NEEDEDUSERS=$(cmdline_value users) - [[ ${NOSECUREROOTPASSWD} == ${DEFAULTROOTPASSWD} ]] && ADDADM=yes +# Задать пароль группе +# $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 # Основная группа пользователя, если не указана, то соответствует имени пользователя +# $3 # Если указано, то принудительно копировать /etc/skel в домашний каталог пользователя +create_home(){ + local SELECT_USERNAME="${1}" + local SELECT_GROUP="${2}" + local SELECT_FORCESKEL="${3}" + local ARG_RECURSIVE= + [[ ${SELECT_GROUP} == "" || ${SELECT_GROUP} == "-" ]] && SELECT_GROUP=${SELECT_USERNAME} + [[ ${SELECT_USERNAME} != "" ]] || return 1 + if [[ -d "${ROOTFS}${PATH_HOME}/${SELECT_USERNAME}" ]]; then + ${CMD_CHROOT} /usr/bin/chmod -f u+rw,g-rwx,o-rwx "${PATH_HOME}/${SELECT_USERNAME}" + [[ -z ${SELECT_FORCESKEL} ]] || cp -Taf ${ROOTFS}/etc/skel "${ROOTFS}${PATH_HOME}/${SELECT_USERNAME}" + else + install -dm700 "${ROOTFS}${PATH_HOME}/${SELECT_USERNAME}" + cp -Taf ${ROOTFS}/etc/skel "${ROOTFS}${PATH_HOME}/${SELECT_USERNAME}" + fi + #rsync -rlpt --ignore-existing etc/skel/ "${ROOTFS}${PATH_HOME}/${SELECT_USERNAME}" + [[ -n ${ROOTFS} ]] && ARG_RECURSIVE="-R" || unset ARG_RECURSIVE + ${CMD_CHROOT} /usr/bin/chown -f ${ARG_RECURSIVE} "${SELECT_USERNAME}" ${PATH_HOME}/"${SELECT_USERNAME}" + ${CMD_CHROOT} /usr/bin/chown -f ${ARG_RECURSIVE} :"${SELECT_GROUP}" "${PATH_HOME}/${SELECT_USERNAME}" } -exec_add_groups(){ - # Создаём группы из ${DEFAULTGROUP},${ADMGROUPS},${USERGROUPS} c ID из /usr/share/ublinux-sysusers/*.sysusers - while read SELECT_GROUP; do - FINDGROUP=$(grep -i "g\s*${SELECT_GROUP}\s*[[:digit:]]\s*" ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers 2>/dev/null | xargs) - IFS=" " read -r NULL FINDGROUP_NAME FINDGROUP_ID NULL <<< "${FINDGROUP}" - if [[ -n ${FINDGROUP} ]]; then - if grep -q "^${SELECT_GROUP}:.*:${FINDGROUP_ID}:" ${FILE_GROUP} 2>/dev/null; then + +# Создаём группы из ${DEFAULTGROUP},${ADMGROUPS},${USERGROUPS} c ID из /usr/share/ublinux-sysusers/*.sysusers +exec_01_add_groups(){ +#echo "exec_01_add_groups" + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + local PARAM="$@" + local GROUPADD_GROUPS SELECT_GROUP ARG_FINDGROUP_ID FINDGROUP_ID + if [[ -n ${PARAM} ]]; then + GROUPADD_GROUPS=${PARAM} + else + 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%*,} +#echo "==>::${GROUPADD_GROUPS}::" + [[ -n ${GROUPADD_GROUPS} ]] && while IFS= read -u3 SELECT_GROUP; do + unset ARG_FINDGROUP_ID +# FINDGROUP=$(grep -i "g\s*${SELECT_GROUP}\s*[[:digit:]]\s*" ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers 2>/dev/null | xargs) +# IFS=" " read -r NULL FINDGROUP_NAME FINDGROUP_ID NULL <<< "${FINDGROUP}" +# if [[ -n ${FINDGROUP} ]]; then +# if grep -q "^${SELECT_GROUP}:.*:${FINDGROUP_ID}:" ${FILE_GROUP} 2>/dev/null; then +# # Группа найдена, имя и id совпадают, пропускаем добавление +# continue +# elif grep -q "^${SELECT_GROUP}:" ${FILE_GROUP} 2>/dev/null; then +# # Группа найдена, имя и id несовпадают, удаляем группу +# 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}:${FINDGROUP_ID}'" +#echo ${CMD_CHROOT} /usr/bin/groupdel -f ${SELECT_GROUP} +# ${CMD_CHROOT} /usr/bin/groupdel -f ${SELECT_GROUP} +# fi +# fi +# [[ ${FINDGROUP_ID} == "" ]] || [[ ${FINDGROUP_ID} == "-" ]] || FINDGROUP_ID="--gid ${FINDGROUP_ID}" +#echo ${CMD_CHROOT} /usr/bin/groupadd --force ${FINDGROUP_ID} ${SELECT_GROUP} +## ${CMD_CHROOT} /usr/bin/groupadd --force ${FINDGROUP_ID} ${SELECT_GROUP} + + [[ $(cat ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers) =~ ($'\n'|^)+'g'[[:blank:]]+"${SELECT_GROUP}"[[:blank:]]+([[:digit:]]+)[^$'\n']*($'\n'|$)+ ]] && FINDGROUP_ID=${BASH_REMATCH[2]} || FINDGROUP_ID= + #[[ $(cat ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers) =~ ($'\n'|^)+'g'[[:blank:]]+([^$'\n']+)[[:blank:]]+"${SELECT_GROUP}"[^$'\n']*($'\n'|$)+ ]] && FINDGROUP_NAME=${BASH_REMATCH[2]} + if [[ ${FINDGROUP_ID} != "" && $(cat ${FILE_GROUP} 2>/dev/null) =~ ($'\n'|^)+${SELECT_GROUP}:[^$'\n']*:${FINDGROUP_ID}:[^$'\n']*($'\n'|$)+ ]]; then # Группа найдена, имя и id совпадают, пропускаем добавление - continue - elif grep -q "^${SELECT_GROUP}:" ${FILE_GROUP} 2>/dev/null; then - # Группа найдена, имя и id несовпадают, удаляем группу + continue + elif [[ ${FINDGROUP_ID} != "" && $(cat ${FILE_GROUP} 2>/dev/null) =~ ($'\n'|^)+${SELECT_GROUP}:[^$'\n']*($'\n'|$)+ ]]; then + # Группа найдена, имя и id не совпадают, удаляем группу 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}:${FINDGROUP_ID}'" - ${CMD_CHROOT} ${ROOTFS}/usr/bin/groupdel -f ${SELECT_GROUP} + ${CMD_CHROOT} /usr/bin/groupdel -f ${SELECT_GROUP} fi - fi - [[ ${FINDGROUP_ID} == "" ]] || [[ ${FINDGROUP_ID} == "-" ]] || FINDGROUP_ID="-g ${FINDGROUP_ID}" - ${CMD_CHROOT} ${ROOTFS}/usr/bin/groupadd -f ${FINDGROUP_ID} ${SELECT_GROUP} - done < <(tr ",;" "\n" <<< "${DEFAULTGROUP},${ADMGROUPS},${USERGROUPS}") + [[ ${FINDGROUP_ID} == @(""|"-") ]] || ARG_FINDGROUP_ID="--gid ${FINDGROUP_ID}" + ${CMD_CHROOT} /usr/bin/groupadd --force ${ARG_FINDGROUP_ID} ${SELECT_GROUP} + done 3<<< "${GROUPADD_GROUPS//,/$'\n'}" + fi } -exec_neededusers(){ - while read SELECT_USER; do - IFS=: read -r SELECT_USERNAME SELECT_UID SELECT_PASS SELECT_GECOS NULL <<< "${SELECT_USER}" - [[ ${SELECT_PASS} == "x" ]] && SELECT_PASS="${DEFAULTPASSWD}" - ADDGROUPS="${USERGROUPS}" - [[ ${SELECT_UID} == ${ADMUID} && ${ADDADM} == "yes" ]] && ADDGROUPS="${USERGROUPS},${ADMGROUPS}" - # Создаём пользователя - if ! grep -q ^"${SELECT_USERNAME}": ${FILE_PASSWD} 2>/dev/null; then - [[ -n ${SELECT_UID} ]] && ARG_SELECT_UID="-u ${SELECT_UID}" || unset ARG_SELECT_UID - [[ -n ${DEFAULTGROUP} ]] && ARG_DEFAULTGROUP="-G ${DEFAULTGROUP}" || unset ARG_DEFAULTGROUP - if [[ -x ${ROOTFS}/usr/bin/useradd ]]; then - [[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="-c ${SELECT_GECOS}" || unset ARG_SELECT_GECOS - ${CMD_CHROOT} ${ROOTFS}/usr/bin/useradd -M ${ARG_DEFAULTGROUP} ${ARG_SELECT_UID} ${ARG_SELECT_GECOS} ${SELECT_USERNAME} #>/dev/null 2>&1 - elif [[ -x ${ROOTFS}/usr/bin/adduser ]]; then - [[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="-g ${SELECT_GECOS}" || unset ARG_SELECT_GECOS - ${CMD_CHROOT} ${ROOTFS}/usr/bin/adduser -D -H "${ARG_DEFAULTGROUP}" "${ARG_SELECT_UID}" "${ARG_SELECT_GECOS}" "${SELECT_USERNAME}" >/dev/null 2>&1 +# Задаём пароль root пользователю +exec_02_defaultrootpasswd(){ +#echo "exec_02_defaultrootpasswd" + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + local PARAM="$@" + if [[ -n ${PARAM} ]]; then + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + # Удалить параметр из локальной конфигурации + [[ -z ${ROOTFS} && -f "${SYSCONF}/users" ]] && sed "/DEFAULTROOTPASSWD=/d" -i "${SYSCONF}/users" + if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ -n ${DEFAULTROOTPASSWD} && ! ${DEFAULTROOTPASSWD,,} == @(no|none|disable) ]]; then + [[ -n ${DEFAULTROOTPASSWD} ]] && DEFAULTROOTPASSWD=$(return_hash_password hash ${HASHPASSWD} ${DEFAULTROOTPASSWD}) + set_passwd root "${DEFAULTROOTPASSWD}" + fi +} + +# Создаем пользователей из ${NEEDEDUSERS} и добавляем в группы +# $1 Команды set или remove с режимом, варианты: set=|set+=|set++=|set-=|set--=|remove +# $2 Для команды set=|set+=|set++= параметр со значением, пример: +# Для команды set-=|set--=|remove параметр только с именем, пример: +# null Если отсутствует $@, то применяем из системной конфигурации +exec_03_neededusers(){ +#echo "exec_03_neededusers" + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || 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" + [[ -z $(cmdline_value users) ]] || NEEDEDUSERS=$(cmdline_value users) + [[ ${NOSECUREROOTPASSWD} == ${DEFAULTROOTPASSWD} ]] && ADDADM=yes + # Удалить параметр из локальной конфигурации + [[ -z ${ROOTFS} && -f "${SYSCONF}/users" ]] && sed "/NEEDEDUSERS=/d" -i "${SYSCONF}/users" + if [[ -n ${NEEDEDUSERS} ]]; then + while IFS= read -ru3 SELECT_USER; do + 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 - fi - # Добавляем пользователя в группу - USER_GROUPS="${ADDGROUPS//;/,}" - ${CMD_CHROOT} ${ROOTFS}/usr/bin/usermod -a -G ${USER_GROUPS%*,} ${SELECT_USERNAME} #>/dev/null 2>&1 - # Задаём пароль пользователю - set_passwd "${SELECT_USERNAME}" "${SELECT_PASS}" - # Создаём домашний каталог - if [[ ! -d ${ROOTFS}/home/"${SELECT_USERNAME}" ]]; then - copy_skel_home "${SELECT_USERNAME}" - elif [[ ${UPDATEHOME,,} == @(yes|y|enable) ]]; then - copy_skel_home "${SELECT_USERNAME}" - fi - done < <(tr ",;" "\n" <<< "${NEEDEDUSERS}") + # Создаём пользователя + if ! grep -q ^"${SELECT_USERNAME}": ${FILE_PASSWD} 2>/dev/null; then + [[ -n ${SELECT_UID} ]] && ARG_SELECT_UID="-u ${SELECT_UID}" || unset ARG_SELECT_UID + if [[ -x ${ROOTFS}/usr/bin/useradd ]]; then + [[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="-c ${SELECT_GECOS}" || unset ARG_SELECT_GECOS + [[ -n ${DEFAULTGROUP} ]] && ARG_DEFAULTGROUP="-G ${DEFAULTGROUP}" || unset ARG_DEFAULTGROUP + ${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}" || unset ARG_SELECT_GECOS + [[ -n ${SELECT_GROUP} ]] && ARG_SELECT_GROUP="-G ${SELECT_GROUP}" || ARG_SELECT_GROUP="-G ${SELECT_USERNAME}" + ${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}" + fi + # Создаём домашний каталог принудительно и копируем /etc/skel + if [[ ! -d ${ROOTFS}${PATH_HOME}/"${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 } -exec_set_root_pass(){ - if [[ -n ${DEFAULTROOTPASSWD} && ! ${DEFAULTROOTPASSWD} =~ @(no|none|disable) ]]; then - set_passwd root "${DEFAULTROOTPASSWD}" +#declare -A UPDATEHOME +#UPDATEHOME[user-4]=yes +#declare -A USERADD_SYNC +#USERADD_SYNC[user-4]="shutdown,boot" +#USERADD_SYNC="shutdown,boot" +#declare -A USERADD +#USERADD[superadmin]='Администратор:1000:x:x:x:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60' +#USERADD[user-1]='Пользователь-1:x:x:vboxusers,libvirt:-s /usr/bin/bash -o:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60' +#USERADD[user-2]='Пользователь-2::users:vboxusers,libvirt:-s /usr/bin/bash -o:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60' +#USERADD[user-3]=':::::x' +#USERADD[user-4]='Пользователь-4::users:user-2,user-3:-s /usr/bin/sh:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60' +#declare -A USERSHADOW +#USERSHADOW[user-4]=19695:0:99999:7:: +#USERSHADOW[user-4]=18000:0:120:7:14: +#USERSHADOW[user-4]="2023-12-31:0:120:7:14:2024-12-31" + +# Добавить пользователя системы в /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, использовать только совместно с параметром +## --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_04_useradd(){ +#echo "exec_04_useradd" + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + + [[ ${USERADD} != @(none|no|disable) ]] || return 0 + [[ -n ${USERADD_SYNC} ]] || declare -gA USERADD_SYNC + [[ -n ${UPDATEHOME} ]] || declare -gA UPDATEHOME + [[ -n ${USERADD} ]] || declare -gA USERADD + 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 PARAM="$@" + if [[ -n ${PARAM} ]]; then + local USERADD= + declare -A USERADD + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + [[ ${#USERADD[@]} == 0 ]] && USERADD[${DEFAULTUSER}]="Administrator:${ADMUID}:x:x:x:${DEFAULTPASSWD}" + # Если в GRUB указан параметр useradd, то создать пользователя + 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}:x:${SELECT_PASSWORD}" + done 3< <(tr ';' '\n' <<< $(cmdline_value useradd)) + # Удалить параметр из локальной конфигурации + [[ -z ${ROOTFS} && -f "${SYSCONF}/users" ]] && sed "/USERADD\[.*\]=/d" -i "${SYSCONF}/users" + if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#USERADD[@]} != 0 ]]; then + exec_06_groupadd + [[ ${NOSECUREROOTPASSWD} == ${DEFAULTROOTPASSWD} ]] && ADDADM=yes + while IFS= read -ru3 SELECT_USERNAME; do + IFS=: read -r SELECT_GECOS SELECT_UID SELECT_GROUP SELECT_EXTRAGROUPS SELECT_OPTIONAL SELECT_PASSWORD NULL <<< "${USERADD[${SELECT_USERNAME}]}" + [[ ${SELECT_GECOS,,} == "x" ]] && unset SELECT_GECOS + [[ ${SELECT_UID,,} == "x" || ${SELECT_UID} =~ ^[^0-9]+$ ]] && unset SELECT_UID + [[ ${SELECT_GROUP,,} == "x" ]] && unset SELECT_GROUP + [[ ${SELECT_EXTRAGROUPS,,} == "x" ]] && unset SELECT_EXTRAGROUPS + [[ ${SELECT_OPTIONAL,,} == "x" ]] && unset SELECT_OPTIONAL + [[ ${SELECT_PASSWORD} == @(""|"x") ]] && SELECT_PASSWORD="${DEFAULTPASSWD}" + [[ ${SELECT_PASSWORD} != @(""|'!*'|'!'|'*') ]] && SELECT_PASSWORD=$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD}) + # Если в дополнительных группа присутствует группа по имени пользователя, то удалить её из списка + SELECT_EXTRAGROUPS=${SELECT_EXTRAGROUPS//${SELECT_USERNAME}/} + # Создадать группы из параметра + [[ ${SELECT_EXTRAGROUPS} == "" ]] || exec_01_add_groups "${SELECT_EXTRAGROUPS}" + SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS},${USERGROUPS}" + [[ ${SELECT_UID} == ${ADMUID} && ${ADDADM} == "yes" ]] && SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS},${ADMGROUPS}" + SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS//;/,}"; SELECT_EXTRAGROUPS="${SELECT_EXTRAGROUPS//,,/,}" + [[ ${SELECT_EXTRAGROUPS:0:1} == "," ]] && SELECT_EXTRAGROUPS=${SELECT_EXTRAGROUPS:1} +#echo "===> ${SELECT_USERNAME}=${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}:${SELECT_PASSWORD}" +#echo "===> ${SELECT_USERNAME}=${SELECT_GECOS}:${SELECT_UID}:${SELECT_GROUP}:${SELECT_EXTRAGROUPS}:${SELECT_OPTIONAL}" + + # Если указана обязательная синхронизация при каждом запуске, то пользователя удалить и создать нового + 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}" 2>/dev/null + elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then + # busybox deluser + ${CMD_CHROOT} /usr/bin/busybox deluser ${SELECT_USERNAME} 2>/dev/null + fi + fi + # Проверяем наличие пользователя в системе + ARG_SELECT_UID=; ARG_SELECT_GROUP=; ARG_SELECT_GECOS=; ARG_SELECT_PASSWORD=; ARG_SELECT_OPTIONAL=; + if [[ ! $(cat ${FILE_PASSWD} 2>/dev/null) =~ ($'\n'|^)+"${SELECT_USERNAME}": ]]; then + [[ -n ${SELECT_UID} ]] && ARG_SELECT_UID="--uid ${SELECT_UID}" || unset ARG_SELECT_UID + + # Если указана основная группа, но она не создана, то создать + unset ARG_GROUPADD_GID ARG_GROUPADD_GROUPNAME + # Если группа не найдена + if [[ -n ${SELECT_GROUP} && ! $(cat ${FILE_GROUP}) =~ ($'\n'|^)+(${SELECT_GROUP}:|[^$'\n']*:${SELECT_GROUP}:) ]]; then + # Группа имет цифровой GID и номер GID=UID + if [[ ${SELECT_GROUP} =~ ^[[:digit:]]+$ && ${SELECT_GROUP} == ${SELECT_UID} ]]; then + #ARG_GROUPADD_GID=" --gid ${SELECT_GROUP}" + ARG_GROUPADD_GID="${SELECT_GROUP}" + ARG_GROUPADD_GROUPNAME=${SELECT_USERNAME} + elif [[ ${SELECT_GROUP} =~ ^[[:digit:]]+$ && ${SELECT_GROUP} != ${SELECT_UID} ]]; then + # Группа имет цифровой GID и номер GID!=UID + #ARG_GROUPADD_GID=" --gid ${SELECT_GROUP}" + ARG_GROUPADD_GID="${SELECT_GROUP}" + ARG_GROUPADD_GROUPNAME=${SELECT_USERNAME} + elif [[ ${SELECT_GROUP} =~ [[:alpha:]]+ ]]; then + # Группа имет буквенный GID + ARG_GROUPADD_GROUPNAME=${SELECT_USERNAME} + else + # Если группа не имеет цифры и буквы + unset SELECT_GROUP + fi + [[ -n ${ARG_GROUPADD_GROUPNAME} ]] && exec_06_groupadd "GROUPADD[${ARG_GROUPADD_GROUPNAME}]=x:${ARG_GROUPADD_GID}" + fi + # Создаём пользователя + if [[ -x ${ROOTFS}/usr/bin/useradd ]]; then + [[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="--comment ${SELECT_GECOS}" || unset ARG_SELECT_GECOS + [[ -n ${SELECT_GROUP} ]] && ARG_SELECT_GROUP="--gid ${SELECT_GROUP}" || unset ARG_SELECT_GROUP + [[ -n ${SELECT_PASSWORD} ]] && ARG_SELECT_PASSWORD="--password ${SELECT_PASSWORD}" || unset ARG_SELECT_PASSWORD + ARG_SELECT_OPTIONAL="${SELECT_OPTIONAL}" + [[ ${SELECT_OPTIONAL} =~ ("-M"|"--no-create-home") ]] || { [[ -d "${ROOTFS}${PATH_HOME}/${SELECT_USERNAME}" ]] || ARG_SELECT_OPTIONAL+=" --create-home"; } + [[ ${SELECT_OPTIONAL} =~ ("-N"|"--no-user-group") ]] || { [[ -z ${SELECT_GROUP} ]] && ARG_SELECT_OPTIONAL+=" --user-group"; } + ${CMD_CHROOT} /usr/bin/useradd ${ARG_SELECT_UID} ${ARG_SELECT_GROUP} ${ARG_SELECT_GECOS} ${ARG_SELECT_PASSWORD} ${ARG_SELECT_OPTIONAL} ${SELECT_USERNAME} #>/dev/null 2>&1 + elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then + # busybox adduser + [[ -n ${SELECT_GECOS} ]] && ARG_SELECT_GECOS="-g ${SELECT_GECOS}" || unset ARG_SELECT_GECOS + [[ -n ${SELECT_GROUP} ]] && ARG_SELECT_GROUP="-G ${SELECT_GROUP}" || ARG_SELECT_GROUP="-G ${SELECT_USERNAME}" + [[ ${SELECT_OPTIONAL} =~ ("-M"|"--no-create-home") ]] && ARG_SELECT_OPTIONAL+=" -H" + ${CMD_CHROOT} /usr/bin/busybox adduser -D ${ARG_SELECT_UID} ${ARG_SELECT_GROUP} ${ARG_SELECT_GECOS} ${ARG_SELECT_OPTIONAL} ${SELECT_USERNAME} #>/dev/null 2>&1 + # Задаём пароль пользователю + set_passwd "${SELECT_USERNAME}" "${SELECT_PASSWORD}" + fi + if [[ -x ${ROOTFS}/usr/bin/usermod ]]; then + # Добавляем пользователя в основную группу + #${CMD_CHROOT} /usr/bin/usermod -a -G ${SELECT_EXTRAGROUPS%*,} ${SELECT_USERNAME} #>/dev/null 2>&1 + # Добавляем пользователя в дополнительные группы + ${CMD_CHROOT} /usr/bin/usermod -a -G ${SELECT_EXTRAGROUPS%*,} ${SELECT_USERNAME} #>/dev/null 2>&1 + elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then + true + fi + # Задаём параметры пароля пользователю /etc/shadow из USERSHADOW[user]. Только если запущено отдельно с параметром. + [[ -n ${PARAM} && -n ${USERSHADOW[${SELECT_USERNAME}]} ]] && exec_05_usershadow "USERSHADOW[${SELECT_USERNAME}]=${USERSHADOW[${SELECT_USERNAME}]}" + # Проверим права на домашний каталог пользователя совпадают с указанным польователем, если нет, то переназначим + if [[ -d ${ROOTFS}${PATH_HOME}/${SELECT_USERNAME} && $(${CMD_CHROOT} /usr/bin/stat -c "%U:%G" ${PATH_HOME}/${SELECT_USERNAME}) != "${SELECT_USERNAME}:${SELECT_GROUP:-${SELECT_USERNAME}}" ]]; then + [[ -n ${ROOTFS} ]] && ARG_RECURSIVE="-R" || unset ARG_RECURSIVE + ${CMD_CHROOT} /usr/bin/chown -f ${ARG_RECURSIVE} "${SELECT_USERNAME}" ${PATH_HOME}/"${SELECT_USERNAME}" + ${CMD_CHROOT} /usr/bin/chown -f ${ARG_RECURSIVE} :"${SELECT_GROUP:-${SELECT_USERNAME}}" ${PATH_HOME}/"${SELECT_USERNAME}" + fi + fi + # Создаём домашний каталог принудительно и копируем /etc/skel + if [[ ${UPDATEHOME,,} == @(yes|y|enable) \ + || ${UPDATEHOME[${SELECT_USERNAME}],,} == @(yes|y|enable) ]]; then + create_home "${SELECT_USERNAME}" "${SELECT_GROUP}" force + fi + done 3< <(printf "%s\n" "${!USERADD[@]}") + elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then + if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then + SELECT_USERNAME=${BASH_REMATCH[1]} + ${CMD_CHROOT} /usr/bin/userdel --force ${SELECT_USERNAME} + fi fi } -exec_firststart(){ - # Autodetect firststart - # Если пароли по умолчанию, то firststart - if ! grep -q "^FIRSTSTART$" ${SYSCONF}/config 2>/dev/null; then - grep -q "^root:${DEFAULTROOTPASSWD}:" ${ROOTFS}/etc/shadow \ - && grep -q "^$(grep ".*:x:${ADMUID}:" ${ROOTFS}/etc/passwd | cut -d: -f1):${DEFAULTPASSWD}:" ${ROOTFS}/etc/shadow \ - && echo "FIRSTSTART=yes" >> ${SYSCONF}/config +# Параметры пользователя системы /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 +## # Если один из параметров не задан, содержит пустое значение, то исходное значение не изменяется +## # Конвертировать кол-во дней от эпохи в понятную дату: 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_05_usershadow(){ +#echo "exec_05_usershadow" + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + local SELECT_USERNAME SELECT_LASTCHANGED SELECT_MINDAY SELECT_MAXDAY SELECT_WARN SELECT_INACTIVE SELECT_EXPIRE NULL + local ARG_SELECT_LASTCHANGED ARG_SELECT_MINDAY ARG_SELECT_MAXDAY ARG_SELECT_WARN ARG_SELECT_INACTIVE ARG_SELECT_EXPIRE + local PARAM="$@" + if [[ -n ${PARAM} ]]; then + local USERSHADOW + declare -A USERSHADOW + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" + fi + if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#USERSHADOW[@]} != 0 ]]; then + while IFS= read -ru3 SELECT_USERNAME; do + IFS=: read -r SELECT_LASTCHANGED SELECT_MINDAY SELECT_MAXDAY SELECT_WARN SELECT_INACTIVE SELECT_EXPIRE NULL <<< "${USERSHADOW[${SELECT_USERNAME}]}" + # Получить из секунд от эпохи текущую дату: date -d @1705841503 + # Получить от эпохи количество дней: $(( $(date +%s)/(60*60*24) )). В дне 86400 секунд (60*60*24) + #[[ ${SELECT_LASTCHANGED} =~ ^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$ ]] && SELECT_LASTCHANGED_EPOH=$(date --date=${SELECT_LASTCHANGED} +"%s") + #[[ -z ${SELECT_LASTCHANGED_EPOH} && -x /bin/busybox && ${SELECT_LASTCHANGED} =~ ^[0-9]{4,4}'.'[0-9]{1,2}'.'[0-9]{1,2}$ ]] && SELECT_LASTCHANGED_EPOH=$(busybox date --date="${SELECT_LASTCHANGED//./}0000" +"%s") + #[[ -z ${SELECT_LASTCHANGED_EPOH} && -x ${ROOTFS}/usr/bin//date && ${SELECT_LASTCHANGED} =~ ^[0-9]{4,4}'.'[0-9]{1,2}'.'[0-9]{1,2}$ ]] && SELECT_LASTCHANGED_EPOH=$(${ROOTFS}/usr/bin/date --date="${SELECT_LASTCHANGED//./} 0000" +"%s") + #[[ -n ${SELECT_LASTCHANGED_EPOH} ]] && SELECT_LASTCHANGED=$(( ${SELECT_LASTCHANGED_EPOH}/(60*60*24) )) + #[[ ${SELECT_LASTCHANGED,,} == @(""|"x") || ${SELECT_LASTCHANGED} =~ ^[^0-9]*$ || ! ${SELECT_LASTCHANGED} =~ ^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$ ]] && unset SELECT_LASTCHANGED + [[ ${SELECT_LASTCHANGED} =~ (^[0-9]*$|^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$) ]] || unset SELECT_LASTCHANGED + [[ ${SELECT_MINDAY} =~ ^[0-9]*$ ]] || unset SELECT_MINDAY + [[ ${SELECT_MAXDAY} =~ ^[0-9]*$ ]] || unset SELECT_MAXDAY + [[ ${SELECT_WARN} =~ ^[0-9]*$ ]] || unset SELECT_WARN + [[ ${SELECT_INACTIVE} =~ ^[0-9]*$ ]] || unset SELECT_INACTIVE + #[[ ${SELECT_EXPIRE} =~ ^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$ ]] && SELECT_EXPIRE_EPOH=$(date --date=${SELECT_EXPIRE} +"%s") + #[[ -z ${SELECT_EXPIRE_EPOH} && -x /bin/busybox && ${SELECT_EXPIRE} =~ ^[0-9]{4,4}'.'[0-9]{1,2}'.'[0-9]{1,2}$ ]] && SELECT_EXPIRE_EPOH=$(busybox date --date="${SELECT_EXPIRE//./}0000" +"%s") + #[[ -z ${SELECT_EXPIRE_EPOH} && -x ${ROOTFS}/usr/bin/date && ${SELECT_EXPIRE} =~ ^[0-9]{4,4}'.'[0-9]{1,2}'.'[0-9]{1,2}$ ]] && SELECT_EXPIRE_EPOH=$(${ROOTFS}/usr/bin/date --date="${SELECT_EXPIRE//./} 0000" +"%s") + #[[ -n ${SELECT_EXPIRE_EPOH} ]] && SELECT_EXPIRE=$(( ${SELECT_EXPIRE_EPOH}/(60*60*24) )) + [[ ${SELECT_EXPIRE} =~ (^[0-9]*$|^[0-9]{4,4}'-'[0-9]{1,2}'-'[0-9]{1,2}$) ]] || unset SELECT_EXPIRE + [[ -n ${SELECT_LASTCHANGED} ]] && ARG_SELECT_LASTCHANGED="--lastday ${SELECT_LASTCHANGED}" || unset ARG_SELECT_LASTCHANGED + [[ -n ${SELECT_MINDAY} ]] && ARG_SELECT_MINDAY="--mindays ${SELECT_MINDAY}" || unset ARG_SELECT_MINDAY + [[ -n ${SELECT_MAXDAY} ]] && ARG_SELECT_MAXDAY="--maxdays ${SELECT_MAXDAY}" || unset ARG_SELECT_MAXDAY + [[ -n ${SELECT_WARN} ]] && ARG_SELECT_WARN="--warndays ${SELECT_WARN}" || unset ARG_SELECT_WARN + [[ -n ${SELECT_INACTIVE} ]] && ARG_SELECT_INACTIVE="--inactive ${SELECT_INACTIVE}" || unset ARG_SELECT_INACTIVE + [[ -n ${SELECT_EXPIRE} ]] && ARG_SELECT_EXPIRE="--expiredate ${SELECT_EXPIRE}" || unset ARG_SELECT_EXPIRE + # Задаём параметры пароля пользователя + if [[ -x ${ROOTFS}/usr/bin/chage ]]; then + ${CMD_CHROOT} /usr/bin/chage ${ARG_SELECT_LASTCHANGED} ${ARG_SELECT_MINDAY} ${ARG_SELECT_MAXDAY} ${ARG_SELECT_WARN} ${ARG_SELECT_INACTIVE} ${ARG_SELECT_EXPIRE} "${SELECT_USERNAME}" #>/dev/null 2>&1 + fi + done 3< <(printf "%s\n" "${!USERSHADOW[@]}") + elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then + if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then + SELECT_USERNAME=${BASH_REMATCH[1]} + ${CMD_CHROOT} /usr/bin/chage --mindays 0 --maxdays 99999 --warndays 7 --inactive -1 --expiredate -1 ${SELECT_USERNAME} + fi fi } -exec_verify_passwd(){ - if [[ -x ${ROOTFS}/usr/bin/pwck ]]; then - #yes | ${ROOTFS}/usr/bin/pwck --root ${PWD} > /dev/null - ${ROOTFS}/usr/bin/pwck -s --root ${PWD} +# Функция добавление/удаление групп в систему. Если группа существует, то изменить под параметры +# $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 группы, если необходимо автоматически рассчитывать, то оставить пустым или 'x' +## 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:x:superadmin:$6$E7stRhRS8fCKk7UU$Qoqw62AUaUa5uLIc2KC7WV3MUThhrR8kjXtCODmnKCzKe2zHu1/wmsiWBHZEIk/IQnk/aELQYbUK93OUtrwg60' +exec_06_groupadd(){ +#echo "exec_06_groupadd" + [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && COMMAND=$1 && shift + [[ -n ${COMMAND} ]] || COMMAND="set=" + local PARAM="$@" + 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 + if [[ -n ${PARAM} ]]; then + local GROUPADD= + declare -A GROUPADD + [[ ${PARAM%%=*} =~ [!\$%\&()*+,/\;\<\=\>?\^\{|\}~] ]] || eval "${PARAM%%=*}=\${PARAM#*=}" fi - if [[ -x ${ROOTFS}/usr/bin/grpck ]]; then - #yes | ${ROOTFS}/usr/bin/grpck --root ${PWD} > /dev/null - ${ROOTFS}/usr/bin/grpck -s --root ${PWD} + # Удалить параметр из локальной конфигурации + [[ -z ${ROOTFS} && -f "${SYSCONF}/users" ]] && sed "/GROUPADD\[.*\]/d" -i "${SYSCONF}/users" + if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#GROUPADD[@]} != 0 ]]; then + while IFS= read -ru3 SELECT_GROUP; do + IFS=: read -r SELECT_USERS SELECT_GID SELECT_OPTIONAL SELECT_ADMINISTRATORS SELECT_PASSWORD NULL <<< "${GROUPADD[${SELECT_GROUP}]}" + [[ ${SELECT_USERS} == "x" ]] && unset SELECT_USERS + [[ ${SELECT_GID,,} == "x" || ${SELECT_GID} =~ ^[^0-9]*$ ]] && unset SELECT_GID +#echo "==> ${SELECT_GROUP}:${SELECT_USERS}:${SELECT_GID}:${SELECT_OPTIONAL}:${SELECT_ADMINISTRATORS}:${SELECT_PASSWORD}" + [[ ${SELECT_OPTIONAL} == "x" ]] && unset SELECT_OPTIONAL + [[ ${SELECT_PASSWORD} == @(""|"x") ]] && unset SELECT_PASSWORD + [[ ${SELECT_PASSWORD} != @(""|'!*'|'!'|'*') ]] && SELECT_PASSWORD=$(return_hash_password hash ${HASHPASSWD} ${SELECT_PASSWORD}) + # Поиск имени и GID в шаблонах пользователей/групп systemd + [[ $(cat ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers) =~ ($'\n'|^)+'g'[[:blank:]]+"${SELECT_GROUP}"[[:blank:]]+([[:digit:]]+)[^$'\n']*($'\n'|$)+ ]] && FINDGROUP_ID=${BASH_REMATCH[2]} || unset FINDGROUP_ID + [[ -z ${FINDGROUP_ID} ]] \ + && [[ $(cat ${ROOTFS}/usr/share/ublinux-sysusers/*.sysusers) =~ ($'\n'|^)+'g'[[:blank:]]+([^$'\n']+)[[:blank:]]+"${SELECT_GROUP}"[^$'\n']*($'\n'|$)+ ]] && FINDGROUP_NAME=${BASH_REMATCH[2]} || unset FINDGROUP_NAME + [[ -n ${FINDGROUP_ID} ]] && SELECT_GID="${FINDGROUP_ID}" + [[ -n ${FINDGROUP_NAME} ]] && SELECT_GID="${FINDGROUP_NAME}" + DATA_FILE_GROUP=$(cat ${FILE_GROUP} 2>/dev/null) + # Добавляем аргументы к опциям, при условии что такого GID не существует + [[ -n ${SELECT_GID} ]] && [[ ! ${DATA_FILE_GROUP} =~ :${SELECT_GID}: ]] && ARG_SELECT_GID="--gid ${SELECT_GID}" || unset ARG_SELECT_GID + #[[ -n ${SELECT_USERS} ]] && ARG_SELECT_USERS="--users ${SELECT_USERS}" || unset ARG_SELECT_USERS + [[ -n ${SELECT_PASSWORD} ]] && ARG_SELECT_PASSWORD="--password ${SELECT_PASSWORD}" || unset ARG_SELECT_PASSWORD + # Создаём группу, если создана то изменяем под установленные параметры + if [[ ! ${DATA_FILE_GROUP} =~ ($'\n'|^)+${SELECT_GROUP}: ]]; then + if [[ -x ${ROOTFS}/usr/bin/groupadd ]]; then + #${CMD_CHROOT} /usr/bin/groupadd --force ${ARG_SELECT_USERS} ${ARG_SELECT_GID} ${SELECT_OPTIONAL} ${ARG_SELECT_PASSWORD} ${SELECT_GROUP} + ${CMD_CHROOT} /usr/bin/groupadd --force ${ARG_SELECT_GID} ${SELECT_OPTIONAL} ${ARG_SELECT_PASSWORD} ${SELECT_GROUP} + elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then + true + # Задаём пароль группе + # set_gpasswd "${SELECT_GROUP}" "${SELECT_PASSWORD}" + fi + elif [[ -n ${ARG_SELECT_GID} ]]; then + if [[ -x ${ROOTFS}/usr/bin/groupmod ]]; then + # т.к. groupmod принимет не все возможные аргументы совместимы с groupadd, то фильтруем + [[ ${SELECT_OPTIONAL} =~ ("--non-unique"|"-o") ]] && ARG_NON_UNIQUE="--non-unique" || unset ARG_NON_UNIQUE + [[ -n ${SELECT_PASSWORD} ]] && ARG_SELECT_PASSWORD="--password ${SELECT_PASSWORD}" || unset ARG_SELECT_PASSWORD + #${CMD_CHROOT} /usr/bin/groupmod --append ${ARG_SELECT_USERS} ${ARG_SELECT_GID} ${ARG_NON_UNIQUE} ${ARG_SELECT_PASSWORD} ${SELECT_GROUP} + ${CMD_CHROOT} /usr/bin/groupmod ${ARG_SELECT_GID} ${ARG_NON_UNIQUE} ${ARG_SELECT_PASSWORD} ${SELECT_GROUP} + elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then + true + # Задаём пароль группе + # set_gpasswd "${SELECT_GROUP}" "${SELECT_PASSWORD}" + fi + fi + DATA_FILE_PASSWD=$(cat ${FILE_PASSWD} 2>/dev/null) + unset REAL_SELECT_USERS REAL_SELECT_ADMINISTRATORS + # Если пользователь не существуют то убрать из списка SELECT_USERS + while IFS= read -r READ_SELECT_USERS; do + [[ ${DATA_FILE_PASSWD} =~ ($'\n'|^)+${READ_SELECT_USERS}: ]] && REAL_SELECT_USERS+=",${READ_SELECT_USERS}" + done <<< ${SELECT_USERS//,/$'\n'} + [[ ${REAL_SELECT_USERS:0:1} == "," ]] && REAL_SELECT_USERS=${REAL_SELECT_USERS:1} + [[ ${REAL_SELECT_USERS} != "" ]] && SELECT_USERS=${REAL_SELECT_USERS} || unset SELECT_USERS + # Если пользователь не существуют то убрать из списка REAL_SELECT_ADMINISTRATORS + while IFS= read -r READ_SELECT_ADMINISTRATORS; do + [[ ${DATA_FILE_PASSWD} =~ ($'\n'|^)+${READ_SELECT_ADMINISTRATORS}: ]] && REAL_SELECT_ADMINISTRATORS+=",${READ_SELECT_ADMINISTRATORS}" + done <<< ${SELECT_ADMINISTRATORS//,/$'\n'} + [[ ${REAL_SELECT_ADMINISTRATORS:0:1} == "," ]] && REAL_SELECT_ADMINISTRATORS=${REAL_SELECT_ADMINISTRATORS:1} + [[ ${REAL_SELECT_ADMINISTRATORS} != "" ]] && SELECT_ADMINISTRATORS=${REAL_SELECT_ADMINISTRATORS} || unset SELECT_ADMINISTRATORS + # Добавляем пользователей в группу, т.к. groupadd не добавил пользователей в /etc/shadow + if [[ -n ${SELECT_USERS} || -n ${SELECT_ADMINISTRATORS} ]]; then + if [[ -x ${ROOTFS}/usr/bin/gpasswd ]]; then + [[ -n ${SELECT_USERS} ]] && ARG_SELECT_USERS="-M ${SELECT_USERS}" || unset ARG_SELECT_USERS + [[ -n ${SELECT_ADMINISTRATORS} ]] && ARG_SELECT_ADMINISTRATORS="-A ${SELECT_ADMINISTRATORS}" || unset ARG_SELECT_ADMINISTRATORS + ${CMD_CHROOT} /usr/bin/gpasswd ${ARG_SELECT_ADMINISTRATORS} ${ARG_SELECT_USERS} ${SELECT_GROUP} #>/dev/null 2>&1 + elif [[ -x ${ROOTFS}/usr/bin/busybox ]]; then + true + fi + fi + done 3< <(printf "%s\n" "${!GROUPADD[@]}") + # Выполнить отдельно только если указан параметр функции + elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then + if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' ]]; then + SELECT_GROUP=${BASH_REMATCH[1]} + ${CMD_CHROOT} /usr/bin/groupdel --force ${SELECT_GROUP} + fi + fi +} + +# Autodetect firststart +# Если пароли по умолчанию, то firststart +exec_99_firststart(){ +#echo "exec_99_firststart" + if grep -q "^root:${DEFAULTROOTPASSWD}:" ${ROOTFS}/etc/shadow \ + && grep -q "^$(grep ".*:x:${ADMUID}:" ${ROOTFS}/etc/passwd | cut -d: -f1):${DEFAULTPASSWD}:" ${ROOTFS}/etc/shadow; then + grep -q "^FIRSTSTART$" ${SYSCONF}/config 2>/dev/null || echo "FIRSTSTART=yes" >> ${SYSCONF}/config fi } + ################ ##### MAIN ##### ################ - exec_get_users - exec_add_groups - exec_neededusers $@ - exec_set_root_pass - exec_firststart - exec_verify_passwd + # Если файл подключен как ресурс с функциями, то выйти + return 0 2>/dev/null && return 0 + #rm -f "${FILE_ROOT_USERS}" + if [[ -z $@ ]]; then + while read -ru3 FUNCTION; do + $"${FUNCTION##* }" + done 3< <(declare -F | grep "declare -f exec_") + else + while [[ $# -gt 0 ]]; do + declare -f ${1} &>/dev/null && FUNCTION+="; ${1}" && shift || { FUNCTION+=" '${1}'" && shift; } + done + eval ${FUNCTION#*; } + fi diff --git a/ublinux/templates/ublinux-data.ini b/ublinux/templates/ublinux-data.ini index ff650e9..0b0d64e 100644 --- a/ublinux/templates/ublinux-data.ini +++ b/ublinux/templates/ublinux-data.ini @@ -186,7 +186,7 @@ SERVICES_ENABLE=dbus-broker,NetworkManager,sshd,systemd-swap,cups,cockpit.socket ## You can cpecify users there whithout using "user=" boot parameter ## Пользователи системы (аналог параметра users) ## NEEDEDUSERS='name_user:id:password:show_name:, ... ' password=x=$DEFAULTPASSWD -NEEDEDUSERS='superadmin:1000:x:Администратор' +#NEEDEDUSERS='superadmin:1000:x:Администратор' ## Добавить пользователя системы в /etc/passwd. Если пользователь существует, то без изменений ## USERADD=no|none|disable # Отключить управление прользователями конфигурации @@ -269,8 +269,88 @@ NEEDEDUSERS='superadmin:1000:x:Администратор' ## no # Не выполнять действие [/etc/ublinux/update] -## Настройка обновления системы +## Настройка репозиториев и обновления системы ################################################################################ +## Настройка подключения репозиториев +## REPOSITORY[]=disable | ::,,..., +## # Произвольное имя репозитория. Обязательный +## disable # Отключить отдин из репозиториев по умолчанию: core,extra,community,multilib,ublinux,modules +## # Уровень проверки подписи репозитория, можно выбрать одну из основных и вторую из дополнительных, разделитель запятая. Не обязательный +## # Последовательность имеет значение, т.к. накладываются правила каскадно. По умолчанию: Required,DatabaseOptional +## Never # Проверка подписи выполняться не будет. Основная +## PackageNever # Только для пакетов. Дополнительная +## DatabaseNever # Только для базы данных. Дополнительная +## Optional # Подписи будут проверяться при их наличии, но неподписанные базы данных и пакеты также будут приниматься. Основная +## PackageOptional # Только для пакетов. Дополнительная +## *DatabaseOptional # Только для базы данных. Дополнительная +## *Required # Подписи будут необходимы для всех пакетов и баз данных. Основная +## PackageRequired # Только для пакетов. Дополнительная +## DatabaseRequired # Только для базы данных. Дополнительная +## TrustedOnly # Если подпись проверяется для пакетов и базы, она должна находиться в связке ключей и быть полностью доверенной; маргинальное доверие не применимо +## PackageTrustedOnly # Если подпись проверяется только для пакетов +## DatabaseTrustedOnly # Если подпись проверяется только для базы данных +## TrustAll # Если подпись проверена, она должна находиться в связке ключей, но ей не требуется назначать уровень доверия (например, неизвестное или предельное доверие) +## PackageTrustAll # Если подпись проверена только для пакетов +## DatabaseTrustAll # Если подпись проверена только для базы данных +## # Уровень использования этого репозитория. Не обязательный +## *All # Включать все перечисленные функции для репозитория. Это значение по умолчанию +## Sync # Включать обновления для этого репозитория +## Search # Включать поиск этого репозитория +## Install # Включать установку пакетов из этого репозитория во время операции --sync +## Upgrade # Позволить этому репозиторию быть действительным источником пакетов при выполнении --sysupgrade +## # Полный URL-адрес места, где можно найти базу данных, пакеты и подписи (если доступны) для этого репозитория. Обязательный +## # Возможно указать несколько, через запятую. +## # Если указан доступный файл, то подключить как дополнительный файл расширения конфигурации +## file:// # URL префикс для репозитория в каталоге +## ftp:// # URL префикс для репозитория FTP +## http:// # URL префикс для репозитория HTTP +## https:// # URL префикс для репозитория HTTPS +## REPOSITORY[modules]=::http://192.168.0.1:8080/repo/2204 +## REPOSITORY[webmyrepo]=never::http://myweb.org/myrepo +## REPOSITORY[localmyrepo]=never::file:///home/myrepo + +## Опубликовать локальный репозиторий в локальной сети, подключиться к сети распределённых репозиториев. +## При установке пакета пакет ищется в распределённой сети репозиториев и устанавливается самой последней доступной версией. +## REPOPUBLIC_NET=,..., +## # Подключенное имя репозитория, например: core,extra,community,multilib,ublinux,modules +## all # Если name_repo=all, то опубликовать все подключенные репозитории +## REPOPUBLIC_NET=all +## REPOPUBLIC_NET=modules + +## Опубликовать локальный репозиторий в виде локального WEB ресурса +## REPOPUBLIC_WEB[]=enable|disable,listing:::: +## # Путь до каталога репозитория, который будет опубликован +## enable # Включить публикацию +## disable # Выключить публикацию +## listing # Включить WEB обозреватель файлов. Не обязятельный +## # Порт по которому доступен репозиторий. По умолчанию: 8080. Не обязательный +## # Параметры авторизации, имя пользователя. Не обязательный +## # Параметры авторизации, открытый пароль или тип хеша. Не обязательный +## password # Не зашифрованный пароль +## sha256 # Использовать зашифрованный пароль SHA256 +## sha512 # Использовать зашифрованный пароль SHA512 +## # Параметры авторизации, зашифроваггый пароль SHA256 или SHA512. Не обязательный +## REPOPUBLIC_WEB[/home/myrepo]=enable + +## Опубликовать ленивое зеркало подключенных репозиториев в виде локального WEB ресурса. +## Получая запрос от пользователя, загружает с удалённого репозитория пакет и сохраняет в кеше передавая его пользователю. +## REPOPUBLIC_CACHE[]=enable|disable::@,...,@ +## # Путь до каталога файлов кеша, если не указан, то по умолчанию: /mnt/livedata/ublinux-data/repopublic_cache +## enable # Включить публикацию +## disable # Выключить публикацию +## # Порт по которому доступен репозиторий. По умолчанию: 8080. Не обязательный +## +## # Произвольное имя репозитория +## # Полный адрес репозитория URL или файл +## # Если не указано @, то по умолчанию системные /etc/pacman.d/mirrorlist +## # Возможно указать несколько, через запятую. +## # Файл списка зеркал, подключается как список зеркал с синтаксисом /etc/pacman.d/mirrorlist +## # Важно: в подключенном списке не должно быть адреса текущего сервера +## http:// # URL префикс для репозитория на HTTP +## https:// # URL префикс для репозитория на HTTPS +## REPOPUBLIC_CACHE[/mnt/livedata/ublinux-data/repopublic_cache]=enable +## REPOPUBLIC_CACHE[/mnt/livedata/ublinux-data/repopublic_cache]=enable:80:myrepo@http://192.168.0.1:8080/repo/2204 + ## Автообновление системы ## UBLINUXUPDATE= ## =auto # автоматически @@ -524,6 +604,12 @@ GRUB_BOOT_SILENT="splash" #SERVER_DOMAIN[type]=samba #SERVER_DOMAIN[admin]=administrator:0J3QvtCy0YvQuV/QlNC10L3RjCEK +#TODO: Переоценить необходимость +## Адрес сервера ublinux-server по умолчанию +#UBLINUXSERVER=192.168.1.31 +## Адрес сети по умолчанию +#NETWORKIP=192.168.1. + [/etc/ublinux/save] ## Настройка сохранений ################################################################################ @@ -662,14 +748,6 @@ GRUB_BOOT_SILENT="splash" ## NETWORK[Проводное соединение 2@connmod]="802-3-ethernet.cloned-mac-address 00:22:22:22:22:22" ## NETWORK[wlan0@connmod]="wifi.cloned-mac-address 70:70:70:70:70:70" - ## ublinux-server ip addres - ## Адрес сервера по умолчанию - #UBLINUXSERVER=192.168.1.31 - - ## Local network base address - ## Адрес сети по умолчанию - #NETWORKIP=192.168.1. - ## Switch on ipv6 at start on all interfaces ## Включение ipv6 по умолчанию на всех интерфейсах IPV6=no @@ -736,13 +814,6 @@ NSSWITCHWINBIND=yes ## Должна быть включена служба tor! #TORUSERS=500-999 - ## Автоматически менять MAC адрес интерфейса при подключении - #MACCHANGE=wlan0 - ## По умолчанию используется алгоритм -e не меняющей тип и производителя - #MACCHANGEROPTIONS='-a' - ## Можно назначить конкретный адрес для интерфейса - #MACCHANGEROPTIONS='--mac=XX:XX:XX:XX:XX:XX' - [/etc/ublinux/security] ## Настройка безопасности, ограничений ################################################################################ @@ -833,16 +904,16 @@ NSSWITCHWINBIND=yes ## Отключить пользовательские nosuid nodev noexec на смонтированные цели ## MOUNT_ATTR[,]=, -## Source: -## LABEL=