Znajdź pliki, których użytkownik nie może odczytać?

12

Chcę znaleźć pliki, których dany użytkownik nie będzie w stanie odczytać.

Załóżmy, że nazwa użytkownika to „użytkownik123” i należą do grupy o nazwie „użytkownik123”. Chcę znaleźć pliki, które, jeśli są własnością użytkownika123, mają włączoną funkcję u + r; w przeciwnym razie, jeśli plik należy do grupy user123, powinien mieć włączony g + r; w przeciwnym razie może mieć włączone o + r.

Ponieważ GNU find ma opcję „-readable”, mógłbym to zrobić:

sudo -u user123 find /start ! -readable -ls

Jednak proces musi być uruchamiany przez użytkownika, który nie ma dostępu do sudo. Dlatego próbowałem tego: (nie sprawdza o + r, ale w tym momencie nie jest to ważne)

find /start \( -user user123 ! -perm -u=r  \) -o \( -group user123 ! -perm -g=r  \) -ls

ale wyświetla ten plik:

272118    4 -rw-------   1 user123   user123       3243 Jul  3 19:50 /start/blah/blah/file.txt

Ten plik jest jedynym plikiem /startnależącym do użytkownika123 przy g=rwyłączonym. To tak, jakby find interpretuje -u=rjako -g=r.

Postanowiłem spróbować odwrócić logikę i zamiast tego przetestować not ( truth ):

find /etc/puppet ! \( \( -user puppet -perm -u=r  \) -o \( -group puppet -perm -g=r \) -o \( -perm -o=r \) \)  -ls

To działa!

Dlaczego oryginał findzawiódł? Czy to błąd find(mało prawdopodobne), czy logika jest zła?

Aktualizacja: pomyliłem logikę. Jak wskazano poniżej, ponieważ! (A || B || C) == (! A &&! B &&! C) są to dwa równoważne stwierdzenia:

find /start ! \( \( -user user123 -perm -u=r \) -o \( -group user123 -perm -g=r \) -o \( ! \( -user user123 -o -group user123 \) -perm -o=r \) \) -ls
find /start ! \( -user user123 -perm -u=r \) ! \( -group user123 -perm -g=r \) ! \( ! \( -user user123 -o -group user123 \) -perm -o=r \) -ls

Moim celem nie było dwukrotne testowanie użytkownika / grupy. To, czego naprawdę potrzebuję, to bardziej skomplikowana struktura „jeśli to wtedy”, która prawdopodobnie byłaby możliwa tylko wtedy, gdyby istniał operator -xor. Mógłbym zbudować xor z i / lub / nie, ale byłoby to bardziej złożone niż dwa powyższe rozwiązania.

TomOnTime
źródło
1
Nawet druga logika jest błędna, ponieważ powiedziałaby, że puppetma dostęp do pliku za pomocą --wxrwxrwx puppet puppet.
Stéphane Chazelas

Odpowiedzi:

7

Logika jest zła. Uważasz, że ten plik nie powinien być wymieniony, ponieważ jest własnością user123i ma rustawiony bit użytkownika . Jest on jednak wymieniony, ponieważ spełnia drugie kryterium (jest własnością grupy user123i ma rustawiony bit grupy ).

Druga wersja działa z powodu jednego z praw de Morgana : negowanie logicznej ORing grupy instrukcji jest logicznie równoważne z ANDingiem negacji poszczególnych instrukcji. Innymi słowy:

 ! ( A || B || C ) == ( !A && !B && !C )

Więc praca findszuka pliku, który

  • Nie jest (własnością użytkownika user123i czytelny dla tego użytkownika) ORAZ
  • Nie jest (własnością grupy user123i jest czytelny dla tej grupy) ORAZ
  • Nie jest czytelny na całym świecie.

podczas gdy pierwszy findszuka pliku, który

  • Jest własnością użytkownika user123i nie może być odczytany przez tego użytkownika LUB
  • Jest własnością grupy user123i nie można jej odczytać przez wspomnianą grupę LUB (jeśli ją ukończyłeś)
  • Nie jest czytelny na całym świecie

Tak więc plik pasujący do DOWOLNEGO z powyższych 3 kryteriów (i niekoniecznie wszystkich) byłby wymieniony tak, jak widziałeś.

Edytować

Nawiasem mówiąc (po obejrzeniu twojego profilu) jestem wielkim fanem twojej książki O'Reilly :)

Joseph R.
źródło
Dziękuję za analizę. Tak, to było niewłaściwe zastosowanie prawa Morgana. Próbowałem to zrobić, ( !A && !B && !C )ale przeniosłem się !do wnętrza każdej części, co nie jest ważne. Dzięki!
TomOnTime
PS Cieszę się, że jesteś fanem mojej książki! Jestem ciekawy, w jakim języku to czytasz.
TomOnTime
@TomOnTime English, oczywiście. Staram się czytać każdą książkę w jej oryginalnym języku, jeśli mogę pomóc.
Joseph R.
8

Jest o wiele więcej rzeczy, które należy wziąć pod uwagę, aby sprawdzić, czy użytkownik ma dostęp do pliku za pośrednictwem danej ścieżki:

  • Właściciel pliku
  • grupa pliku
  • listy ACL w pliku
  • UID, GID i dodatkowe identyfikatory użytkownika
  • dostęp do wyszukiwania do dowolnego elementu ścieżki prowadzącego do tego pliku.
  • czy plik jest dowiązaniem symbolicznym
  • uprawnienia dotyczą inaczej użytkowników 0.
  • prawdopodobnie więcej funkcji bezpieczeństwa, takich jak SELinux ...

Poza tym, że faktycznie przełączam wszystkie identyfikatory użytkownika na identyfikatory użytkownika i sprawdzasz, bardzo trudno jest wdrożyć tę samą logikę, co system.

Z zsh możesz zrobić (jako root):

readable() (
  USERNAME=$u
  [ -r "$REPLY" ]
)
u=some-user
print -rl -- **/*(DoN^+readable)

Lub z perl:

find . -print0 | sudo -u some-user perl -Mfiletest=access -l -0ne '
  print unless -r'

W obu przypadkach należy opuścić drzewo katalogów jako, rootale przetestować dostęp do pliku jako odpowiedni użytkownik.

Działa find -readabletak some-user, jak nie jest, ponieważ nie będzie w stanie przejść obok katalogów, do których użytkownik nie ma dostępu lub nie ma uprawnień do odczytu (ale prawdopodobnie dostępu).

Nawet jeśli rozważasz tylko uprawnienia i własność samego pliku (a nie list ACL lub komponentów ścieżki ...), potrzebujesz przynajmniej (tutaj składni GNU):

u=some-user; g=$(id -G "$u" | sed 's/ / -o -group /g'); IFS=" "
find . ! \( -user "$u" -perm -u=r -o \
          ! -user "$u" \( -group $g \) -perm -g=r -o \
          ! -user "$u" ! \( -group $g \) -perm -o=r \)

Chodzi o to, że jeśli plik jest własnością użytkownika, wszystkie inne uprawnienia są nieistotne. Jeśli nie, to jeśli plik należy do grupy którejkolwiek z grup użytkowników, wówczas uprawnienie „inne” nie ma znaczenia.

Stéphane Chazelas
źródło
1
Dobra uwaga na temat list ACL i innych czynników. Jedyną 100% poprawną oceną jest access()to, że używa tego samego kodu jądra co open(). sudo -u user123 find /start -readableJest to zatem najlepsze rozwiązanie, jeśli sudojest opcją.
TomOnTime
1
@TomOnTime. Cóż, nie, jeśli użyjesz sudo -u user123 find -readable, nie zgłosi plików w katalogach, do których nie możesz wejść, lub w katalogach, których nie możesz odczytać (więc będą fałszywe negatywy i fałszywe pozytywy). Dlatego sugeruję używanie zshdo opuszczania drzewa katalogów jako root i do access()( [ -r ... ]) jako rzeczywistego użytkownika (ustawienie $USERNAMEw zshzmianach wszystkich identyfikatorów UID i GID sudo).
Stéphane Chazelas,