구성 감사의 이유로 변경 불가능한 속성이 설정된 파일을 통해 ext3 파일 시스템을 검색 할 수 있기를 원합니다 (via chattr +i
). find
이 작업을 수행 하는 데 필요한 옵션 이나 유사한 옵션을 찾을 수 없습니다 . 이 시점에서 lsattr
각 디렉토리의 출력 을 구문 분석 하기 위해 자체 스크립트를 작성해야합니다 . 더 나은 방법을 제공하는 표준 유틸리티가 있습니까?
구성 감사의 이유로 변경 불가능한 속성이 설정된 파일을 통해 ext3 파일 시스템을 검색 할 수 있기를 원합니다 (via chattr +i
). find
이 작업을 수행 하는 데 필요한 옵션 이나 유사한 옵션을 찾을 수 없습니다 . 이 시점에서 lsattr
각 디렉토리의 출력 을 구문 분석 하기 위해 자체 스크립트를 작성해야합니다 . 더 나은 방법을 제공하는 표준 유틸리티가 있습니까?
답변:
grep
명령을 lsattr
명령 으로 파이핑하여 부분적으로 수행 할 수 있습니다 .
lsattr -R | grep +i
그러나, 나는 당신이 전체 말할 때 믿는 ext3
검색을 포함 할 수 파일 시스템 /proc
, /dev
및보고하면 그냥 원하는 몇 가지 오류가 무시하는 다른 디렉토리를. 다음과 같이 명령을 실행할 수 있습니다.
lsattr -R 2>/dev/null | grep -- "-i-"
의 PCRE 기능을 grep
사용 grep
하여 "-i-"와보다 명확하게 일치시켜 조금 더 엄격하게 만들 수 있습니다 .
lsattr -R 2>/dev/null | grep -P "(?<=-)i(?=-)"
그러면 다음과 같은 상황에서 작동합니다.
$ lsattr -R 2>/dev/null afile | grep -P "(?<=-)i(?=-)"
----i--------e-- afile
그러나 불완전하다. 불변 플래그 주위에 추가 속성이 활성화되어 있으면 일치하지 않으며, 위와 같은 패턴과 이름이 일치하는 파일에 속합니다.
$ lsattr -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-)"
----i--------e-- afile
-------------e-- afile-i-am
다음과 같이 패턴을 조금 더 강화할 수 있습니다.
$ lsattr -a -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-).* "
----i--------e-- afile
그러나 여전히 약간 깨지기 쉽고 파일 시스템 내의 파일에 따라 추가 조정이 필요합니다. 하지 언급에 관해서는 @StephaneChazeles은 이 위의 패턴을 우회하는 파일 이름으로 줄 바꿈을 포함하여 비교적 쉽게 gamed 될 수 있다는 의견에 언급했다 grep
.
https://groups.google.com/forum/#!topic/alt.os.linux/LkatROg2SlM
-i-
(현재 로그온 한 시스템에 34 개가 있음). 당신은 아마 -a
옵션도 원할 것입니다
+i
때문에 첫 번째 예에서 무엇을해야합니까? 그것은 나를 위해 작동하지 않습니다. 또한 grepping은 (와 같은 ) -i-
옆에 나타나는 속성 이 설정되지 않은 것으로 가정합니다 . i
a
^....i
않습니까? 또는 같은 적어도 뭔가 ^[^ ]*i
(가) 경우 i
다섯 번째가 아닌 다른 위치에있을 수 있습니다.
스크립트의 목적이 감사라는 점을 고려하면 임의의 파일 이름 (예 : 줄 바꾸기 포함 이름)을 올바르게 처리하는 것이 특히 중요합니다. 이 lsattr
경우 출력 lsattr
이 모호 할 수 있으므로 여러 파일에서 동시에 사용할 수 없습니다.
한 번에 하나의 파일로 반복해서 find
호출 할 수 있습니다 lsattr
. 그래도 꽤 느릴 것입니다.
find / -xdev -exec sh -c '
for i do
attrs=$(lsattr -d "$i"); attrs=${attrs%% *}
case $attrs in
*i*) printf "%s\0" "$i";;
esac
done' sh {} +
Perl, Python 또는 Ruby와 같이 덜 까다로운 언어를 사용하고 lsattr
직접 작업하는 것이 좋습니다 . ioctl syscall lsattr
을 발행 FS_IOC_GETFLAGS
하고 파일의 inode 플래그를 검색하여 작동합니다 . 다음은 Python 개념 증명입니다.
#!/usr/bin/env python2
import array, fcntl, os, sys
FS_IOC_GETFLAGS = 0x80086601
EXT3_IMMUTABLE_FL = 0x00000010
count = 0
def check(filename):
fd = os.open(filename, os.O_RDONLY)
a = array.array('L', [0])
fcntl.ioctl(fd, FS_IOC_GETFLAGS, a, True)
if a[0] & EXT3_IMMUTABLE_FL:
sys.stdout.write(filename + '\0')
global count
count += 1
os.close(fd)
for x in sys.argv[1:]:
for (dirpath, dirnames, filenames) in os.walk(x):
for name in dirnames + filenames:
check(os.path.join(dirpath, name))
if count != 0: exit(1)
FS_IOC_GETFLAGS
는 0x80046601
입니다.
FS_IOC_GETFLAGS
따라 다릅니다 sizeof(long)
. C에서 매크로가 확장되는 것을 찾으려면 예를 들어 다음 bash 명령을 참조하십시오 gcc -E - <<< $'#include <linux/fs.h>\nFS_IOC_GETFLAGS' | tail -n1
. : 나는 그것에서 다음 식을 가지고 (((2U) << (((0 +8)+8)+14)) | ((('f')) << (0 +8)) | (((1)) << 0) | ((((sizeof(long)))) << ((0 +8)+8)))
로 단순화 (2U << 30) | ('f' << 8) | 1 | (sizeof(long) << 16)
.
임의의 파일 이름 (줄 바꾸기 문자가 포함 된 파일 이름 포함)을 처리하기 위해 일반적인 속임수 는에서 .//.
대신 파일을 찾는 것입니다 .
. 때문에 //
디렉토리 트리를 통과하는 동안 일반적으로 발생할 수 없습니다, 당신이 확신하는 //
것을 알리는에서 새 파일 이름의 시작 find
(또는 여기 lsattr -R
) 출력.
lsattr -R .//. | awk '
function process() {
i = index(record, " ")
if (i && index(substr(record,1,i), "i"))
print substr(record, i+4)
}
{
if (/\/\//) {
process()
record=$0
} else {
record = record "\n" $0
}
}
END{process()}'
출력은 여전히 줄 바꿈으로 구분됩니다. 사후 처리가 필요한 경우이를 조정해야합니다. 예를 들어, -v ORS='\0'
GNU를에 공급할 수 있도록를 추가 할 수 있습니다 xargs -r0
.
또한 lsattr -R
(적어도 1.42.13) 경로가 PATH_MAX (보통 4096) 보다 큰 파일의 플래그를보고 할 수 없으므로 누군가 부모 디렉토리 (또는 경로 구성 요소로 이동하는 경로 구성 요소)를 이동하여 변경 불가능한 파일을 숨길 수 있습니다 그것은 매우 깊은 디렉토리에 있습니다.
해결 방법은 다음 find
과 함께 사용하는 것 입니다 -execdir
.
find . -execdir sh -c '
a=$(lsattr -d "$1") &&
case ${a%% *} in
(*i*) ;;
(*) false
esac' sh {} \; -print0
이제와 -print0
, 후 처리 가능한, 그러나 당신이 그 경로가 무엇보다 큰 파일 경로에있는 모든 시스템 호출주의 할하려는 경우 PATH_MAX가 여전히 실패 및 디렉토리 구성 요소가 간격으로 이름이 변경 될 수도 있습니다.
다른 사람이 쓸 수있는 디렉토리 트리에 대한 신뢰할 수있는 보고서를 얻으려면 lsattr
언급해야 할 명령 자체에 몇 가지 문제가 더 있습니다 .
lsattr -R .
은 디렉토리 트리를 통과하며 경쟁 조건에 따라 달라질 수 있습니다. .
적절한 시점에 일부 디렉토리를 심볼릭 링크로 교체하여 라우팅 된 디렉토리 트리 외부의 디렉토리로 내려갈 수 있습니다 .lsattr -d file
경쟁 조건이 있습니다. 이러한 속성은 일반 파일 또는 디렉토리에만 적용됩니다. 그래서 lsattr
않는 lstat()
파일이 올바른 유형이며 다음 않는다는 것을 확인하기 위해 먼저 open()
다음 ioctl()
속성을 검색 할 수 있습니다. 그러나 (또는 O_NOCTTY) open()
없이 호출합니다 O_NOFOLLOW
. 예를 들어 및 사이에 file
있는 심볼릭 링크로 대체 되어 시스템이 재부팅 될 수 있습니다. 그것은 어떻게해야 그 다음 , 그리고 여기에 경쟁 조건을 피하기 위해./dev/watchdog
lstat()
open()
open(O_PATH|O_NOFOLLOW)
fstat()
openat()
ioctl()
Ramesh, slm 및 Stéphane에게 올바른 방향으로 나를 가리켜 주셔서 감사합니다 (에 대한 -R
스위치 가 누락되었습니다 lsattr
). 불행히도, 지금까지 답변 중 어느 것도 나를 위해 올바르게 작동하지 않았습니다.
나는 다음을 생각해 냈다.
lsattr -aR .//. | sed -rn '/i.+\.\/\/\./s/\.\/\///p'
이렇게하면 파일이 변경되지 않은 경우 파일을 변경할 수없는 것처럼 보이게하는 데 사용되는 줄 바꿈을 방지 할 수 있습니다. 변경 불가능으로 설정되고 파일 이름에 줄 바꿈이있는 파일은 보호 하지 않습니다 . 그러나 그러한 파일은 루트로 그렇게 만들어야하므로, 해당 파일이 내 사용 사례를 위해 파일 시스템에 존재하지 않는다고 확신 할 수 있습니다. (이 방법은 루트 사용자가 손상된 경우 침입 탐지에 적합하지 않지만 lsattr
동일한 루트 사용자가 소유 한 동일한 시스템 유틸리티를 사용하지 않습니다 .)
사용 find -exec
의 출력을 구문 분석, 너무 느린 것은 lsattr
입니다 유사의에 신뢰할 수없는ls
에서 파이썬을 사용하여, 질 의해 답변 에 대한 상수를 선택하는 데 필요한 ioctl
파이썬 인터프리터는 32 비트 또는 64 비트인지에 따라 ...
C ++은 스크립팅 언어만큼 나쁘지는 않습니다. 보너스로 C 프리 프로세서의 모든 기능을 갖춘 시스템 C 헤더에 액세스 할 수 있습니다.
다음 프로그램은 하나의 파일 시스템 내에있는 불변 파일을 검색합니다. 즉, 마운트 지점을 절대로 넘지 않습니다. 필요에 따라 마운트 포인트를 건너는 겉보기 트리를 검색하려면 호출 FTW_MOUNT
에서 플래그를 제거 nftw
하십시오. 또한 심볼릭 링크를 따르지 않습니다. 이를 따르려면 FTW_PHYS
플래그를 제거하십시오 .
#define _FILE_OFFSET_BITS 64
#include <iostream>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <ftw.h>
bool isImmutable(const char* path)
{
static const int EXT3_IMMUTABLE_FLAG=0x10;
const int fd=open(path,O_RDONLY|O_NONBLOCK|O_LARGEFILE);
if(fd<=0)
{
perror(("Failed to open file \""+std::string(path)+"\"").c_str());
return false;
}
unsigned long attrs;
if(ioctl(fd,FS_IOC_GETFLAGS,&attrs)==-1)
{
perror(("Failed to get flags for file \""+std::string(path)+"\"").c_str());
close(fd);
return false;
}
close(fd);
return attrs & EXT3_IMMUTABLE_FLAG;
}
int processPath(const char* path, const struct stat* info, int type, FTW* ftwbuf)
{
switch(type)
{
case FTW_DNR:
std::cerr << "Failed to read directory: " << path << "\n";
return 0;
case FTW_F:
if(isImmutable(path))
std::cout << path << '\n';
return 0;
}
return 0;
}
int main(int argc, char** argv)
{
if(argc!=2)
{
std::cerr << "Usage: " << argv[0] << " dir\n";
return 1;
}
static const int maxOpenFDs=15;
if(nftw(argv[1],processPath,maxOpenFDs,FTW_PHYS|FTW_MOUNT))
{
perror("nftw failed");
return 1;
}
}
출력을 grep에 파이핑하는 대신 awk를 사용하여 출력의 첫 번째 필드에서 'i'만 일치시키는 이유는 무엇입니까?
lsattr -Ra 2>/dev/null /|awk '$1 ~ /i/ && $1 !~ /^\// {print}'
실제로 매일 cron을 통해 수백 대의 서버에서 / etc 디렉토리를 스캔하고 출력을 syslog로 보냅니다. 그런 다음 Splunk를 통해 일일 보고서를 생성 할 수 있습니다.
lsattr -Ra 2>/dev/null /etc|awk '$1 ~ /i/ && $1 !~ /^\// {print "Immutable_file="$2}'|logger -p local0.notice -t find_immutable
/etc
. 그러나 두 명령은 잘못 만든 비 불변의 파일 찾기touch `"echo -e "bogus\n---------i---e-- changeable"`"
touch "`echo -e 'bogus\n---------i---e-- changeable'`"
매우 간단합니다. 용의자 폴더로 이동하여 다음 명령을 실행하십시오.
lsattr -laR | grep *immutable