diff --git a/deploy/install-systemd.sh b/deploy/install-systemd.sh index 48801a7..96e4d38 100644 --- a/deploy/install-systemd.sh +++ b/deploy/install-systemd.sh @@ -78,6 +78,8 @@ if [ -f /etc/smail/smail.env ]; then cp -p -- /etc/smail/smail.env "$backup_dir/ if ! getent group smail >/dev/null; then groupadd --system smail; fi if ! getent passwd smail >/dev/null; then useradd --system --gid smail --home-dir "$runtime_dir" --shell /usr/sbin/nologin smail; fi +if ! getent group smail-plugin >/dev/null; then groupadd --system smail-plugin; fi +if ! getent passwd smail-plugin >/dev/null; then useradd --system --gid smail-plugin --home-dir /nonexistent --shell /usr/sbin/nologin smail-plugin; fi install -d -o root -g root -m 0755 "$runtime_dir" install -d -o root -g root -m 0750 /etc/smail if [ ! -e /etc/smail/smail.env ]; then @@ -85,6 +87,12 @@ if [ ! -e /etc/smail/smail.env ]; then umask 0077 printf '%s\n' 'SMAIL_ROOT=/opt/smail' 'GOMEMLIMIT=256MiB' > /etc/smail/smail.env fi +if ! grep -q '^SMAIL_PLUGIN_UID=' /etc/smail/smail.env; then + printf 'SMAIL_PLUGIN_UID=%s\n' "$(id -u smail-plugin)" >> /etc/smail/smail.env +fi +if ! grep -q '^SMAIL_PLUGIN_GID=' /etc/smail/smail.env; then + printf 'SMAIL_PLUGIN_GID=%s\n' "$(id -g smail-plugin)" >> /etc/smail/smail.env +fi chown root:root /etc/smail/smail.env chmod 0600 /etc/smail/smail.env for directory in config data ssl log plugins; do diff --git a/deploy/systemd/smail.service b/deploy/systemd/smail.service index aaf672e..4b6dd7d 100644 --- a/deploy/systemd/smail.service +++ b/deploy/systemd/smail.service @@ -7,8 +7,8 @@ StartLimitBurst=3 [Service] Type=simple -User=smail -Group=smail +# 主进程需要保留受限的 root 能力,才能为插件创建 chroot 和网络隔离;插件 +# 通过 SMAIL_PLUGIN_UID/SMAIL_PLUGIN_GID 降权运行,不能以 root 身份执行。 # 运行环境仅由 root 可读写的独立文件提供,避免在 unit 中混入部署环境配置。 EnvironmentFile=/etc/smail/smail.env WorkingDirectory=/opt/smail @@ -34,7 +34,7 @@ RuntimeDirectoryMode=0750 NoNewPrivileges=true AmbientCapabilities=CAP_NET_BIND_SERVICE -CapabilityBoundingSet=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SYS_CHROOT CAP_SETUID CAP_SETGID CAP_CHOWN CAP_SYS_ADMIN PrivateTmp=true ProtectHome=true ProtectSystem=full