Jak nieinwazyjnie przetestować dostęp do zapisu w pliku?

20

W jaki sposób w skrypcie powłoki mogę w łatwy i nieinwazyjny sposób sprawdzać dostęp do zapisu do pliku bez faktycznej próby modyfikacji pliku?

Mógłbym przeanalizować dane wyjściowe stat, ale wydaje się to naprawdę skomplikowane i być może kruche, chociaż nie jestem pewien, jak wiele danych statystycznych różni się w zależności od implementacji i czasu.

Mógłbym dołączyć na końcu pliku i sprawdzić, czy to się powiedzie, ale to potencjalnie niebezpieczne, z dwóch powodów, o których mogę myśleć:

  1. Teraz muszę usunąć dodatek, a jeśli jakiś inny proces zapisuje do pliku, to natychmiast staje się nietrywialne, ponieważ moja linia nie jest już ostatnią.
  2. Każdy proces odczytywający plik może mieć dowolne wymagania dotyczące zawartości tego pliku, a ja właśnie mogłem zepsuć tę aplikację.
użytkownik50849
źródło

Odpowiedzi:

29

Wystarczy użyć wflagi - testużyteczności:

[ -w /path/to/file ] && echo "writeable" || echo "write permission denied"

Pamiętaj, że jeśli zamierzasz później zapisać plik, nadal możliwe jest, że nie będziesz mógł do niego zapisać. Plik mógł zostać przeniesiony, uprawnienia mogły ulec zmianie itp. Może się również zdarzyć, że -wwykryje uprawnienia do zapisu, ale interweniuje jakiś inny czynnik, aby uniemożliwić zapisywanie pliku .

chaos
źródło
1
Oczywiście! Powinienem był pomyśleć o sprawdzeniu strony podręcznika testu. Dziękuję Ci.
user50849,
1
@qweilun to wbudowana powłoka, ale możesz wyświetlić stronę podręcznika za pomocą man testlubman [
chaos
5
@chaos Jest to zarówno wbudowana powłoka, jak i zewnętrzny plik wykonywalny - spróbujtype -a
Volker Siegel
1
Dlatest zastosowań źródłowych, euidaccessktóre po prostu sprawdzają bity uprawnień . Czy nie istnieją inne czynniki (np. SELinux), które mogą zabronić dostępu do zapisu?
zamnuts
2
@BroSlow &&i ||mają równy priorytet. Są oceniane od lewej do prawej.
Wildcard,
11

Inne podejście:

if >> /path/to/file
then
    echo "writeable"
else
    echo "write permission denied"
fi

Spowoduje to próbę otwarcia pliku w celu dołączenia, a jeśli to się powiedzie, nie uruchom żadnej komendy (tj. Uruchom komendę zerową ) z wyjściem do pliku. 

Uważaj, aby utworzyć pusty plik, jeśli nie istniał.

-wOperator testpolecenia może po prostu zrobić stat , a następnie spróbuj dowiedzieć się, czy wygląda na to trzeba mieć dostęp. Moja alternatywa (powyżej) jest bardziej niezawodna niż testpodejście w niektórych specjalnych warunkach, ponieważ wymusza sprawdzenie dostępu przez jądro, a nie powłokę. Na przykład,

  • jeśli plik znajduje się w systemie plików innym niż Unix - zwłaszcza jeśli jest on zdalnie zamontowany z serwera plików innego niż Unix - ponieważ statmoże zwrócić mylącą wartość trybu.
  • jeśli plik znajduje się w systemie plików, który jest zamontowany tylko do odczytu.
  • jeśli plik ma ACL, a tryb sprawia, że ​​wygląda na to, że powinieneś mieć dostęp, ale ACL go zaprzecza lub odwrotnie.
  • jeśli niektóre ramy bezpieczeństwa (AppArmor, SELinux,…) odmawiają dostępu do pliku.
G-Man mówi „Przywróć Monikę”
źródło
3
Właśnie to przetestowałem (na Debianie). Żaden czas nie został zmieniony i tak powinno działać na każdym Uniksie. Czas dostępu powinien być aktualizowany tylko wtedy, gdy czytasz z pliku, czas modyfikacji powinien być aktualizowany tylko wtedy, gdy zapisujesz do pliku. Ten kod też nie. @ Schwern: czy masz odniesienie do swojego oświadczenia? Czy ktoś z was tego próbował?
G-Man mówi „Reinstate Monica”
2
PS @muru: Właśnie próbowałem touchutworzyć plik, który posiadałem, ale nie miałem dostępu do zapisu, i udało się. Myślę, że to chmodplik i chmodto z powrotem. Więc touchwydaje się być absolutnie bezużyteczne jako odpowiedź na pytanie.
G-Man mówi „Przywróć Monikę”
2
@ G-Man ah, to interesujące. IIRC vimzachowuje się tak, że szybko zmienia uprawnienia, gdy jest zmuszony pisać na plikach tylko do odczytu. Sprawdziłem strace, touchjest opennie z EACCES, ale późniejsze wywołanie utimensatsię powiedzie, dlatego myślę, że touchna całych wyjść pomyślnie.
muru
2
@muru: Dziękujemy za sprawdzenie tego. utimensat(2)mówi: „ Wymagania dotyczące uprawnień: 1. dostęp do zapisu (lub) 2. efektywny identyfikator użytkownika dzwoniącego musi być zgodny z właścicielem pliku,…”.
G-Man mówi „Przywróć Monikę”
3
Inne problemy, takie jak w przypadku Champignac: >> filenie jest przenośny (na przykład uruchamia NULLCMD w zsh), użyj true >> filezamiast tego. A jeśli plik ma nazwane potoki, ma nieprzyjemne skutki uboczne.
Stéphane Chazelas,
3

G-man ma rację: [ -w ]nie zawsze mówi prawdę. Tutaj, aby poradzić sobie z nieistniejącym plikiem i wiadomością odmowy uprawnień z powłoki:

( [ -e /path/to/file ] && >> /path/to/file ) 2> /dev/null && 
  echo writable || 
  echo not writable

Aktualizacja : Wygląda przerażająco, prawda? No cóż, tak jest. Hmm ... jak to sformułować ... NIE UŻYWAJ TEGO, chyba że doskonale wiesz, że jesteś w warunkach, w których wymaga on działania zgodnie z oczekiwaniami. Zobacz komentarz Stephane'a.

Co zatem wyciągnąć wniosek? Nawet jeśli [ -w ]nie mówi prawdy, jest to jedno polecenie, które ma wykonać zadanie. Jeśli tak się nie stanie, będziemy go winić, pisać raporty o błędach i będzie działać w przyszłości. Lepiej sprawdź warunki, w jakich działa i używa [ -w ]; napisz specjalny kod dla specjalnych przypadków. Obejścia mają swoje własne warunki.

[ -w /path/to/file ]

jest najlepszy a priori .

Champignac
źródło
3
Jeśli plik jest nazwanym potokiem, zawiesi się, jeśli nie będzie czytać, a nawet jeśli czytelnik będzie miał nieprzyjemne skutki uboczne. test -ww większości zastosowań implementacyjnych access(2)powinno wystarczyć do przetestowania uprawnień.
Stéphane Chazelas,