当 /etc/{passwd,shadow,group} 为符号链接时无法 useradd/adduser (debian squeeze)

当 /etc/{passwd,shadow,group} 为符号链接时无法 useradd/adduser (debian squeeze)

当我将 /etc/passwd /etc/shadow /etc/group 从 /etc 移动到 /home 并创建符号链接以便 /etc/{passwd,shadow,group} 分别指向 /home/{passwd,shadow,group} 时,我在 useradd 方面遇到了问题

我无法创建任何用户并有 useradd 输出:

root@client:/home# useradd testuser
Adding user `testuser' ...
Adding new group `testuser' (1000) ...
groupadd: cannot open /etc/group

顺便说一下 useradd 输出是

root@client:/home# adduser testuser
useradd: cannot open /etc/passwd

答案1

为什么useradd拒绝打开符号链接/etc/passwd

要回答这个问题,我们需要看一下源代码useradd(我在 Ubuntu 12.04 上做了这个,在 Debian 上可能略有不同):

  1. 找出哪个包拥有/usr/sbin/useradd

    $ dpkg-query -S /usr/sbin/useradd
    passwd: /usr/sbin/useradd
    
  2. 安装源:

    $ apt-get source passwd
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    Picking 'shadow' as source package instead of 'passwd'
    (...)
    dpkg-source: info: extracting shadow in shadow-4.1.4.2+svn3283
    dpkg-source: info: unpacking shadow_4.1.4.2+svn3283.orig.tar.gz
    dpkg-source: info: applying shadow_4.1.4.2+svn3283-3ubuntu5.1.diff.gz
    (...)
    
  3. cd到源目录:

    $ cd shadow-4.1.4.2+svn3283/
    
  4. 在目录中搜索 的useradd源文件,理想情况下该文件应该被称为useradd.c

    $ find . -name useradd.c
    ./src/useradd.c
    

    答对了!

  5. 查找错误消息cannot open /etc/passwd(实际上我只搜索cannot open,因为整个字符串没有返回任何结果):

    $ grep -B 1 'cannot open' src/useradd.c
    (...)
      if (pw_open (O_RDWR) == 0) {
          fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ());
    (...)
    

    -B 1表示在匹配行之前打印 1 行前导上下文。

    这就是您看到的错误消息生成的地方。函数pw_open控制是否/etc/passwd可以打开或是否应抛出错误。

    pw_open不是Linux系统调用apropos pw_open没有返回任何结果),所以它很可能在这个包中实现。我们来搜索一下。

  6. 追踪结果pw_open显示:

    $ grep -R pw_open * 
    (...)
    lib/pwio.c:int pw_open (int mode)
    (...)
    

    pw_open实施方案是:

    $ grep -A 3 'int pw_open (int mode)' lib/pwio.c 
    int pw_open (int mode)
    {
        return commonio_open (&passwd_db, mode);
    }
    

    越来越近了,但我们还没有到达。commonio_open这是我们的新目标。

  7. 搜索commonio_open

    $ grep -R commonio_open *
    (...)
    lib/commonio.c:int commonio_open (struct commonio_db *db, int mode)
    
  8. 打开lib/commonio.c并滚动到功能commonio_open

    int commonio_open (struct commonio_db *db, int mode)
    {
    (...)
    
        fd = open (db->filename,
                     (db->readonly ? O_RDONLY : O_RDWR)
                   | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
    

    你看到了O_NOFOLLOW吗?这就是罪魁祸首(来自man 2 open):

    O_NOFOLLOW 
          If pathname is a symbolic link, then the open fails.
    

总而言之,useradd.c使用pw_open,进而使用,使用带有选项的系统调用commonio_open打开,拒绝符号链接。/etc/passwdopenO_NOFOLLOW

尽管在很多(我想说大多数)情况下符号链接可以用来替换文件,但它useradd却很挑剔并拒绝它,可能是因为符号链接/etc/passwd强烈暗示该文件/etc已被篡改。

我为什么要passwd离开/etc

启动和登录需要几个文件/etc,例如(但不限于):fstab、、和中的 init 脚本。任何系统管理员都希望这些文件在那里,而不是符号链接到inittab或任何地方。passwdshadowinit.d//home

因此,即使可以,你也应该passwd离开/etc

此外,Linux中的文件系统结构定义明确,请在此处查看:http://www.pathname.com/fhs/pub/fhs-2.3.html。还有一章/etc。不建议移动物品。

答案2

医生,我这样做的时候会很痛。

那就别这么做!

说真的,不要把如此重要的文件放在意想不到的位置。无论您要测试什么:找到更好的方法。如果您要进行集中身份验证:请使用 ldap。或者如果必须,请使用 nis。

答案3

系统无法对文件 /etc/passwd、/etc/shadow 进行任何更改

再生问题:

[root@ubuntu]# useradd salten
cannot open /etc/passwd
useradd: cannot open /etc/group
useradd: cannot open /etc/gshadow

下面显示文件是不可变的,如果您设置了参数-i,文件将被标记为“不可变”,这意味着它的数据(和一些重要的元数据)不能被更改,即使是由 root 更改,直到属性被取消设置。

列出属性:

[root@salten]#lsattr /etc/passwd
----i-------- /etc/shadow

更改文件属性:

[root@salten]# chattr -i /etc/passwd
[root@salten]# lsattr /etc/passwd
[root@salten]# chattr -i /etc/group
[root@salten]# chattr -i /etc/gshadow

尝试添加用户:

[root@salten]# useradd apache

有用 !!!

相关内容