Değişmez öznitelik kümesine sahip dosyalar nasıl aranır?


18

Yapılandırma denetimi nedenleriyle, ext3 dosya sistemimi değiştirilemeyen özniteliği (üzerinden chattr +i) ayarlanmış dosyaları arayabilmek istiyorum . Bunu yapan herhangi bir findveya benzer seçenek bulamıyorum . Bu noktada, lsattrher dizinin çıktısını ayrıştırmak için kendi komut dosyamı yazmak zorunda kalacağımdan korkuyorum . Daha iyi bir yol sağlayan standart bir yardımcı program var mı?


Benim durumumda, izinsiz giriş tespiti için değil, sadece yapılandırma yönetimi için denetlediğimi açıklığa kavuşturmalıydım, bu yüzden çalıştığım dosya adlarının sahip olmayacağını bildiğim için yeni satırlar hakkında çok fazla endişelenmem gerekmiyor. onlar. Bununla birlikte, yeni hat sorunu akılda tutulmaya değer, bu yüzden sorumu olduğu gibi bırakacağım.
depquid

Yanıtlar:


9

grepKomutu, lsattrkomut komutunu pipete ederek gerçekleştirilebilir .

lsattr -R | grep +i

Ancak, ben tamamını bahsedildiğinde inanıyoruz ext3arama içerebilir dosya sistemi /proc, /devve raporlar eğer sadece istediğiniz bazı hata görmezden diğer bazı dizinleri. Komutu muhtemelen şu şekilde çalıştırabilirsiniz:

lsattr -R 2>/dev/null | grep -- "-i-"

"-İ-" ile daha açık bir şekilde eşleşmek için PCRE özelliğini grepkullanarak biraz daha sıkı hale getirmek isteyebilirsiniz grep.

lsattr -R 2>/dev/null | grep -P "(?<=-)i(?=-)"

Bu daha sonra aşağıdaki gibi durumlarda işe yarayacaktır:

$ lsattr -R 2>/dev/null afile | grep -P "(?<=-)i(?=-)"
----i--------e-- afile

Ama kusurlu. Değişmez bayrak etrafında etkinleştirilen ek özellikler varsa, bunları eşleştirmeyiz ve bu, yukarıdaki desenle eşleşen isimler tarafından da kandırılacaktır, örneğin:

$ lsattr -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-)"
----i--------e-- afile
-------------e-- afile-i-am

Deseni biraz daha sıkabiliriz:

$ lsattr -a -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-).* "
----i--------e-- afile

Ancak yine de biraz kırılgan ve dosya sisteminizdeki dosyalara bağlı olarak ek ayar gerektiriyor. Değil söz olarak @StephaneChazeles bu yukarıdaki desen baypas bir dosya adı ile yeni satırlarla dahil edilmesiyle oldukça kolay oynanabildiğinden edilebileceğini yorum olarak bahsedilen etmiştir grep.

Referanslar

https://groups.google.com/forum/#!topic/alt.os.linux/LkatROg2SlM


1
Ha aynı konuyu okudum ve göndermek üzereydim. Bunun yerine ekstralarımı sizinkine ekleyeceğim.
slm

@slm, herhangi bir değişiklik yapmaktan memnuniyet duyarız :)
Ramesh

2
Muhtemelen, bu yaklaşımla dosya adında yeni satır karakterleri bulunarak değişmez bir dosyayı taklit edebilir veya gizleyebilir. Ayrıca, dosya adlarının -i-adında bulunması nadir değildir (şu anda oturum açtığım sistemde 34 tane var). Muhtemelen -aseçeneği de isteyeceksiniz
Stéphane Chazelas

1
Sadece meraktan, +iilk örnekte ne olması gerekiyordu? Benim için işe yaramıyor. Ayrıca, selamlama, -i-bitişik i(örneğin a) gibi görünen özniteliklerin ayarlanmadığını varsayar .
depquid

1
Neden sadece grep değil ^....i? Veya en azından böylesi bir şey ^[^ ]*iolursa ibeşinci dışındaki bir pozisyonda olabilir.
Ruslan

6

Komut dosyasının amacının denetim olduğu göz önüne alındığında, rastgele dosya adlarıyla, örneğin satırsonu içeren adlarla doğru şekilde ilgilenmek özellikle önemlidir. Bu lsattr, birden fazla dosyada aynı anda kullanılmasını imkansız hale getirir , çünkü bu durumda çıktısı lsattrbelirsiz olabilir.

Bir kerede bir dosyayla tekrar görüşebilir findve çağrı yapabilirsiniz lsattr. Yine de oldukça yavaş olacak.

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 veya Ruby gibi daha az huysuz bir dil kullanmanızı ve lsattrkendi başınıza çalışmanızı öneririm . ioctl sistem çağrısı lsattrdüzenleyerek FS_IOC_GETFLAGSve dosyanın inode bayraklarını alarak çalışır . İşte bir Python kavram kanıtı.

#!/usr/bin/env python2
import array, fcntl, os, sys
S_IFMT =  0o170000
S_IFDIR = 0o040000
S_IFREG = 0o100000
FS_IOC_GETFLAGS = 0x80086601
EXT3_IMMUTABLE_FL = 0x00000010
count = 0
def check(filename):
    mode = os.lstat(filename).st_mode
    if mode & S_IFMT not in [S_IFREG, S_IFDIR]:
        return
    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)

1
Benim sistem Bilginize üzerinde FS_IOC_GETFLAGSolduğunu 0x80046601.
antonone

1
Değeri FS_IOC_GETFLAGSbağlıdır sizeof(long). C: 'de makronun neye genişlediğini öğrenmek için aşağıdaki bash komutuna bakınız gcc -E - <<< $'#include <linux/fs.h>\nFS_IOC_GETFLAGS' | tail -n1. Ondan şu ifadeyi aldım: (((2U) << (((0 +8)+8)+14)) | ((('f')) << (0 +8)) | (((1)) << 0) | ((((sizeof(long)))) << ((0 +8)+8)))basitleştiren (2U << 30) | ('f' << 8) | 1 | (sizeof(long) << 16).
Ruslan

Bu fleksoda boğuluyor.
Roadowl

@Roadowl Gerçekten. lsattruyarı mesajı olanları atlar. Sessizce atlamak için kavram kanıtı kodumu yamaladım.
Gilles 'SO- kötü olmayı bırak'

3

Rasgele dosya adları (yeni satır karakterleri içerenler dahil) ile başa çıkmak için, normal hile.//. yerine dosyaları bulmaktır .. Çünkü //dizin ağacında geçiş yaparken, normalde oluşamaz, emin olduğun bir //sinyal yeni dosya başlangıcı find(veya burada lsattr -R) çıktı.

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()}'

Çıktının hala satırsonu olarak ayrılacağını unutmayın. Sonradan işlem yapmanız gerekiyorsa, uyarlamanız gerekir. Örneğin, -v ORS='\0'GNU'lara besleyebilmek için a ekleyebilirsiniz xargs -r0.

Ayrıca unutmayınız lsattr -R(en azından 1.42.13) yolu daha büyüktür dosyaların bayraklarını rapor edemez PATH_MAX'dan birisi böylece, (genellikle 4096) gizlemek yolunu bileşenlerinden herhangi üst dizin hareket ettirerek böyle bir değişmez dosyası (veya o kurşun için değişmez olduğu gibi kendisi hariç) çok derin bir dizine.

Ara çözüm kullanmak olacaktır findile -execdir:

find . -execdir sh -c '
  a=$(lsattr -d "$1") &&
    case ${a%% *} in
      (*i*) ;;
      (*) false
    esac' sh {} \; -print0

Şimdi, -print0bu, sonradan işlenebilir, ancak bu yollarla herhangi bir şey yapmak istiyorsanız, PATH_MAX'tan daha büyük dosya yollarındaki herhangi bir sistem çağrısının yine başarısız olacağını ve dizin bileşenlerinin aralıklarla yeniden adlandırılmış olabileceğini unutmayın.

Başkaları tarafından yazılabilir bir dizin ağacı hakkında güvenilir bir rapor lsattralırsak , komutun kendisinde belirtmemiz gereken birkaç sorun daha vardır :

  • lsattr -R .dizin ağacında geçiş yolu , yarış koşullarına tabidir. .Bazı dizinleri doğru anda semboliklerle değiştirerek , dizin ağacının dışındaki dizinlere inebilir .
  • hatta lsattr -d filebir yarış durumu var. Bu öznitelikler yalnızca normal dosyalara veya dizinlere uygulanabilir. Yani lsattrbir does lstat()dosya sağ türleri ve daha sonra olmadığını kontrol etmek için ilk open()takiben ioctl()özelliklerini almak için. Ama open()olmadan çağırıyor O_NOFOLLOW(ne de O_NOCTTY). Birisi örneğin ve arasında filebir sembolik işaretle yer değiştirebilir ve sistemin yeniden başlatılmasına neden olabilir. Bu yapmalıyım ardından , ve burada yarış koşulları önlemek için./dev/watchdoglstat()open()open(O_PATH|O_NOFOLLOW)fstat()openat()ioctl()

2

Beni doğru yöne yönlendirdikleri için Ramesh, slm ve Stéphane'ye teşekkürler ( -Ranahtarını kaçırdım lsattr). Ne yazık ki, şimdiye kadar cevapların hiçbiri benim için doğru şekilde çalışmadı.

Aşağıdaki ile geldim:

lsattr -aR .//. | sed -rn '/i.+\.\/\/\./s/\.\/\///p'

Bu, bir dosyanın olmadığı zaman değişmez görünmesini sağlamak için kullanılan yeni satırlara karşı koruma sağlar. O mu değil değişmez olarak ayarlayabilir ve onların Dosya adlarında yeni satır var dosyaların karşı koruma sağlar. Ancak böyle bir dosyanın kök tarafından bu şekilde yapılması gerektiğinden, bu tür dosyaların kullanım durumum için dosya sistemimde mevcut olmadığından emin olabilirim. (Bu yöntem, kök kullanıcının tehlikeye girebileceği durumlarda izinsiz giriş tespiti için uygun değildir, ancak ikisi lsattrde aynı kök kullanıcının sahip olduğu aynı sistemin yardımcı programını kullanmaz .)


Yalnızca kök dosyaya değişmez bit ekleyebilir, ancak potansiyel olarak diğer kullanıcılar daha sonra bu dosyalara yol açan yol bileşenlerini yeniden adlandırabilir, böylece dosya yolu yeni satır içerebilir. Ayrıca bir kullanıcı, komut dosyanızı başka bir dosyanın değişmez olduğunu düşünmeye kandıracak bir dosya yolu (değiştirilemez) oluşturabilir.
Stéphane Chazelas

2

Kullanılması find -execçıktısını ayrıştırma, çok yavaş olduğu lsattrbir benzer o kadar güvenilmezls olduğu gibi Python kullanarak, Gilles tarafından cevap için sabiti seçmenizi gerektirir ioctlPython yorumlayıcısı 32 veya 64 bitlik olmasına bağlı olarak ...

Eldeki sorun az ya da çok düşük seviyededir, bu yüzden daha düşük seviyeye gidelim: C ++ bir betik dili kadar kötü değildir :) Bir bonus olarak, C ön işlemcisinin tam gücüne sahip sistem C başlıklarına erişimi vardır.

Aşağıdaki program, tek bir dosya sistemi içinde kalan değişmez dosyaları arar, yani hiçbir zaman bağlama noktalarını geçmez. Görünen ağacı aramak için, bağlama noktalarını gerektiği gibi geçerek aramadaki FTW_MOUNTbayrağı kaldırın nftw. Ayrıca sembolik bağlantıları takip etmez. Bunları takip etmek için FTW_PHYSbayrağı kaldırın .

#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;
    }
}

-1

Çıktıyı grep'e bağlamak yerine, neden sadece çıktının ilk alanındaki 'i' ile eşleştirmek için awk kullanmıyorsunuz?

lsattr -Ra 2>/dev/null /|awk '$1 ~ /i/ && $1 !~ /^\// {print}'

Aslında, bu günlük cron üzerinden yüzlerce sunucu / etc dizini taramak ve çıktı syslog göndermek için çalıştırın. Daha sonra Splunk ile günlük rapor oluşturabilirim:

lsattr -Ra 2>/dev/null /etc|awk '$1 ~ /i/ && $1 !~ /^\// {print "Immutable_file="$2}'|logger -p local0.notice -t find_immutable

İlk kod snippet'inizin bir yazım hatası var ve ikincisi sistemimde değişmez dosyalar bulamıyor.
depquid

İlk komuttaki yazım hatası düzeltildi. Belki ikincisi hiç değişmez dosya bulamıyor çünkü hiç yok?
Rootdev

İkinci komutun sadece içeri girdiğini fark etmedim /etc. Ancak her iki komut da yanlış bir şekilde oluşturulmuş ve değiştirilemeyen bir dosya touch `"echo -e "bogus\n---------i---e-- changeable"`"
bulur

Orijinal yazımda / etc dizinini taramak için cron üzerinden çalıştırdığımı söylüyor. Çalıştırmadan önce gönderiyi veya komutu okumadıysanız yardımcı olamam. Ve evet, muhtemelen herhangi bir aramayı kandırmak için bir uç durum oluşturabilirsiniz, ancak orijinal komutumdaki (sonuncuyu eksik) yazım hatasını belirtmek için çok hızlı olduğunuzdan, komutunuz yazıldığı gibi çalışmaz, bu yüzden hiçbir şey yaratmaz! :-)
Rootdev

Benim hatam. touch "`echo -e 'bogus\n---------i---e-- changeable'`"
Şunu

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.