我正在查看下面包含的 bash 脚本。它接受几个命令行参数并创建一个 .deb 包,当使用该sudo dpkg -i created-file.deb
命令执行该包时,将创建一个新用户,并且您会看到,新用户的主目录有一个.ssh
目录,其中的authorized_keys
文件与作为第二个参数提交的文件。但是,.ssh
目录和authorized_keys
文件是如何创建的呢?我可以看到该useradd
命令,但创建的 .deb 文件似乎没有实际将文件移动到新用户主目录的命令。
这是我在该脚本上运行的命令:
sudo ./gvm-lsc-deb-creator.sh newuser some_file.pub /home/currentuser /home/currentuser [email protected]
这是完整的脚本:
# Command line parameters
USERNAME="$1"
PUBKEY_FILE="$2"
TEMP_DIR="$3"
OUTPUT_PATH=$4
MAINTAINER_EMAIL="$5"
if [ -z "${USERNAME}" ]
then
echo "No username given" >&2
exit 1
fi
if [ -z "${PUBKEY_FILE}" ]
then
echo "No pubkey path given" >&2
exit 1
fi
if [ -z "${TEMP_DIR}" ]
then
echo "No temp dir path given" >&2
exit 1
fi
if [ -z "${OUTPUT_PATH}" ]
then
echo "No output path given" >&2
exit 1
fi
if [ -z "${MAINTAINER_EMAIL}" ]
then
MAINTAINER_HOSTNAME="$(hostname)"
if [ -z "$HOSTNAME" ]
then
MAINTAINER_HOSTNAME="localhost"
fi
MAINTAINER_EMAIL="admin@${MAINTAINER_HOSTNAME}"
fi
# Constants
# Package data
PACKAGE_NAME="gvm-lsc-target-${USERNAME}"
PACKAGE_VERSION="0.5-1"
PACKAGE_NAME_VERSION="${PACKAGE_NAME}_${PACKAGE_VERSION}"
MAINTAINER="Greenbone Vulnerability Manager <${MAINTAINER_EMAIL}>"
PACKAGE_DATE=$(date "+%a, %d %b %Y %H:%M:%S %z")
USER_COMMENT="GVM Local Security Checks"
USER_COMMENT_GREP="GVM\\ Local\\ Security\\ Checks"
# Paths
PACKAGE_BASE_DIR="${TEMP_DIR}/${PACKAGE_NAME_VERSION}"
# Data paths
DATA_DIR="${PACKAGE_BASE_DIR}"
HOME_SUBDIR="home/${USERNAME}"
HOME_DATA_DIR="${DATA_DIR}/${HOME_SUBDIR}"
SSH_DATA_DIR="${HOME_DATA_DIR}/.ssh"
DOC_SUBDIR="usr/share/doc/${PACKAGE_NAME}"
DOC_DATA_DIR="${DATA_DIR}/${DOC_SUBDIR}"
# Control file path
CONTROL_DIR="${PACKAGE_BASE_DIR}/DEBIAN"
#
# Test dependencies
#
if [ -z "$(which dpkg)" ]
then
echo "dpkg not found" >&2
exit 1
fi
if [ -z "$(which fakeroot)" ]
then
echo "fakeroot not found" >&2
exit 1
fi
if [ -z "$(which md5sum)" ]
then
echo "md5sum not found" >&2
exit 1
fi
#
# Set up error handling
#
handle_error() {
echo "DEB package generation failed" >&2
exit 1
}
trap handle_error ERR
#
# Create data files
#
# Create .ssh directory
mkdir -p "${SSH_DATA_DIR}"
# Copy public key
AUTH_KEYS_FILE="${SSH_DATA_DIR}/authorized_keys"
cp "${PUBKEY_FILE}" "${AUTH_KEYS_FILE}"
# Create doc directory
mkdir -p "${DOC_DATA_DIR}"
# Create Changelog
cd "${DOC_DATA_DIR}"
CHANGELOG_FILE="${DOC_DATA_DIR}/changelog.Debian"
{
echo "${PACKAGE_NAME} (${PACKAGE_VERSION}) experimental; urgency=low"
echo ""
echo " * Automatically generated local security check credential package"
echo " "
echo ""
echo " -- ${MAINTAINER} ${PACKAGE_DATE}"
} > "${CHANGELOG_FILE}"
# Compress Changelog
gzip -f --best "${CHANGELOG_FILE}"
CHANGELOG_FILE="${CHANGELOG_FILE}.gz"
# Create Copyright info
COPYRIGHT_FILE="${DOC_DATA_DIR}/copyright"
{
echo "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/"
echo ""
echo "Files: *"
echo "Copyright: 2018-2020 Greenbone AG"
echo "License: GPL-2+ (/usr/share/common-licenses/GPL-2)"
} > "${COPYRIGHT_FILE}"
# Create data archive
cd "${DATA_DIR}"
tar -C "${DATA_DIR}" -z -cf "../data.tar.gz" "${HOME_SUBDIR}" "${DOC_SUBDIR}"
#
# Create control files
#
# Create directory
mkdir -p "${CONTROL_DIR}"
chmod "0755" "${CONTROL_DIR}"
# Create "control" file
CONTROL_FILE="${CONTROL_DIR}/control"
{
echo "Package: ${PACKAGE_NAME}"
echo "Version: ${PACKAGE_VERSION}"
echo "Maintainer: ${MAINTAINER}"
echo "Priority: optional"
echo "Architecture: all"
echo "Description: GVM local security check preparation"
echo " This package prepares a system for GVM local security checks."
echo " A user is created with a specific SSH authorized key."
echo " The corresponding private key is located at the respective"
echo " GVM installation."
} > "${CONTROL_FILE}"
# Create "preinst" file run before installation
PREINST_FILE="${CONTROL_DIR}/preinst"
touch "${PREINST_FILE}"
chmod "0755" "${PREINST_FILE}"
{
echo "#!/bin/sh"
echo "set -e # abort on errors"
echo "useradd -c \"${USER_COMMENT}\" -d /home/${USERNAME} -m -s /bin/bash ${USERNAME}"
} > "${PREINST_FILE}"
# Create "postinst" file run after installation
POSTINST_FILE="${CONTROL_DIR}/postinst"
touch "${POSTINST_FILE}"
chmod "0755" "${POSTINST_FILE}"
{
echo "#!/bin/sh"
echo "set -e # abort on errors"
echo "chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}"
echo "chmod 500 /home/${USERNAME}/.ssh"
echo "chmod 400 /home/${USERNAME}/.ssh/authorized_keys"
} > "${POSTINST_FILE}"
# Create "postinst" file run after removal or on error
POSTRM_FILE="${CONTROL_DIR}/postrm"
touch "${POSTRM_FILE}"
chmod "0755" "${POSTRM_FILE}"
{
echo "#!/bin/sh"
echo "# Remove user only if it was created by this package."
echo "# The debian package will run the postun script in case of errors"
echo "# (e.g. user already existed)."
echo "# Delete the user only if /etc/passwd lists content that suggests"
echo "# that the user was created by this package."
# echo "set -e # abort on errors"
echo "grep \"${USERNAME}.*${USER_COMMENT_GREP}\" /etc/passwd && userdel -fr ${USERNAME}"
} > "${POSTRM_FILE}"
# Calculate md5 checksums
MD5SUMS_FILE="${CONTROL_DIR}/md5sums"
cd "${DATA_DIR}"
{
md5sum "${HOME_SUBDIR}/.ssh/authorized_keys"
md5sum "${DOC_SUBDIR}/changelog.Debian.gz"
md5sum "${DOC_SUBDIR}/copyright"
} > "${MD5SUMS_FILE}"
#
# Build package
#
# Combine into .deb file
cd "${TEMP_DIR}"
fakeroot -- dpkg --build "${PACKAGE_NAME_VERSION}" "${OUTPUT_PATH}"
我知道该脚本将创建一个目录PACKAGE_BASE_DIR
,并将第二个命令参数中的文件移动到该目录,该目录将被压缩并编译到 .deb 包中。但是,.deb 包具有三个可执行文件“preinst”、“.deb”postinst
和postrm
“.deb”。这些文件的内容是:
预安装:
#!/bin/sh
set -e # abort on errors
useradd -c "GVM Local Security Checks" -d /home/testing -m -s /bin/bash testing
后置
#!/bin/sh
set -e # abort on errors
chown -R testing:testing /home/testing
chmod 500 /home/testing/.ssh
chmod 400 /home/testing/.ssh/authorized_keys
但这些命令实际上都没有将 .deb 包中包含的文件移动到新用户的主目录中。我查看了adduser
联机帮助页,但看不到任何允许执行此操作的函数。这不只是创建一个框架,它实际上会移动文件。
我读这个答案希望它能指向某个可以自动执行此操作的函数,但没有。
我的问题是,这些文件是如何移动的。创建新用户时似乎没有命令实际移动它们,但它们确实如此。运行该脚本不会创建用户或用户主目录。它仅输出 .deb 包。 .deb 包的脚本没有明显的文件移动方式。
PS 这个文件难倒了 ChatGPT,我不断地编译和运行它,一遍又一遍地感到震惊。文件将移至新用户的主目录中。
答案1
感谢 @muru 的评论,我能够快速理解 .deb 包如何将包文件填充到 Linux 文件结构中。
在preinst
和postinst
脚本之间,Debian 包管理系统执行多项任务,包括将包文件解压到文件系统、设置包的配置文件以及向系统的包管理数据库注册包。
以下是安装 Debian 软件包时发生的步骤的总体概述:
- 该包被解压到临时目录中。该
preinst
脚本将被执行,从而执行任何必要的预安装任务。 - 包的文件被复制到文件系统中的最终位置。
- 该
postinst
脚本将被执行,从而执行任何必要的安装后任务。 - 该包已在系统的包管理数据库中注册。
- 系统的包管理数据库已更新以反映新的包安装。
- 包的配置文件已设置。
另外,成功安装软件包后,可以使用系统的软件包管理工具将其删除,该工具将在从文件系统中删除软件包文件之前和之后分别执行prerm
和脚本。postrm