8

i'm having trouble with useradd when im moving /etc/passwd /etc/shadow /etc/group from /etc to /home and create a symlink in order to have /etc/{passwd,shadow,group} respecively pointing to /home/{passwd,shadow,group}

i cannot create any user and have useradd outputing:

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

btw useradd output is

root@client:/home# adduser testuser
useradd: cannot open /etc/passwd
8
  • 1
    I'm not surprised; the locations and nature of /etc/passwd and /etc/group in particular are very long-standing UNIX concepts. Why are you trying to do this?
    – MadHatter
    Mar 25, 2013 at 9:02
  • Agreed - this is a very bad idea.
    – Jenny D
    Mar 25, 2013 at 9:03
  • for testing purposes Mar 25, 2013 at 9:04
  • 1
    If /etc and /home reside in the same filesystem, you could use hardlinks (ln without the -s option).
    – jaume
    Mar 25, 2013 at 9:07
  • 1
    That's a vague response... I'm afraid you're still stuck with "don't do this".
    – Jenny D
    Mar 25, 2013 at 9:07

3 Answers 3

31

Why does useradd refuse to open a symlinked /etc/passwd?

To answer the question we need to take a look at the source code of useradd (I did this on Ubuntu 12.04, on Debian it may differ slightly):

  1. Find out which package owns /usr/sbin/useradd:

    $ dpkg-query -S /usr/sbin/useradd
    passwd: /usr/sbin/useradd
    
  2. Install the source:

    $ 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 to the source directory:

    $ cd shadow-4.1.4.2+svn3283/
    
  4. Search the directory for useradd's source file, which ideally should be called useradd.c:

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

    Bingo!

  5. Look for error message cannot open /etc/passwd (in fact I only search for cannot open, since the whole string doesn't return any results):

    $ 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 means print 1 line of leading context before the matching line.

    This is where the error message you see is being generated. Function pw_open controls whether /etc/passwd can be opened or an error should be thrown.

    pw_open is not a Linux syscall (apropos pw_open doesn't return any results), so it is probably implemented within this package. Let's search for it.

  6. Tracing pw_open leads to:

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

    pw_open implementation is:

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

    Getting closer, but we're not there yet. commonio_open is our new objective.

  7. Search for commonio_open:

    $ grep -R commonio_open *
    (...)
    lib/commonio.c:int commonio_open (struct commonio_db *db, int mode)
    
  8. Open lib/commonio.c and scroll to function 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);
    

    Do you see O_NOFOLLOW? This is the culprit (from man 2 open):

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

Summarizing, useradd.c uses pw_open, which in turn uses commonio_open, which opens /etc/passwd using syscall open with option O_NOFOLLOW, that rejects symbolic links.

Although a symlink can be used as a replacement of a file in many (I'd say most) situations, useradd is quite picky and rejects it, probably because a symlinked /etc/passwd strongly suggests that /etc has been tampered with.

Why should I leave passwd in /etc?

There are several files in /etc needed to boot and log in, for example (but not limited to): fstab, inittab, passwd, shadow and the init scripts in init.d/. Any sysadmin expects those files to be there, not symlinked to /home or wherever.

So even if you could, you should leave passwd in /etc.

Furthermore, the filesystem structure in Linux is well defined, take a look at it here: http://www.pathname.com/fhs/pub/fhs-2.3.html. There is also a chapter for /etc. Moving things around is not recommended.

6
  • 3
    What a beautifully-presented and well-researched answer. I'd give it +10 if I could.
    – MadHatter
    Mar 25, 2013 at 13:52
  • 1
    @jaume - Awesome! Apr 6, 2013 at 16:37
  • 1
    Sorry for this late answer On debian useradd uses open (2) With strace we can see that write(2) on passwd fail because open(2) has O_NOFOLLOW flag and returned -1 you were right! Apr 6, 2013 at 17:25
  • Thanks, I'm glad I could help. I also used strace but somehow I didn't manage to find the relevant line, it's great you did!
    – jaume
    Apr 6, 2013 at 18:02
  • 1
    Amazing thorough investigation 👏
    – 3wordchant
    Mar 4 at 14:52
2

Doctor, it hurts when I do this.

Well, don't do it then!

Seriously, don't stick files as critical as that in an unexpected location. Whatever you're trying to test: find a better way. If you're trying to do central authentication: use ldap. Or nis if you must.

2
  • i'll take a look at ldap and nis Mar 25, 2013 at 9:24
  • 2
    If I were the doctor I'd say 'Let me take a look!'. My diagnosis (and recommendation) is in my answer below.
    – jaume
    Mar 25, 2013 at 13:49
0

System unable to make any changes on the files /etc/passwd, /etc/shadow

Regenerate issue:

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

Below shows that files are immutable, If you set the -i argument, a file will be marked as "immutable", meaning its data (and some vital metadata) cannot be changed, even by root, until the attribute is unset.

List the attributes:

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

Change the file attribute :

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

Try to add user:

[root@salten]# useradd apache

It works !!!

1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Apr 24, 2022 at 18:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .