我正在使用 pam_mount.so 为 Ubuntu 14.04 客户端上的用户自动挂载 CIFS 共享。
pam_mount 在每个用户主目录中使用本地 conf。我正在使用 pam_exec 运行 bash 脚本,该脚本使用 CIFS 共享的路径更新配置文件。
我的 /etc/pam.d/common-session 文件的结尾如下所示:
session required pam_unix.so
session optional pam_exec.so log=/var/log/pamexec /usr/local/bin/mdrive_add
session optional pam_mount.so
session optional pam_ldap.so
session optional pam_systemd.so
当使用 SSH 或通过 GUI 登录时,此功能有效,脚本在挂载之前运行,因此可以访问共享。
但是,当使用 su 时,脚本失败,并且本地用户配置未更新,因此挂载也会失败。
使用 su 从 [accountA] 到 [accountB] 时收到的错误是:
/bin/sed: couldn't open temporary file /home/[accountB]/sednpoogQ: Permission denied
脚本中失败的行是这样的:
/bin/sed -i "s|\@S|${XSERVER}|g" /home/${PAM_USER}/.pam_mount.conf.xml
我尝试从 ~/.profile 和其他地方运行该脚本,它运行正常,但在 pam_mount 之前没有运行。
所以我的问题是,当使用 su 时,如何让 pam_exec 替换位于用户主目录中的文本文件中的字符串?
更新
根据评论,我尝试过“sudo -u [accountb] -i”(在 /etc/pam.d/sudo 中包含 @common-session 之后),这不会返回相同的错误,它可以工作。但是,这不是一个可接受的解决方案,因为我需要 su 才能工作(并且它会导致 pam_mount 提示输入密码)。
更新2
我已经使用 ssh 登录,将 env 转储到一个文件中,然后我从另一个帐户使用 ssh 登录,使用 su 并将 env 转储到一个文件中。
比较两者(账户名称用 accounta 和 accountb 替换,如问题所示:
$ comm -3 <(sort ssh_list.txt ) <(sort su_list.txt)
PASSWD_FD=0
_PMT_DEBUG_LEVEL=0
PWD=/home/[accounta]
PWD=/home/[accountb]
SHLVL=1
SHLVL=2
SSH_CLIENT=10.112.9.87 58090 22
SSH_CLIENT=10.112.9.87 58695 22
SSH_CONNECTION=10.112.9.87 58090 10.80.0.68 22
SSH_CONNECTION=10.112.9.87 58695 10.80.0.68 22
SSH_TTY=/dev/pts/13
SSH_TTY=/dev/pts/14
XDG_RUNTIME_DIR=/run/user/1000
XDG_RUNTIME_DIR=/run/user/10006
XDG_SESSION_ID=6
XDG_SESSION_ID=7
更新3
添加了pam_exec运行的完整脚本(敏感信息用占位符替换):
#!/bin/bash
USERN=$PAM_USER
if grep -q @S /home/${USERN}/.pam_mount.conf.xml || grep -q @P /home/${USERN}/.pam_mount.conf.xml; then
BASEDIR=`ldapsearch -LLL -H ldaps://dc.example.org:3269 -D "[email protected]" -b "DC=c,DC=sdu,DC=dk" -w [secretpw] "sAMAccountName=${USERN}" dn`;
PREFIX="dn:: "
BASEDIR=${BASEDIR#$PREFIX}
PREFIX="dn: "
BASEDIR=${BASEDIR#$PREFIX}
BASEDIR=`echo $BASEDIR | tr -d ' '`
if [[ $BASEDIR != *","* ]]
then
BASEDIR=`echo $BASEDIR | base64 --decode`
fi
BASEDIR=`echo $BASEDIR | tr -d ' \n' | awk -F "DC=" '{ st = index($0,"DC=");print substr($0,st+0)}'`;
DOMAIN=`echo $BASEDIR | sed 's/,DC=/./g' | sed 's/DC=//'`;
OUTPUT=`ping -c 1 -t 10 $DOMAIN | grep icmp`
HOMEDIR='\\fallbackserver\share'
if [[ -n "$OUTPUT" ]]
then
DC=`echo $OUTPUT| cut -d' ' -f 4`
HOMEDIR=`ldapsearch -LLL -H ldaps://$DC:636 -D "[email protected]" -b "${BASEDIR}" -w [secretpw] "sAMAccountName=${USERN}" homeDirectory | grep homeDirectory | awk '{print $2}'`;
fi
CHOMEDIR=$(echo ${HOMEDIR} | sed 's/\\/\//g')
XSERVER=`echo $CHOMEDIR | cut -f3 -d/`
XPATH=`echo $CHOMEDIR | cut -f4- -d/`
/bin/sed -i "s|\@S|${XSERVER}|g" /home/${USERN}/.pam_mount.conf.xml
/bin/sed -i "s|\@P|${XPATH}|g" /home/${USERN}/.pam_mount.conf.xml
fi
更新4
在脚本中放置一个 whoami,表明当使用 su 从 accounta 到 accountb 时,该脚本由 accounta 运行。
更新5
使用 pam_exec 的“seteuid”选项解决了该问题。
session optional pam_exec.so seteuid log=/var/log/pamexec /usr/local/bin/mdrive_add
当从 A 切换到 B 时,whoami 现在显示“root”,并且没有权限问题。
我不明白 pam_exec 手册中的术语“真实用户 ID”和“有效用户 ID”,但这是另一天的问题。
默认情况下,pam_exec.so 将使用调用进程的真实用户 ID 执行外部命令。指定此选项意味着使用有效用户 ID 运行命令。
答案1
问题是,通过su
pam_exec
以“旧”用户身份登录时执行脚本,而该用户没有写入“新”用户主目录的权限。
设置seteuid
选项以 rootsession optional pam_exec.so log=/var/log/pamexec /usr/local/bin/mdrive_add
身份pam_exec
执行脚本,解决了该问题:
session optional pam_exec.so seteuid log=/var/log/pamexec /usr/local/bin/mdrive_add
然而“真正的”解决方案可能是/etc/pam.d/su
充分配置的,这是我仍然在摆弄的东西;一旦我了解正确的配置方法,我将更新这个答案/etc/pam.d/su
。