TL; DR
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'
사용자에게 쓰기 권한이 있는지 시스템에 문의해야합니다. 신뢰할 수있는 유일한 방법은 효과적인 uid, 효과적인 gid 및 보충 gid를 사용자의 것으로 바꾸고access(W_OK)
시스템 호출을 것입니다 (일부 시스템 / 구성에 일부 제한이 있음).
파일에 대한 쓰기 권한이 없다고해서 해당 경로에서 파일의 내용을 수정할 수 없다는 것을 반드시 명심해야합니다.
더 긴 이야기
의 그것에 대한 쓰기 접근이 달러 (A $)의 사용자에 대해 예를 들면 무엇이 필요한지 생각해 보자 /foo/file.txt
의 (가정 없음을/foo
하고 /foo/file.txt
심볼릭 링크입니다)을?
그는 필요하다 :
- 에 대한 검색 액세스
/
(필요 없음 read
)
- 에 대한 검색 액세스
/foo
(필요 없음 read
)
- 쓰다 권한
/foo/file.txt
이미 @ lcd047 's 또는 @ apaul ' s 와 같이 접근 권한 만 확인 하는 접근 방식 은 사용자에게 검색 권한이없는 경우에도 쓰기 가능 file.txt
하다고 말할 수 있기 때문에 작동 file.txt
하지 않습니다./
또는 /foo
.
그리고 다음과 같은 접근법 :
sudo -u "$user" find / -writeble
그것으로 (사용자가 읽기 액세스 권한이없는 디렉토리에있는 파일을보고하지 않기 때문에 중 하나가 작동하지 않음 find
으로 실행$user
내용을 나열 할 수없는 상태 .
ACL, 읽기 전용 파일 시스템, FS 플래그 (불변과 같은), 기타 보안 조치 (서로 다른 유형의 쓰기를 구분할 수있는 의류, SELinux)를 잊고 기존 권한과 소유권 속성에만 초점을 맞추면 (검색 또는 쓰기) 권한이 주어지면 이미 상당히 복잡하고 표현하기가 어렵습니다 find
.
당신이 필요합니다 :
- 파일이 본인 소유인 경우 소유자에 대한 해당 권한이 필요합니다 (또는 uid 0).
- 파일을 소유하지 않았지만 그룹이 귀하의 파일 인 경우 그룹에 대한 해당 권한이 필요합니다 (또는 uid 0).
- 귀하의 소유가 아니며 귀하의 그룹이 아닌 경우 다른 권한이 적용됩니다 (uid가 0이 아닌 경우).
에서는 find
구문 여기서 UID 1 및 GID 1 및 2의 사용자와의 일례로서, 그 것이다 :
find / -type d \
\( \
-user 1 \( -perm -u=x -o -prune \) -o \
\( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) -o -type l -o \
-user 1 \( ! -perm -u=w -o -print \) -o \
\( -group 1 -o -group 2 \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
그 자두 사용자가 다른 형식의 파일 (그들은 관련이없는 것 같이 제외 심볼릭 링크), 쓰기 액세스에 대한 검사에 적합한 검색하지 않는 디렉토리.
디렉토리에 대한 쓰기 액세스도 고려하려면 다음을 수행하십시오.
find / -type d \
\( \
-user 1 \( -perm -u=x -o -prune \) -o \
\( -group 1 -o -group 2 \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user 1 \( ! -perm -u=w -o -print \) -o \
\( -group 1 -o -group 2 \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
또는 $user
사용자 데이터베이스에서 임의 및 그룹 구성원을 검색 한 경우 :
groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
\( \
-user "$user" \( -perm -u=x -o -prune \) -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( ! -perm -u=w -o -print \) -o \
\( -group $groups \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
(즉, 총 3 개 과정이다 : id
, sed
및find
)
여기서 가장 좋은 방법은 트리를 루트로 내림차순으로 각 파일의 사용자 권한을 확인하는 것입니다.
find / ! -type l -exec sudo -u "$user" sh -c '
for file do
[ -w "$file" ] && printf "%s\n" "$file"
done' sh {} +
(즉, 하나 개의 find
프로세스를 더한 sudo
와 sh
모든 수천 파일을 처리, [
및printf
일반적으로 쉘에 내장되어 있습니다).
또는과 perl
:
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -l -0ne 'print if -w'
(총 3 개 공정 : find
, sudo
및perl
).
또는과 zsh
:
files=(/**/*(D^@))
USERNAME=$user
for f ($files) {
[ -w $f ] && print -r -- $f
}
(총 0 개의 프로세스이지만 전체 파일 목록을 메모리에 저장)
이러한 솔루션은 access(2)
시스템 호출 에 의존합니다 . 그것은 시스템이 액세스 권한을 확인하는 데 사용하는 알고리즘을 재생산하는 대신 시스템에 동일한 알고리즘 (권한, ACL, 불변 플래그, 읽기 전용 파일 시스템을 고려한)을 사용하여 확인하도록 요청하는 것입니다. ) 파일을 쓰기 위해 열려고 할 때 신뢰할 수있는 솔루션에 가장 가깝습니다.
다양한 사용자, 그룹 및 권한 조합으로 여기에 제공된 솔루션을 테스트하려면 다음을 수행하십시오.
perl -e '
for $u (1,2) {
for $g (1,2,3) {
$d1="u${u}g$g"; mkdir$d1;
for $m (0..511) {
$d2=$d1.sprintf"/%03o",$m; mkdir $d2; chown $u, $g, $d2; chmod $m,$d2;
for $uu (1,2) {
for $gg (1,2,3) {
$d3="$d2/u${uu}g$gg"; mkdir $d3;
for $mm (0..511) {
$f=$d3.sprintf"/%03o",$mm;
open F, ">","$f"; close F;
chown $uu, $gg, $f; chmod $mm, $f
}
}
}
}
}
}'
1과 2 사이의 사용자와 1, 2, 3 사이의 그룹을 변경하고 이미 작성된 9458694 파일이므로 권한의 하위 9 비트로 제한합니다. 디렉토리와 파일에 대한 것입니다.
가능한 모든 조합을 만듭니다 u<x>g<y>/<mode1>/u<z>g<w>/<mode2>
. uid 1 및 gid 1 및 2를 가진 사용자 는 예를 들어 쓰기 액세스 권한을 u2g1/010/u2g3/777
갖지만 액세스 권한은 없습니다 u1g2/677/u1g1/777
.
이제 모든 솔루션은 사용자가 쓰기 위해 열 수있는 파일의 경로를 식별하려고 시도합니다. 이는 사용자가 컨텐츠를 수정할 수있는 경로와 다릅니다. 보다 일반적인 질문에 대답하기 위해 고려해야 할 몇 가지 사항이 있습니다.
- $ user는 쓰기 권한이
/a/b/file
없지만 소유하고있는 경우 file
(에 대한 검색 액세스 권한이 /a/b
있고 파일 시스템이 읽기 전용이 아니며 파일에 변경할 수없는 플래그가없고 시스템에 대한 쉘 액세스 권한이있는 경우) 그런 다음 그는 권한을 변경 file
하고 액세스 권한을 부여 할 수 있습니다.
- 그가 소유 한 경우에도 마찬가지
/a/b
하지만 검색 액세스 권한이없는 입니다.
- $ user는 또는에
/a/b/file
대한 검색 액세스 권한이 없기 때문에 액세스 할 수 없지만 해당 파일은 예를 들어 하드 링크를 가질 수 있습니다. 이 경우 경로 를 통해 파일을 열어서 내용을 수정할 수 있습니다 ./a
/a/b
/b/c/file
/a/b/file
/b/c/file
- bind-mounts 와 동일합니다 . 그는에 검색 액세스하지 못할 수도
/a
있지만 /a/b
할 수있다 바인드 마운트 에서 /c
그는 열 수 있도록, file
자사를 통해 작성하기위한 /c/file
다른 경로.
- 그는 쓰기 권한이 없을 수 있습니다
/a/b/file
,하지만 그는 쓰기 권한이있는 경우에 /a/b
그는 제거하거나 이름을 바꿀 수 있습니다 file
거기에 그 자신의 버전으로 교체합니다. 그는 파일의 내용을/a/b/file
다른 파일이더라도 것입니다.
- 에 대한 쓰기 권한이있는 경우에도 마찬가지입니다
/a
(이름 /a/b
을 바꾸고 /a/c
새 /a/b
디렉토리를 작성하고 새 디렉토리를 작성할 file
수 있음).
$user
수정할 수 있는 경로를 찾습니다 . 1 또는 2를 해결하기 위해 access(2)
더 이상 시스템 호출 에 의존 할 수 없습니다 . find -perm
디렉토리에 대한 검색 액세스를 가정하거나 소유자가되는 즉시 파일에 대한 액세스를 가정하도록 접근 방식을 조정할 수 있습니다.
groups=$(id -G "$user" | sed 's/ / -o -group /g'); IFS=" "
find / -type d \
\( \
-user "$user" -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" -print -o \
\( -group $groups \) \( ! -perm -g=w -o -print \) -o \
! -perm -o=w -o -print
디바이스와 inode 번호 또는 $ user가 쓰기 권한을 가진 모든 파일과 dev + inode 번호가있는 모든 파일 경로를보고함으로써 모든 주소를 3과 4로 지정할 수 있습니다. 이번에는 더 안정적인 것을 사용할 수 있습니다 access(2)
기반 접근 방식을 .
다음과 같은 것 :
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-w,$_' |
perl -l -0ne '
($w,$p) = /(.)(.*)/;
($dev,$ino) = stat$p or next;
$writable{"$dev,$ino"} = 1 if $w;
push @{$p{"$dev,$ino"}}, $p;
END {
for $i (keys %writable) {
for $p (@{$p{$i}}) {
print $p;
}
}
}'
5와 6은 언뜻보기에는 t
약간의 권한으로 인해 복잡해 보인다. 디렉토리에 적용되는 경우, 이는 디렉토리 의 소유자가 아닌 사용자가 디렉토리에 대한 쓰기 액세스 권한이 있더라도 소유하지 않은 파일을 제거하거나 이름을 바꾸지 못하게 하는 제한된 삭제 비트입니다.
예를 들어, 이전 예제로 돌아가서에 대한 쓰기 권한이 있으면 /a
로 이름 /a/b
을 바꾼 /a/c
다음 /a/b
디렉토리와 디렉토리를 새로 만들 수 file
있습니다. 그러나 t
비트가 설정되어 /a
있고 소유 /a
하고 있지 않으면 소유 한 경우에만 할 수 있습니다 /a/b
. 그 결과는 다음과 같습니다.
- 1에 따라 디렉토리를 소유하고 있다면 쓰기 권한을 부여 할 수 있고 t 비트가 적용되지 않으며 (어쨌든 제거 할 수 있음) 파일 또는 디렉토리를 삭제 / 이름 바꾸기 / 재 생성 할 수 있습니다. 모든 파일 경로는 내용으로 다시 쓸 수 있습니다.
- 소유하고 있지 않지만 쓰기 권한이있는 경우 :
- 어느
t
비트가 설정하고 상기와 같은 경우에있어하지 않습니다 (모든 파일 경로는 당신입니다).
- 또는 설정되어 있고 소유하지 않거나 쓰기 액세스 권한이없는 파일을 수정할 수 없으므로 수정할 수있는 파일 경로를 찾기 위해 쓰기 권한이 전혀없는 것과 같습니다.
따라서 다음과 같이 1, 2, 5 및 6을 모두 처리 할 수 있습니다.
find / -type d \
\( \
-user "$user" -prune -exec find {} + -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( -type d -o -print \) -o \
\( -group $groups \) \( ! -perm -g=w -o \
-type d ! -perm -1000 -exec find {} + -o -print \) -o \
! -perm -o=w -o \
-type d ! -perm -1000 -exec find {} + -o \
-print
그와 3과 4에 대한 솔루션은 독립적이므로 출력을 병합하여 전체 목록을 얻을 수 있습니다.
{
find / ! -type l -print0 |
sudo -u "$user" perl -Mfiletest=access -0lne 'print 0+-w,$_' |
perl -0lne '
($w,$p) = /(.)(.*)/;
($dev,$ino) = stat$p or next;
$writable{"$dev,$ino"} = 1 if $w;
push @{$p{"$dev,$ino"}}, $p;
END {
for $i (keys %writable) {
for $p (@{$p{$i}}) {
print $p;
}
}
}'
find / -type d \
\( \
-user "$user" -prune -exec sh -c 'exec find "$@" -print0' sh {} + -o \
\( -group $groups \) \( -perm -g=x -o -prune \) -o \
-perm -o=x -o -prune \
\) ! -type d -o -type l -o \
-user "$user" \( -type d -o -print0 \) -o \
\( -group $groups \) \( ! -perm -g=w -o \
-type d ! -perm -1000 -exec sh -c 'exec find "$@" -print0' sh {} + -o -print0 \) -o \
! -perm -o=w -o \
-type d ! -perm -1000 -exec sh -c 'exec find "$@" -print0' sh {} + -o \
-print0
} | perl -l -0ne 'print unless $seen{$_}++'
지금까지 모든 것을 읽었을 경우, 쓰기 권한을 부여하거나 제한 할 수있는 다른 기능 (읽기 전용 FS, ACL, 불변 플래그, 기타 보안 기능)이 아니라 권한 및 소유권 만 다루는 부분이 있습니다. ...). 그리고 여러 단계로 처리 할 때 파일 / 디렉토리가 생성 / 삭제 / 이름이 바뀌거나 스크립트가 실행되는 동안 수백만 개의 파일이있는 바쁜 파일 서버에서 권한 / 소유권이 수정되면 일부 정보가 잘못 될 수 있습니다 .
이식성 메모
다음을 제외한 모든 코드는 표준 (POSIX, Unix t
비트)입니다.
-print0
GNU 확장은 이제 몇 가지 다른 구현에서도 지원됩니다. 로 find
그에 대한 지원이 부족 구현, 당신이 사용할 수있는 -exec printf '%s\0' {} +
대신에, 그리고 교체 -exec sh -c 'exec find "$@" -print0' sh {} +
와 함께 -exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +
.
perl
POSIX 지정 명령은 아니지만 널리 사용 가능합니다. 이상이 필요 perl-5.6.0
합니다 -Mfiletest=access
.
zsh
POSIX 지정 명령이 아닙니다. 즉, zsh
위의 코드는 zsh을-3 (1995) 이상으로 작동합니다.
sudo
POSIX 지정 명령이 아닙니다. 시스템 구성 perl
에서 지정된 사용자로 실행할 수있는 한 코드는 모든 버전에서 작동해야합니다 .