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
  • 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 '13 at 9:02
  • Agreed - this is a very bad idea. – Jenny D Mar 25 '13 at 9:03
  • for testing purposes – Mickael Ciocca Mar 25 '13 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 '13 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 '13 at 9:07

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-
    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. Search the directory for useradd's source file, which ideally should be called useradd.c:

    $ find . -name useradd.c


  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):

          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.

  • 1
    What a beautifully-presented and well-researched answer. I'd give it +10 if I could. – MadHatter Mar 25 '13 at 13:52
  • @jaume - Awesome! – Mickael Ciocca Apr 6 '13 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! – Mickael Ciocca Apr 6 '13 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 '13 at 18:02
  • Interestingly, the reference lists passwd and group below the header "The following files, or symbolic links to files, must be in /etc" – Charlie Gorichanaz Aug 6 '17 at 1:45

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.

  • i'll take a look at ldap and nis – Mickael Ciocca Mar 25 '13 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 '13 at 13:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.