Por que useradd
se recusa a abrir um link simbólico /etc/passwd
?
Para responder a pergunta, precisamos dar uma olhada no código-fonte de useradd
(eu fiz isso no Ubuntu 12.04, no Debian ele pode ser um pouco diferente):
-
Descubra qual pacote possui
/usr/sbin/useradd
:$ dpkg-query -S /usr/sbin/useradd passwd: /usr/sbin/useradd
-
Instale a fonte:
$ 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 (...)
-
cd
no diretório de origem:$ cd shadow-4.1.4.2+svn3283/
-
Pesquise no diretório o arquivo de origem de
useradd
, que idealmente deve ser chamado deuseradd.c
:$ find . -name useradd.c ./src/useradd.c
Bingo!
-
Procure a mensagem de erro
cannot open /etc/passwd
(na verdade, só pesquisocannot open
, pois a string inteira não retorna nenhum resultado):$ 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
significa imprimir 1 linha do contexto principal antes da linha correspondente.Aqui é onde a mensagem de erro que você vê está sendo gerada. A função
pw_open
controla se/etc/passwd
pode ser aberto ou se deve ser gerado um erro.pw_open
não é um syscall do Linux (apropos pw_open
não retorna nenhum resultado), então é provavelmente implementado dentro deste pacote. Vamos procurar por isso. -
Rastrear
pw_open
leva a:$ grep -R pw_open * (...) lib/pwio.c:int pw_open (int mode) (...)
A implementação
pw_open
é:$ grep -A 3 'int pw_open (int mode)' lib/pwio.c int pw_open (int mode) { return commonio_open (&passwd_db, mode); }
Chegando mais perto, mas ainda não chegamos lá.
commonio_open
é o nosso novo objetivo. -
Pesquise
commonio_open
:$ grep -R commonio_open * (...) lib/commonio.c:int commonio_open (struct commonio_db *db, int mode)
-
Abra
lib/commonio.c
e role para a funçãocommonio_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);
Você vê
O_NOFOLLOW
? Este é o culpado (deman 2 open
):O_NOFOLLOW If pathname is a symbolic link, then the open fails.
Resumindo, useradd.c
usa pw_open
, que por sua vez usa commonio_open
, que abre /etc/passwd
usando syscall open
com a opção O_NOFOLLOW
, que rejeita links simbólicos.
Embora um symlink possa ser usado como um substituto de um arquivo em muitas (eu diria a maioria) situações, useradd
é bastante exigente e o rejeita, provavelmente porque um /etc/passwd
com link simbólico sugere strongmente que /etc
tem foi adulterado.
Por que devo deixar o passwd
em /etc
?
Existem vários arquivos em /etc
necessários para inicializar e fazer login, por exemplo (mas não limitados a): fstab
, inittab
, passwd
, shadow
e os scripts de inicialização em init.d/
. Qualquer sysadmin espera que esses arquivos estejam lá, não ligados simbolicamente a /home
ou a qualquer lugar.
Então, mesmo que você pudesse, você deveria deixar passwd
em /etc
.
Além disso, a estrutura do sistema de arquivos no Linux é bem definida, dê uma olhada aqui: link . Há também um capítulo para /etc
. Não é recomendável mudar as coisas.