【问题标题】:Scripts launched from udev do not have DISPLAY access anymore?从 udev 启动的脚本不再具有 DISPLAY 访问权限?
【发布时间】:2013-12-22 02:24:06
【问题描述】:

当我插入外部驱动器时,我有一个从 udev 运行的脚本。它总是有效的。但是在从 Linux 3.8/Xorg 1.12/Mint 14(Ubuntu 12.10 兼容)升级到 Linux 3.11/Xorg 1.14/Mint 16(Ubuntu 13.10 兼容),它不再工作了。

脚本仍在运行,但没有任何需要显示的命令起作用。我通过退出 udev 守护进程并手动运行 udevd --debug 以获取详细输出(更多信息见下文)来解决这个问题。

此脚本曾在 Mint 14/12.10 中工作:

export DISPLAY=:0
UUID=$1
DEV=$2

notify-send -t 700 "mounting $DEV ($UUID)"
gnome-terminal -t "Backing up home..." -x rsync long line of data
zenity --warning --text="Done."

但在 Mint 16/13.10 中不再存在。如果您想知道可能的解决方案,我逐渐添加了一些东西,现在看起来像这样:

export DISPLAY=:0.0

xhost +local:
xhost +si:localuser:root
xhost +

DISPLAY=:0.0
export DISPLAY=:0.0
UUID=$1
DEV=$2

notify-send -t 700 "mounting $DEV ($UUID)"
gnome-terminal -t "Backing up home..." -x rsync long line of data
zenity --warning --text="Done." --display=:0.0

但它仍然不起作用。 udevd --debug 仍然显示:

'(err) 'No protocol specified'
'(err) ''
'(err) '** (gnome-terminal:24171): WARNING **: Could not open X display'
'(err) 'No protocol specified'
'(err) 'Failed to parse arguments: Cannot open display: '
'(err) 'No protocol specified'
'(err) ''
'(err) '** (zenity:24173): WARNING **: Could not open X display'
'(err) 'No protocol specified'
'(err) ''
'(err) '(zenity:24173): Gtk-WARNING **: cannot open display: :0.0'
'(err) 'No protocol specified'

请注意,任何 bash 逻辑都有效。将测试变量回显到>>/tmp/test.log 有效。它只是访问不再工作的显示。

这快把我逼疯了。现在实现这一目标的正确方法是什么?

2013 年 12 月 20 日更新

因此,在之前的 Ubuntu 中,X 命令会使用用户自动找到通往当前X 的路径。

现在,我似乎每次都需要这两件事:

  • 在X 上使用用户:
    • xhost +si:localuser:root
  • 在root/udev 方面:
    • 使用用户的~/.Xauthority文件将X复制到/root

这“感觉”就像是时光倒流。这仅在我每次以同一用户身份登录时脚本化才有效,因此我可以在脚本执行时从该用户的家中复制 .Xauthority 文件。

旧的 Ubuntu 使用了什么“技巧”来自动“神奇”地完成这项工作?

【问题讨论】:

  • 您是否检查了工作 X 会话中的 XAUTHORITY 环境变量? IIRC,Ubuntu更改了.Xauthority文件的默认路径。
  • 它仍然在~ 中(并且相应地设置了ENV) - 我相信它一直在~ 中。
  • 但是如果在另一个用户启动桌面会话时脚本以 root 身份运行,~ 将会不同。但确定你检查过了!
  • 你可能想在serverfault.com上试试这个问题,你可能会得到更好的结果。
  • 是的,至少我认为我明白了。 Aparently,root 曾经拥有访问权限(如脚本所示,该脚本曾经在没有任何额外身份验证选项的情况下工作)。似乎不再是了,所以xhost + afaik 应该涵盖这一点。

标签: linux ubuntu xorg udev linux-mint


【解决方案1】:

好的,我写这个答案是为了尝试澄清 X 服务器的安全模型,据我所知。我不是这方面的专家,所以我可能弄错了一些(很多?)事情。此外,正如 OP 所指出的,在不同的发行版中,甚至同一发行版的不同版本中,许多事情都是不同的。

获得授权连接到 X 服务器的主要方法有两种:

  • xhost 方式(主机访问):服务器维护一个允许连接到服务器的主机、本地用户、组等的列表。
  • xauth 方式(基于 Cookie):服务器有一个随机生成的 cookie 列表,任何显示其中一个 cookie 的人都将被授予访问权限。

现在,分配特定的东西......

X 服务器由启动系统启动时,通常会传递-auth <filename> 形式的命令行。此文件包含用于授权的初始 cookie 列表。它是在 X 服务器运行之前使用xauth 工具创建的。然后就在 X 服务器之后,登录管理器启动,并指示它从同一文件中读取 cookie,因此它可以连接。

现在,当用户rodrigo 登录时,它必须被授权连接到服务器。这是由登录管理器完成的,它有两个选项:

  • 相当于:xhost +si:localuser:rodrigo。
  • 它生成另一个cookie,将其添加到服务器并将其传递给用户。这种传递可以通过两种方式完成:
    • 写在文件$HOME/.Xauthority(新用户的家)中。
    • 它写在其他地方 (/var/run/gdm/auth-for-rodrigo-xxxx) 并且环境变量 XAUTHORITY 设置为该文件的名称。

此外,它可以做这两件事。一些登录管理器甚至默认将root用户添加到授权用户列表中(好像xhost +si:localuser:root)。

但请注意,如果您无权连接到 X 服务器,则无法将自己添加到列表中(例如运行 xhost +)。原因和没有钥匙不能从外面打开房门是一样的……就算你是root也是如此!

是不是说root用户无法连接服务器?绝对不!但是要首先做到这一点,您必须知道如何将登录的用户配置为连接到服务器。对于以登录用户身份运行:

$ xhost

它将显示一条消息和授权用户、主机或组的列表(如果有):

access control enabled, only authorized clients can connect
SI:localuser:rodrigo

然后运行:

$ echo $XAUTHORITY

查看授权文件的保存位置。如果为空,则为~/.Xauthority。那么:

$ xauth list :0

查看您的授权 cookie 列表。

现在,如果服务器中有任何 cookie,root 用户应该能够连接,使 XAUTHORITY 环境变量指向正确的 cookie 文件。请注意,在许多设置中,登录管理器的 cookie 也被保留。随便找!

root 访问的另一种可能性是修改Xsession 文件以添加命令xhost +si:localuser:root 并获得永久访问权限。具体细节因使用的特定程序而异,但对于gdm,您只需使用xhost 命令在/etc/gdm/Init/ 中添加一个可执行脚本,它将在下次启动时自动运行。

PS:您可以使用sudo -i检查您对X服务器的root访问权限,但请注意,某些sudo配置可能会保留DISPLAY、XAUTHORITY或HOME变量并修改测试结果.

示例:此脚本应该能够以 root 身份将您连接到 X 服务器

export DISPLAY=:0
export XAUTHORITY=`ls /var/run/gdm/auth-for-gdm-*/database`
xrandr #just for show

当然,XAUTHORITY 变量的路径取决于您使用的登录管理器(问候语)。你可以使用用户文件(你说它在/home/redsandro/.Xauthority,但我不太确定)。或者,您可以使用欢迎 cookie。要获取欢迎 cookie,您可以使用以下命令:

$ pgrep -a Xorg

在我的系统中给出:

408 /usr/bin/Xorg :0 -background none -verbose -auth /var/run/gdm/auth-for-gdm-gDg3Ij/database -seat seat0 -nolisten tcp vt1

所以我的文件是/var/run/gdm/auth-for-gdm-gDg3Ij/database。 gDg3Ij 是随机的,每次服务器重新启动时都会发生变化,这就是 ls ... 技巧的原因。

使用 GDM cookie 代替用户的好处是它不依赖于登录的用户。它甚至可以在没有用户的情况下工作!

更新:从您的最新评论中,我看到您的 X 服务器命令是:

/usr/bin/X :0 -audit 0 -auth /var/lib/mdm/:0.Xauth -nolisten tcp vt8

所以有用于启动登录管理器的 cookie 的名称。如果我是正确的,那应该一直可用,如果您能够阅读该文件。而且您是 root,因此,以下几行应该足以让您以 root 身份访问显示器:

export DISPLAY=:0
export XAUTHORITY=/var/lib/mdm/:0.Xauth

zenity --info --text 'Happy New Year'

【讨论】:

  • 感谢您为澄清所有这些 X 内容所做的努力,但是在玩了半小时这个新见解之后,我似乎仍然无法在不同的 tts 中从根目录触摸 X(用于测试目的) .因此,虽然是一个很好的总结,但这不是我正在寻找的解决方案。我的根脚本中可能只需要一两个特定的简单命令。我确实需要它们,因为我自己没有弄清楚它们。现在两次。
  • @Redsandro:好的,让我们一步一步来。首先,您确定您的 X 服务器使用哪种身份验证方法了吗?如果它是一个 xauth cookie,您是否确定该文件在哪里?完全确定——注意周围可能有旧的 .Xauthority 文件——删除它并尝试从用户会话中打开一个 X 程序:如果它失败了,就是这样!
  • 它使用cookie方法。并且环境变量指向~ 中的那个。如果我把它复制给另一个用户,那个用户也可以访问X。我不确定我是否敢删除原始文件;您不是刚刚提到它可能会阻止我从该用户访问X 吗?我试图在这里获得更多X 访问权限,而不是更少。我还没有准备好接受这种承诺。 :P
  • @Redsandro:这不是信任问题......问题是我非常有信心这些工具可以像我认为的那样工作。而且您的工具必须工作起来也一样。如果没有访问您的机器,我很难知道发生了什么:-(,而且您没有回答我的一些问题,所以我猜我能做到的最好(而且我不能使用 MDM,因为它不可用对于我的操作系统)。最重要的一个未回答的问题是:X 服务器的命令行是什么 (ps -ef | grep Xorg)?。
  • @Redsandro:别担心,这些天我们都很慢。是的,X 服务器有很多名字。请查看我的更新答案。
【解决方案2】:

快速搜索发现以下内容:

X 身份验证基于 cookie —— 秘密的随机小片段 只有你和 X 服务器知道的数据……所以,你需要让 其他用户了解您的 cookie 是什么。一种方法是 遵循:在您发出 su 或 sudo 之前(但在 ssh 进入 远程系统,如果您使用 ssh),请求 cookie 当前正在连接到 X 服务器的 DISPLAY:

$ xauth list $DISPLAY 你会得到类似的东西

somehost.somedomain:10 mit-magic-cookie-1 4d22408a71a55b41ccd1657d377923ae

然后,在完成 su 之后,告诉新用户 cookie 是什么:

$ xauth add somehost.somedomain:10 MIT-MAGIC-COOKIE-1 4d22408a71a55b41ccd1657d377923ae

(只需将上述“xauth 列表”的输出复制并粘贴到“xauth”中 添加')就是这样。现在,您应该可以启动任何 X 应用程序了。

供参考,这里是出处http://www.linuxquestions.org/questions/linux-newbie-8/xlib-connection-to-0-0-refused-by-server-xlib-no-protocol-specified-152556/

【讨论】:

  • 这应该用xhost +解决吧?我试过了(见第二个脚本)。另外,我认为任何基于 2013 年之前信息的解决方案都是无关紧要的,因为过去工作的脚本是基于这些约定的。
  • 这不一定是真的,但我猜他们增加了安全问题,所以xhost + 不尊重 root。
  • @Redsandro xhost 不会解决 xauth 身份验证的问题。它们是两种完全不同的机制。 xhost 是较旧、更简单且安全性大大降低的机制。 xauth 较新,(在某种程度上)更安全,但更难做到正确......
  • 哦,所以任何xhost(相关)命令都已过时? (通过 google 获取最新信息真的很难,有数百个模糊的问题和排序但不是真正的解决方案同时提到 xhost 和 xauth。
  • @Redsandro 我不确定xhost 是否真的被宣布过时......但根据我的经验,现在大多数发行版和其他Unixen 都将xauth 配置为主要方法...... . 不过,两者都仍然包含在内并且可以正常工作。
【解决方案3】:

这并不漂亮,但我还没有看到任何解决方案。所以这是迄今为止最好的。

  • 在X 上使用用户:
    • xhost +si:localuser:root
  • 在 root/udev 端:
    • 使用用户的~/.Xauthority 文件将X 复制到/root(* 请参阅下面的注释)

现在可以了。试试zenity --warning --text=Hooray

这仅在您知道哪个用户将要登录 X 时才有效。因此,仅当计算机由具有单个用户帐户的单个用户使用时才可接受。

*) 注意
这是值得注意的,因为我尝试了xauth merge /home/redsandro/.Xauthority 和$XAUTHORITY=/home/redsandro/.Xauthority 的记录方法。这些记录在案的方法现在什么都不做,即使root 有权阅读它。您需要从字面上看整个 .Xauthority 文件,而不是仅仅指向它。

【讨论】:

  • 这根本不是真的。我有一个最新的 Xorg-server (1.14),它的工作方式与文档完全一致。我的猜测是您的用户有一个陈旧无用的~/.Xauthority 文件,而真正的文件在其他地方。例如,在以 root 身份运行的系统中,xauth merge /run/gdm/auth-for-*/* 将授予 m 访问 X 服务器的权限,无论哪个用户登录。/run/gdm/auth-for-gdm-*/* 也可以工作,因为 gdm 始终存在,但这样更有趣。跨度>
  • 您(和其他人)不断提到真正的.Xauthority 在其他地方,但在哪里?如果~ 中的那个是陈旧的,为什么它会有效?
  • 这是“完全正确”的,因为它“简单有效”。我不知道为什么。这就是我提出 +50 赏金的原因。
  • 我认为您正在混合解决方案。如果您以登录用户身份执行xhost +si:localuser:root,则无论 XAUTHORITY 变量和文件是什么,root 都将具有访问权限。 Ubuntu 中的 GDM(你在使用它吗?)不再将 .Xauthority 保存在 ~ 中,而是在 /var/run/gdm/auth-for-* 中。
  • 我不太了解技术细节(因此是我的问题),但事实(最重要的)是这个解决方案确实有效。我更喜欢使用适用于任何登录用户的旧方法,而不是硬编码的方法,但我没有看到(或找到)任何方法。
【解决方案4】:

较新版本的 Ubuntu 使用不同的显示管理器,因此您必须知道您使用的是哪一个。 在 Rodrigo 的帖子中,有一个提示显示如何使用以下命令发现它:

ls /var/run/gdm/auth-for-gdm-*/database

要检查这一点,请列出 /var/run 目录并使用“pgrep -a Xorg”命令。 在 Ubuntu 16* 中,它使用 sddm,因此,您可以使用

ls /var/run/sddm* 导出 XAUTHORITY 变量。

脚本是这样的:

#!/bin/bash
export DISPLAY=:0
export XAUTHORITY=`ls /var/run/sddm*`
HDMI_STATUS="$(cat /sys/class/drm/card0-HDMI-A-1/status)"
USER="your username"
export XAUTHORITY=/home/$USER/.Xauthority
export DISPLAY=:0

if [ "$HDMI_STATUS" = connected ];
then
sudo -u $USER pactl set-card-profile 0 output:hdmi-stereo+input:analog-stereo
else
sudo -u $USER pactl set-card-profile 0 output:analog-stereo+input:analog-stereo
fi
exit 0

然后运行:

sudo chmod 755 /usr/local/bin/toggle-sound

echo 'ACTION=="change", SUBSYSTEM=="drm", RUN+="/usr/local/bin/toggle-sound"' | sudo tee /etc/udev/rules.d/99-hdmi-sound.rules

sudo udevadm control --reload-rules

【讨论】:

    【解决方案5】:

    我必须在 Kali Linux 2016 中使用它才能让它工作:

    #!/bin/bash
    set -x
    xhost local:root
    export DISPLAY=:0.0
    su root -c 'zenity --notification --text="I am a notification!"'
    

    【讨论】:

      【解决方案6】:

      如果直接从 udev 调用脚本不起作用,为什么不启动一个调用该脚本的 systemd 服务?

      这是我的解决方案:

      首先是在拔出具有 ID_PART_ENTRY_UUID 的设备(或分区)时运行 media-storage-unplugged.service 的 udev 规则

      /etc/udev/rules.d/storage-unplugged.rules:

      ACTION=="remove", KERNEL=="sd[a-z][0-9]", ENV{ID_PART_ENTRY_UUID}=="replace-with-your-uuid", SYMLINK+="storage", RUN+="/usr/bin/systemctl --no-block start media-storage-unplugged.service"
      

      /etc/systemd/system/media-storage-unplugged.service:(服务文件)

      [Unit]
      Description=Triggered when storage is unplugged
      
      [Service]
      Type=oneshot
      ExecStart=/usr/local/bin/storage_unplugged
      
      [Install]
      WantedBy=multi-user.target
      

      /usr/local/bin/storage_unplugged(在这里发挥创意)

      #!/bin/bash
      notify-send-to-user "storage unplugged"
      exit 0
      

      /usr/local/bin/notify-send-to-user

      #!/bin/bash
      
      function ns() {
          #Detect the name of the display in use
          local display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"
      
          #Detect the user using such display (NOTE: Didn't work on Arch linux since the "who" command doesn't show which display the user is using)
          #local user=$(who | grep '('$display')' | awk '{print $1}' | head -n 1)
          #Statically assign user:
          local user="user" # Replace with your user
      
          #Detect the id of the user
          local uid=$(id -u $user)
      
          sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@"
      }
      
      ns "$@"
      

      根据您的需要调整此方法:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-22
        • 1970-01-01
        相关资源
        最近更新 更多