Egidio Docile 发布的文章

目的

使用 GNU Stow 轻松管理从源代码安装的程序和点文件(LCTT 译注: 点文件 dotfile ,即以 . 开头的文件,在 *nix 下默认为隐藏文件,常用于存储程序的配置信息。)

要求

  • root 权限

难度

简单

约定

  • # - 给定的命令要求直接以 root 用户身份或使用 sudo 命令以 root 权限执行
  • $ - 给定的命令将作为普通的非特权用户来执行

介绍

有时候我们必须从源代码安装程序,因为它们也许不能通过标准渠道获得,或者我们可能需要特定版本的软件。 GNU Stow 是一个非常不错的 符号链接工厂 symlinks factory 程序,它可以帮助我们保持文件的整洁,易于维护。

获得 stow

你的 Linux 发行版本很可能包含 stow,例如在 Fedora,你安装它只需要:

# dnf install stow

在 Ubuntu/Debian 中,安装 stow 需要执行:

# apt install stow

在某些 Linux 发行版中,stow 在标准库中是不可用的,但是可以通过一些额外的软件源(例如 RHEL 和 CentOS7 中的EPEL )轻松获得,或者,作为最后的手段,你可以从源代码编译它。只需要很少的依赖关系。

从源代码编译

最新的可用 stow 版本是 2.2.2。源码包可以在这里下载:https://ftp.gnu.org/gnu/stow/

一旦你下载了源码包,你就必须解压它。切换到你下载软件包的目录,然后运行:

$ tar -xvpzf stow-2.2.2.tar.gz

解压源文件后,切换到 stow-2.2.2 目录中,然后编译该程序,只需运行:

$ ./configure
$ make

最后,安装软件包:

# make install

默认情况下,软件包将安装在 /usr/local/ 目录中,但是我们可以改变它,通过配置脚本的 --prefix 选项指定目录,或者在运行 make install 时添加 prefix="/your/dir"

此时,如果所有工作都按预期工作,我们应该已经在系统上安装了 stow

stow 是如何工作的?

stow 背后主要的概念在程序手册中有很好的解释:

Stow 使用的方法是将每个软件包安装到自己的目录树中,然后使用符号链接使它看起来像文件一样安装在公共的目录树中

为了更好地理解这个软件的运作,我们来分析一下它的关键概念:

stow 文件目录

stow 目录是包含所有 stow 软件包的根目录,每个包都有自己的子目录。典型的 stow 目录是 /usr/local/stow:在其中,每个子目录代表一个软件包。

stow 软件包

如上所述,stow 目录包含多个“软件包”,每个软件包都位于自己单独的子目录中,通常以程序本身命名。包就是与特定软件相关的文件和目录列表,作为一个实体进行管理。

stow 目标目录

stow 目标目录解释起来是一个非常简单的概念。它是包文件应该安装到的目录。默认情况下,stow 目标目录被视作是调用 stow 的目录。这种行为可以通过使用 -t 选项( --target 的简写)轻松改变,这使我们可以指定一个替代目录。

一个实际的例子

我相信一个好的例子胜过 1000 句话,所以让我来展示 stow 如何工作。假设我们想编译并安装 libx264,首先我们克隆包含其源代码的仓库:

$ git clone git://git.videolan.org/x264.git

运行该命令几秒钟后,将创建 x264 目录,它将包含准备编译的源代码。我们切换到 x264 目录中并运行 configure 脚本,将 --prefix 指定为 /usr/local/stow/libx264 目录。

$ cd x264 && ./configure --prefix=/usr/local/stow/libx264

然后我们构建该程序并安装它:

$ make
# make install

x264 目录应该创建在 stow 目录内:它包含了所有通常直接安装在系统中的东西。 现在,我们所要做的就是调用 stow。 我们必须从 stow 目录内运行这个命令,通过使用 -d 选项来手动指定 stow 目录的路径(默认为当前目录),或者通过如前所述用 -t 指定目标。我们还应该提供要作为参数存储的软件包的名称。 在这里,我们从 stow 目录运行程序,所以我们需要输入的内容是:

# stow libx264

libx264 软件包中包含的所有文件和目录现在已经在调用 stow 的父目录 (/usr/local) 中进行了符号链接,因此,例如在 /usr/local/ stow/x264/bin 中包含的 libx264 二进制文件现在符号链接在 /usr/local/bin 之中,/usr/local/stow/x264/etc 中的文件现在符号链接在 /usr/local/etc 之中等等。通过这种方式,系统将显示文件已正常安装,并且我们可以容易地跟踪我们编译和安装的每个程序。要反转该操作,我们只需使用 -D 选项:

# stow -d libx264

完成了!符号链接不再存在:我们只是“卸载”了一个 stow 包,使我们的系统保持在一个干净且一致的状态。 在这一点上,我们应该清楚为什么 stow 还可以用于管理点文件。 通常的做法是在 git 仓库中包含用户特定的所有配置文件,以便轻松管理它们并使它们在任何地方都可用,然后使用 stow 将它们放在适当位置,如放在用户主目录中。

stow 还会阻止你错误地覆盖文件:如果目标文件已经存在,并且没有指向 stow 目录中的包时,它将拒绝创建符号链接。 这种情况在 stow 术语中称为冲突。

就是这样!有关选项的完整列表,请参阅 stow 帮助页,并且不要忘记在评论中告诉我们你对此的看法。


via: https://linuxconfig.org/how-to-use-gnu-stow-to-manage-programs-installed-from-source-and-dotfiles

作者:Egidio Docile 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

目标

学习在 Linux 上使用 pass 密码管理器来管理你的密码

条件

  • 需要 root 权限来安装需要的包

难度

简单

约定

  • # - 执行指定命令需要 root 权限,可以是直接使用 root 用户来执行或者使用 sudo 命令来执行
  • $ - 使用普通的非特权用户执行指定命令

介绍

如果你有根据不同的意图设置不同密码的好习惯,你可能已经感受到需要一个密码管理器的必要性了。在 Linux 上有很多选择,可以是专有软件(如果你敢用的话)也可以是开源软件。如果你跟我一样喜欢简洁的话,你可能会对 pass 感兴趣。

第一步

pass 作为一个密码管理器,其实际上是一些你可能早已每天使用的、可信赖且实用的工具的一种封装,比如 gpggit 。虽然它也有图形界面,但它专门设计能成在命令行下工作的:因此它也可以在 headless 机器上工作(LCTT 译注:根据 wikipedia 的说法,所谓 headless 是指没有显示器、键盘和鼠标的机器,一般通过网络链接来控制)。

安装

pass 在主流的 Linux 发行版中都是可用的,你可以通过包管理器安装:

Fedora

# dnf install pass

RHEL 和 CentOS

pass 不在官方仓库中,但你可以从 epel 中获取道它。要在 CentOS7 上启用后面这个源,只需要执行:

# yum install epel-release

然而在 Red Hat 企业版的 Linux 上,这个额外的源是不可用的;你需要从 EPEL 官方网站上下载它。

Debian 和 Ubuntu

# apt-get install pass

Arch Linux

# pacman -S pass

初始化密码仓库

安装好 pass 后,就可以开始使用和配置它了。首先,由于 pass 依赖于 gpg 来对我们的密码进行加密并以安全的方式进行存储,我们必须准备好一个 gpg 密钥对。

首先我们要初始化密码仓库:这就是一个用来存放 gpg 加密后的密码的目录。默认情况下它会在你的 $HOME 创建一个隐藏目录,不过你也可以通过使用 PASSWORD_STORE_DIR 这一环境变量来指定另一个路径。让我们运行:

$ pass init

然后 password-store 目录就创建好了。现在,让我们来存储我们第一个密码:

$ pass edit mysite

这会打开默认文本编辑器,我么只需要输入密码就可以了。输入的内容会用 gpg 加密并存储为密码仓库目录中的 mysite.gpg 文件。

pass 以目录树的形式存储加密后的文件,也就是说我们可以在逻辑上将多个文件放在子目录中以实现更好的组织形式,我们只需要在创建文件时指定存在哪个目录下就行了,像这样:

$ pass edit foo/bar

跟上面的命令一样,它也会让你输入密码,但是创建的文件是放在密码仓库目录下的 foo 子目录中的。要查看文件组织结构,只需要不带任何参数运行 pass 命令即可:

$ pass
Password Store
├── foo
│   └── bar
└── mysite

若想修改密码,只需要重复创建密码的操作就行了。

获取密码

有两种方法可以获取密码:第一种会显示密码到终端上,方法是运行:

pass mysite

然而更好的方法是使用 -c 选项让 pass 将密码直接拷贝到剪切板上:

pass -c mysite

这种情况下剪切板中的内容会在 45 秒后自动清除。两种方法都会要求你输入 gpg 密码。

生成密码

pass 也可以为我们自动生成(并自动存储)安全密码。假设我们想要生成一个由 15 个字符组成的密码:包含字母,数字和特殊符号,其命令如下:

pass generate mysite 15

若希望密码只包含字母和数字则可以是使用 --no-symbols 选项。生成的密码会显示在屏幕上。也可以通过 --clip-c 选项让 pass 把密码直接拷贝到剪切板中。通过使用 -q--qrcode 选项来生成二维码:

qrcode

从上面的截屏中可看出,生成了一个二维码,不过由于运行该命令时 mysite 的密码已经存在了,pass 会提示我们确认是否要覆盖原密码。

pass 使用 /dev/urandom 设备作为(伪)随机数据生成器来生成密码,同时它使用 xclip 工具来将密码拷贝到粘帖板中,而使用 qrencode 来将密码以二维码的形式显示出来。在我看来,这种模块化的设计正是它最大的优势:它并不重复造轮子,而只是将常用的工具包装起来完成任务。

你也可以使用 pass mvpass cppass rm 来重命名、拷贝和删除密码仓库中的文件。

将密码仓库变成 git 仓库

pass 另一个很棒的功能就是可以将密码仓库当成 git 仓库来用:通过版本管理系统能让我们管理密码更方便。

pass git init

这会创建 git 仓库,并自动提交所有已存在的文件。下一步就是指定跟踪的远程仓库了:

pass git remote add <name> <url>

我们可以把这个密码仓库当成普通仓库来用。唯一的不同点在于每次我们新增或修改一个密码,pass 都会自动将该文件加入索引并创建一个提交。

pass 有一个叫做 qtpass 的图形界面,而且也支持 Windows 和 MacOs。通过使用 PassFF 插件,它还能获取 firefox 中存储的密码。在它的项目网站上可以查看更多详细信息。试一下 pass 吧,你不会失望的!


via: https://linuxconfig.org/how-to-organize-your-passwords-using-pass-password-manager

作者:Egidio Docile 译者:lujun9972 校对:Locez

本文由 LCTT 原创编译,Linux中国 荣誉推出

读者对象

理解 udev 背后的基本概念,学习如何写简单的规则。

要求

  • root 权限

难度

中等

约定

  • # - 要求给定的命令使用 root 权限或者直接以一个 root 用户或者使用 sudo 命令去运行。
  • $ - 要求给定的命令以一个普通的非特权用户运行。

介绍

在 GNU/Linux 系统中,虽然设备的底层支持是在内核层面处理的,但是,它们相关的事件管理是在用户空间中通过 udev 来管理的。确切地说是由 udevd 守护进程来完成的。学习如何去写规则,并应用到发生的这些事件上,将有助于我们修改系统的行为并使它适合我们的需要。

规则如何组织

udev 规则是定义在一个以 .rules 为扩展名的文件中。那些文件主要放在两个位置:/usr/lib/udev/rules.d,这个目录用于存放系统安装的规则;/etc/udev/rules.d/ 这个目录是保留给自定义规则的。

定义那些规则的文件的命名惯例是使用一个数字作为前缀(比如,50-udev-default.rules),并且以它们在目录中的词汇顺序进行处理的。在 /etc/udev/rules.d 中安装的文件,会覆盖安装在系统默认路径中的同名文件。

规则语法

如果你理解了 udev 规则的行为逻辑,它的语法并不复杂。一个规则由两个主要的节构成:match 部分,它使用一系列用逗号分隔的键定义了规则应用的条件,而 action 部分,是当条件满足时,我们执行一些动作。

测试案例

讲解可能的选项的最好方法莫过于配置一个真实的案例,因此,我们去定义一个规则作为演示,当鼠标被连接时禁用触摸板。显然,在该规则定义中提供的属性将反映我的硬件。

我们将在 /etc/udev/rules.d/99-togglemouse.rules 文件中用我们喜欢的文本编辑器来写我们的规则。一条规则定义允许跨多个行,但是,如果是这种情况,必须在一个换行字符之前使用一个反斜线(\)表示行的延续,就和 shell 脚本一样。这是我们的规则:

ACTION=="add" \
, ATTRS{idProduct}=="c52f" \
, ATTRS{idVendor}=="046d" \
, ENV{DISPLAY}=":0" \
, ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority" \
, RUN+="/usr/bin/xinput --disable 16"

我们来分析一下这个规则。

操作符

首先,对已经使用以及将要使用的操作符解释如下:

== 和 != 操作符

== 是相等操作符,而 != 是不等于操作符。通过使用它们,我们可以确认规则上应用的键是否匹配各自的值。

分配操作符 = 和 :=

= 是赋值操作符,是用于为一个键赋值。当我们想要赋值,并且想确保它不会被其它规则所覆盖,我们就需要使用 := 操作符来代替,使用这个操作符分配的值,它就不能被改变。

+= 和 -= 操作符

+=-= 操作符各自用于从一个指定的键定义的值列表中增加或者移除一个值。

我们使用的键

现在,来分析一下在这个规则中我们使用的键。首先,我们有一个 ACTION 键:通过使用它,当在一个设备上发生了特定的事件,我们将指定我们要应用的规则的具体内容。有效的值有 addremove 以及 change

然后,我们使用 ATTRS 关键字去指定一个属性去匹配。我们可以使用 udevadm info 命令去列出一个设备属性,提供它的名字或者 sysfs 路径即可:

udevadm info -ap /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39':
    KERNEL=="input39"
    SUBSYSTEM=="input"
    DRIVER==""
    ATTR{name}=="Logitech USB Receiver"
    ATTR{phys}=="usb-0000:00:1d.0-1.2/input1"
    ATTR{properties}=="0"
    ATTR{uniq}==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010':
    KERNELS=="0003:046D:C52F.0010"
    SUBSYSTEMS=="hid"
    DRIVERS=="hid-generic"
    ATTRS{country}=="00"

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1':
    KERNELS=="2-1.2:1.1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usbhid"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceClass}=="03"
    ATTRS{bInterfaceNumber}=="01"
    ATTRS{bInterfaceProtocol}=="00"
    ATTRS{bInterfaceSubClass}=="00"
    ATTRS{bNumEndpoints}=="01"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':
    KERNELS=="2-1.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{bMaxPower}=="98mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 2"
    ATTRS{bcdDevice}=="3000"
    ATTRS{bmAttributes}=="a0"
    ATTRS{busnum}=="2"
    ATTRS{configuration}=="RQR30.00_B0009"
    ATTRS{devnum}=="12"
    ATTRS{devpath}=="1.2"
    ATTRS{idProduct}=="c52f"
    ATTRS{idVendor}=="046d"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Logitech"
    ATTRS{maxchild}=="0"
    ATTRS{product}=="USB Receiver"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="removable"
    ATTRS{speed}=="12"
    ATTRS{urbnum}=="1401"
    ATTRS{version}==" 2.00"

    [...]

上面截取了运行这个命令之后的输出的一部分。正如你从它的输出中看到的那样,udevadm 从我们提供的指定路径开始,并且提供了所有父级设备的信息。注意设备的属性都是以单数的形式报告的(比如,KERNEL),而它的父级是以复数形式出现的(比如,KERNELS)。父级信息可以做为规则的一部分,但是同一时间只能有一个父级可以被引用:不同父级设备的属性混合在一起是不能工作的。在上面我们定义的规则中,我们使用了一个父级设备属性:idProductidVendor

在我们的规则中接下来做的事情是,去使用 ENV 关键字:它既可以用于设置也可以用于去匹配环境变量。我们给 DISPLAYXAUTHORITY 分配值。当我们使用 X 服务器程序进行交互去设置一些需要的信息时,这些变量是非常必要的:使用 DISPLAY 变量,我们指定服务器运行在哪个机器上,用的是哪个显示和屏幕;使用 XAUTHORITY 提供了一个文件路径,其包含了 Xorg 认证和授权信息。这个文件一般位于用户的家目录中。

最后,我们使用了 RUN 字:它用于运行外部程序。非常重要:这里没有立即运行,但是一旦所有的规则被解析,将运行各种动作。在这个案例中,我们使用 xinput 实用程序去改变触摸板的状态。我不想解释这里的 xinput 的语法,它超出了本文的范围,只需要注意这个触摸板的 ID 是 16

规则设置完成之后,我们可以通过使用 udevadm test 命令去调试它。这个命令对调试非常有用,它并不真实去运行 RUN 指定的命令:

$ udevadm test --action="add" /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39

我们提供给命令的是使用 --action 选项,以及设备的 sysfs 路径的模拟动作。如果没有报告错误,说明我们的规则运行的很好。要在真实的环境中去使用它,我们需要重新加载规则:

# udevadm control --reload

这个命令将重新加载规则文件,但是,它只对重新加载之后发生的事件有效果。

我们通过创建一个 udev 规则了解了基本的概念和逻辑,这只是 udev 规则中众多的选项和可能的设置中的一小部分。udev 手册页提供了一个详尽的列表,如果你想深入了解,请参考它。


via: https://linuxconfig.org/tutorial-on-how-to-write-basic-udev-rules-in-linux

作者:Egidio Docile 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

目标

了解特殊权限的工作原理,以及如何识别和设置它们。

要求

难度

简单

约定

  • # - 要求直接以 root 用户或使用 sudo 命令执行指定的命令
  • $ - 用普通的非特权用户来执行指定的命令

介绍

通常,在类 Unix 操作系统上,文件和目录的所有权是基于文件创建者的默认 uid(user-id)和 gid(group-id)的。启动一个进程时也是同样的情况:它以启动它的用户的 uidgid 运行,并具有相应的权限。这种行为可以通过使用特殊的权限进行改变。

setuid 位

当使用 setuid (设置用户 ID)位时,之前描述的行为会有所变化,所以当一个可执行文件启动时,它不会以启动它的用户的权限运行,而是以该文件所有者的权限运行。所以,如果在一个可执行文件上设置了 setuid 位,并且该文件由 root 拥有,当一个普通用户启动它时,它将以 root 权限运行。显然,如果 setuid 位使用不当的话,会带来潜在的安全风险。

使用 setuid 权限的可执行文件的例子是 passwd,我们可以使用该程序更改登录密码。我们可以通过使用 ls 命令来验证:

ls -l /bin/passwd
-rwsr-xr-x. 1 root root 27768 Feb 11 2017 /bin/passwd

如何识别 setuid 位呢?相信您在上面命令的输出已经注意到,setuid 位是用 s 来表示的,代替了可执行位的 x。小写的 s 意味着可执行位已经被设置,否则你会看到一个大写的 S。大写的 S 发生于当设置了 setuidsetgid 位、但没有设置可执行位 x 时。它用于提醒用户这个矛盾的设置:如果可执行位未设置,则 setuidsetgid 位均不起作用。setuid 位对目录没有影响。

setgid 位

setuid 位不同,setgid (设置组 ID)位对文件和目录都有影响。在第一个例子中,具有 setgid 位设置的文件在执行时,不是以启动它的用户所属组的权限运行,而是以拥有该文件的组运行。换句话说,进程的 gid 与文件的 gid 相同。

当在一个目录上使用时,setgid 位与一般的行为不同,它使得在所述目录内创建的文件,不属于创建者所属的组,而是属于父目录所属的组。这个功能通常用于文件共享(目录所属组中的所有用户都可以修改文件)。就像 setuid 一样,setgid 位很容易识别(我们用 test 目录举例):

ls -ld test
drwxrwsr-x. 2 egdoc egdoc 4096 Nov 1 17:25 test

这次 s 出现在组权限的可执行位上。

sticky 位

sticky (粘连)位的工作方式有所不同:它对文件没有影响,但当它在目录上使用时,所述目录中的所有文件只能由其所有者删除或移动。一个典型的例子是 /tmp 目录,通常系统中的所有用户都对这个目录有写权限。所以,设置 sticky 位使用户不能删除其他用户的文件:

$ ls -ld /tmp
drwxrwxrwt. 14 root root 300 Nov 1 16:48 /tmp

在上面的例子中,目录所有者、组和其他用户对该目录具有完全的权限(读、写和执行)。sticky 位在可执行位上用 t 来标识。同样,小写的 t 表示可执行权限 x也被设置了,否则你会看到一个大写字母 T

如何设置特殊权限位

就像普通的权限一样,特殊权限位可以用 chmod 命令设置,使用数字或者 ugo/rwx 格式。在前一种情况下,setuidsetgidsticky 位分别由数值 4、2 和 1 表示。例如,如果我们要在目录上设置 setgid 位,我们可以运行:

$ chmod 2775 test

通过这个命令,我们在目录上设置了 setgid 位(由四个数字中的第一个数字标识),并给它的所有者和该目录所属组的所有用户赋予全部权限,对其他用户赋予读和执行的权限(目录上的执行位意味着用户可以 cd 进入该目录或使用 ls 列出其内容)。

另一种设置特殊权限位的方法是使用 ugo/rwx 语法:

$ chmod g+s test

要将 setuid 位应用于一个文件,我们可以运行:

$ chmod u+s file

要设置 sticky 位,可运行:

$ chmod o+t test

在某些情况下,使用特殊权限会非常有用。但如果使用不当,可能会引入严重的漏洞,因此使用之前请三思。


via: https://linuxconfig.org/how-to-use-special-permissions-the-setuid-setgid-and-sticky-bits

作者:Egidio Docile 译者:jessie-pang 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出