Eu sou raiz Gostaria de saber se um usuário não root tem acesso de gravação a alguns arquivos - milhares deles. Como fazer isso de forma eficiente, evitando a criação de processos?
shell
files
permissions
users
Howard
fonte
fonte
access(2)
com um UID real definido adequadamente (por exemplo, viasetresuid(2)
ou o equivalente portátil)? Quero dizer, eu seria pressionado a fazer isso a partir do bash, mas tenho certeza que o Perl / Python pode lidar com isso.[ -w
geralmente usam o acesso (2) ou equivalente. Você também precisa definir os gids além do uid (como su ou sudo faz). O bash não tem suporte embutido para isso, mas o zsh possui.chgrp
em qualquer shell.Respostas:
Talvez assim:
O acima executado executa um único programa externo para cada arquivo, a saber
stat(1)
.Nota: Isso assume
bash(1)
, e a encarnação do Linux destat(1)
.Nota 2: Leia os comentários de Stéphane Chazelas abaixo para conhecer os perigos passados, presentes, futuros e potenciais e limitações dessa abordagem.
fonte
-
. Você pode modificá-lo para aceitar uma lista NUL delimitado vez comread -d ''
util-linux
) especificamente criados para Linux, o questat
você está se referindo não é, é um comando GNU que foi portado para a maioria dos sistemas, não apenas para Linux. Observe também que você tinha umstat
comando no Linux muito antes da gravação do GNUstat
(ostat
zsh builtin).stat(1)
". Estou me referindo a umstat(1)
que aceita a-c <format>
sintaxe, em oposição a, digamos, a sintaxe BSD-f <format>
. Eu também acredito que estava bem claro ao qual eu não estava me referindostat(2)
. Tenho certeza de que uma página wiki sobre a história dos comandos comuns seria bastante interessante.TL; DR
Você precisa perguntar ao sistema se o usuário tem permissão de gravação. A única maneira confiável é mudar o uid efetivo, o gid efetivo e os suplementos para o usuário e usar a
access(W_OK)
chamada do sistema (mesmo que tenha algumas limitações em alguns sistemas / configurações).E lembre-se de que não ter permissão de gravação em um arquivo não garante necessariamente que você não possa modificar o conteúdo do arquivo nesse caminho.
A história mais longa
Vamos considerar o que é necessário, por exemplo, para um usuário $ ter acesso de gravação
/foo/file.txt
(assumindo que nenhum/foo
e/foo/file.txt
sejam links simbólicos)?Ele precisa:
/
(não é necessárioread
)/foo
(não é necessárioread
)/foo/file.txt
Você já pode ver as abordagens (como @ lcd047 ou @ apaul's ) que verificam apenas a permissão de
file.txt
não funcionarão porque poderiam dizer quefile.txt
é gravável, mesmo que o usuário não tenha permissão de pesquisa/
ou/foo
.E uma abordagem como:
Também não funcionará porque não reportará os arquivos nos diretórios em que o usuário não tem acesso de leitura (em
find
execução como$user
não é possível o conteúdo), mesmo que ele possa gravá-los.Se esquecermos ACLs, sistemas de arquivos somente leitura, sinalizadores FS (como imutáveis), outras medidas de segurança (apparmor, SELinux, que podem até distinguir entre diferentes tipos de gravação) e focar apenas nos atributos tradicionais de permissão e propriedade, para obter uma com permissão (pesquisar ou escrever), isso já é bastante complicado e difícil de expressar com
find
.Você precisa:
Na
find
sintaxe, aqui como um exemplo com um usuário do uid 1 e dos gids 1 e 2, seria:Que alguém poda os diretórios que o usuário não tenha procurar certa para e para outros tipos de arquivos (links simbólicos excluídos como eles não são relevantes), cheques para acesso de gravação.
Se você também deseja considerar o acesso de gravação aos diretórios:
Ou para uma
$user
associação arbitrária e de seu grupo recuperada do banco de dados do usuário:(que é 3 processos totais:
id
,sed
efind
)O melhor aqui seria descer a árvore como raiz e verificar as permissões como usuário para cada arquivo.
(esse é um
find
processo mais umsudo
esh
processa a cada poucos milhares de arquivos[
eprintf
geralmente é construído no shell).Ou com
perl
:(3 processos totais:
find
,sudo
eperl
).Ou com
zsh
:(0 processo no total, mas armazena toda a lista de arquivos na memória)
Essas soluções dependem da
access(2)
chamada do sistema. Em vez de reproduzir o algoritmo que o sistema usa para verificar a permissão de acesso, pedimos que o sistema faça essa verificação com o mesmo algoritmo (que leva em conta permissões, ACLs, sinalizadores imutáveis, sistemas de arquivos somente leitura ... ), você tentaria abrir o arquivo para escrever, portanto, é o mais próximo que você vai chegar de uma solução confiável.Para testar as soluções fornecidas aqui, com as várias combinações de usuário, grupo e permissões, você pode:
Variando o usuário entre 1 e 2 e o grupo entre 1, 2 e 3 e limitando-nos aos 9 bits inferiores das permissões, já que são 9458694 arquivos criados. Isso para diretórios e novamente para arquivos.
Isso cria todas as combinações possíveis de
u<x>g<y>/<mode1>/u<z>g<w>/<mode2>
. O usuário com uid 1 e gids 1 e 2 teria acesso de gravação,u2g1/010/u2g3/777
mas nãou1g2/677/u1g1/777
por exemplo.Agora, todas essas soluções tentam identificar os caminhos dos arquivos que o usuário pode abrir para gravação, diferente dos caminhos em que o usuário pode modificar o conteúdo. Para responder a essa pergunta mais genérica, há várias coisas a serem consideradas:
/a/b/file
mas se ele possuifile
(e tem acesso de pesquisa/a/b
e o sistema de arquivos não é somente leitura, e o arquivo não tem o sinalizador imutável e ele tem acesso de shell ao sistema), então ele seria capaz de alterar as permissões dofile
e conceder a si mesmo acesso./a/b
mas não tem acesso à pesquisa./a/b/file
porque ele não tem acesso à pesquisa/a
ou/a/b
, mas esse arquivo pode ter um link/b/c/file
físico, por exemplo, nesse caso, ele pode modificar o conteúdo/a/b/file
abrindo-o pelo/b/c/file
caminho./a
, mas/a/b
pode ser montado em ligação/c
, para que ele possa abrirfile
para escrever através de seu/c/file
outro caminho./a/b/file
, mas se tiver acesso de gravação/a/b
, poderá remover ou renomearfile
lá e substituí-lo por sua própria versão. Ele mudaria o conteúdo do arquivo,/a/b/file
mesmo que fosse um arquivo diferente./a
(ele poderia mudar o nome/a/b
para/a/c
, criar um novo/a/b
diretório e um novofile
nele.Para encontrar os caminhos que
$user
poderiam modificar. Para endereçar 1 ou 2, não podemos mais confiar naaccess(2)
chamada do sistema. Poderíamos ajustar nossafind -perm
abordagem para assumir o acesso à pesquisa nos diretórios ou gravar o acesso aos arquivos assim que você for o proprietário:Poderíamos endereçar 3 e 4, gravando os números do dispositivo e do inode ou todos os arquivos que $ user tem permissão de gravação e relatando todos os caminhos de arquivos que possuem esses números de dev + inode. Desta vez, podemos usar o mais confiável
access(2)
abordagens :Algo como:
5 e 6 são, à primeira vista, complicados pelo
t
pouco das permissões. Quando aplicado em diretórios, esse é o bit de exclusão restrito que impede que usuários (outros que não sejam o proprietário do diretório) removam ou renomeiem os arquivos que eles não possuem (mesmo tendo acesso de gravação ao diretório).Por exemplo, se voltarmos ao nosso exemplo anterior, se você tem acesso de gravação para
/a
, em seguida, você deve ser capaz de mudar o nome/a/b
para/a/c
, em seguida, recriar um/a/b
diretório e uma novafile
lá. Mas se ot
bit estiver ativado/a
e você não possuir/a
, poderá fazê-lo somente se possuir/a/b
. Isso dá:t
bit não está definido e você está no mesmo caso acima (todos os caminhos de arquivo são seus).Portanto, podemos resolver todos os itens 1, 2, 5 e 6 com:
Como a solução para 3 e 4 é independente, você pode mesclar a saída deles para obter uma lista completa:
Como deve ficar claro, se você leu tudo até agora, parte dele, pelo menos, trata apenas de permissões e propriedade, e não os outros recursos que podem conceder ou restringir o acesso de gravação (FS, ACLs, sinalizador imutável, outros recursos de segurança, somente leitura ...) E, como a processamos em vários estágios, algumas dessas informações podem estar erradas se os arquivos / diretórios estiverem sendo criados / excluídos / renomeados ou se suas permissões / propriedade forem modificadas enquanto esse script estiver em execução, como em um servidor de arquivos ocupado com milhões de arquivos .
Notas de portabilidade
Todo esse código é padrão (POSIX, Unix para
t
bit), exceto:-print0
é uma extensão GNU agora também suportada por algumas outras implementações. Comfind
implementações que não têm suporte para isso, você pode usar-exec printf '%s\0' {} +
e substituir-exec sh -c 'exec find "$@" -print0' sh {} +
por-exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +
.perl
não é um comando especificado pelo POSIX, mas está amplamente disponível. Você precisaperl-5.6.0
ou acima para-Mfiletest=access
.zsh
não é um comando especificado pelo POSIX. Essezsh
código acima deve funcionar com zsh-3 (1995) e acima.sudo
não é um comando especificado pelo POSIX. O código deve funcionar com qualquer versão, desde que a configuração do sistema permita a execuçãoperl
como o usuário especificado.fonte
x
permissão de pesquisa ( bit) no diretório. Você também pode ter permissões de pesquisa, mas não ler , o que significa que os arquivos estão ocultos para você, mas se você souber o nome deles, poderá acessá-los. Um exemplo típico é o diretório do arquivo de sessão php (algo como / var / lib / php).Você pode combinar opções com o
find
comando, para descobrir os arquivos com o modo e o proprietário especificados. Por exemplo:O comando acima listará todas as entradas que pertencem ao grupo "equipe" ou "usuários" e tem permissão de gravação para esse grupo.
Você também deve verificar as entradas pertencentes ao seu usuário e os arquivos que podem ser gravados mundialmente, portanto:
No entanto, esse comando não corresponderá às entradas com a ACL estendida. Então você pode
su
descobrir todas as entradas graváveis:fonte
r-xrwxrwx yourusername:anygroup
our-xr-xrwx anyone:staff
é gravável.yourusername
não há acesso.A abordagem depende do que você está realmente testando.
Isso ocorre porque existem muitas maneiras de chegar a 2) e a resposta de Stéphane cobre isso muito bem (é imutável lembrar) e lembre-se de que existem meios físicos também, como desmontar a unidade ou torná-la somente leitura em um nível de hardware (guias de disquete). Suponho que seus milhares de arquivos estejam em diretórios diferentes e você deseja um relatório ou está verificando uma lista principal. (Outro abuso de Puppet apenas esperando para acontecer).
Você provavelmente deseja que a árvore perl de passagem do Stéphane e "junte" a saída a uma lista, se necessário (su também pegará a execução ausente nos diretórios pai?). Se a barriga de aluguel é um problema de desempenho, você está fazendo isso para um "grande número" de usuários? Ou é uma consulta online? Se esse for um requisito permanente permanente, talvez seja hora de considerar um produto de terceiros.
fonte
Você pode fazer...
... para obter uma lista de todos os arquivos nos quais o usuário não pode gravar como gravado no stderr no formulário ...
...ou similar.
Veja os comentários abaixo para obter notas sobre os problemas que essa abordagem pode ter e a explicação abaixo sobre por que ela pode funcionar. Mais prudentemente, porém, você provavelmente deveria apenas
find
arquivos regulares como:Em resumo,
tee
imprimirá erros quando tentaropen()
um arquivo com um dos dois sinalizadores ...... e encontros ...
... como especificado aqui :
Porque tem que verificar da mesma maneira
test -w
que ...Ambos procuram EACCESS .
fonte
tee
irá travar, a menos que seja explicitamente interrompido uma vez por execução. Foi a coisa mais próxima que pude pensar[ -w
... porém - seus efeitos devem estar próximos, pois garante que o usuário possa OAPPENDER o arquivo. Muito mais fácil do que qualquer uma das opções seriapax
com as-o
opções de formato e / ou-t
para verificaçãoEACCESS
- mas toda vez que sugiro que aspax
pessoas pareçam ignorar. E, de qualquer forma, o únicopax
que encontrei que atende ao padrão existente é o AST - nesse caso, você também pode usá-lols
.