Jestem rootem. Chciałbym wiedzieć, czy użytkownik inny niż root ma dostęp do zapisu do niektórych plików - tysięcy z nich. Jak to zrobić skutecznie, unikając tworzenia procesów?
shell
files
permissions
users
Howard
źródło
źródło
access(2)
z odpowiednio ustawionym rzeczywistym UID (np. Przezsetresuid(2)
lub przenośny odpowiednik)? Mam na myśli, że trudno byłoby mi to zrobić po bashu, ale jestem pewien, że Perl / Python sobie z tym poradzą.[ -w
zwykle używają dostępu (2) lub równoważnego. Musisz także ustawić GID oprócz UID (tak jak robią Su lub Sudo). bash nie ma wbudowanej obsługi tego, ale zsh ma.chgrp
w dowolnej powłoce.Odpowiedzi:
Być może tak:
Powyżej uruchamia pojedynczy program zewnętrzny dla każdego pliku, a mianowicie
stat(1)
.Uwaga: To zakłada
bash(1)
i wcielenie Linuxastat(1)
.Uwaga 2: Proszę przeczytać komentarze Stéphane Chazelas poniżej dotyczące przeszłości, teraźniejszości, przyszłości oraz potencjalnych zagrożeń i ograniczeń tego podejścia.
źródło
-
. Zamiast tego możesz zmodyfikować go, aby akceptował listę rozdzielaną wartościami NULread -d ''
util-linux
), które są napisane specjalnie dla Linuksa,stat
to nie jest to polecenie, o którym mowa, to polecenie GNU, które zostało przeniesione na większość systemów, nie tylko na Linuksa. Zauważ też, że maszstat
komendę w Linuksie na długo przed napisaniem GNUstat
(stat
wbudowane zsh).stat(1)
”. Mam na myśli a,stat(1)
który akceptuje-c <format>
składnię, w przeciwieństwie do, powiedzmy, składni BSD-f <format>
. Uważam również, że było całkiem jasne, że nie miałem na myślistat(2)
. Jestem jednak pewien, że strona wiki o historii popularnych poleceń byłaby całkiem interesująca.TL; DR
Musisz zapytać system, czy użytkownik ma uprawnienia do zapisu. Jedynym niezawodnym sposobem jest przełączenie efektywnego identyfikatora UID, efektywnego identyfikatora GID i suplementów na identyfikator użytkownika i użycie
access(W_OK)
wywołania systemowego (nawet jeśli ma to pewne ograniczenia w niektórych systemach / konfiguracjach).I pamiętaj, że brak uprawnień do zapisu do pliku niekoniecznie gwarantuje, że nie możesz modyfikować zawartości pliku w tej ścieżce.
Dłuższa historia
Zastanówmy się, czego potrzeba na przykład, aby użytkownik $ miał dostęp do zapisu
/foo/file.txt
(zakładając, że żaden z/foo
i/foo/file.txt
ma dowiązań symbolicznych)?On potrzebuje:
/
(nie ma potrzebyread
)/foo
(nie ma potrzebyread
)/foo/file.txt
Widać już, że podejścia (takie jak @ lcd047 lub @ apaul ), które sprawdzają, że tylko pozwolenie
file.txt
nie działa, ponieważ mogliby powiedzieć, żefile.txt
jest zapisywalne, nawet jeśli użytkownik nie ma uprawnień do wyszukiwania/
lub/foo
.I takie podejście jak:
Nie zadziała również, ponieważ nie zgłosi plików w katalogach, użytkownik nie ma dostępu do odczytu (tak
find
działający, jak$user
nie może wyświetlić ich zawartości), nawet jeśli może do nich pisać.Jeśli zapomnimy o listach ACL, systemach plików tylko do odczytu, flagach FS (takich jak niezmienne), innych środkach bezpieczeństwa (apparmor, SELinux, które potrafią nawet rozróżnić różne typy zapisu) i skupimy się tylko na tradycyjnych atrybutach uprawnień i własności, aby uzyskać z uprawnieniami (wyszukiwanie lub zapis), jest to już dość skomplikowane i trudne do wyrażenia
find
.Potrzebujesz:
W
find
składni, tutaj jako przykład z użytkownikiem UID 1 oraz GID 1 i 2, byłoby to:Ten ściąga katalogi, których użytkownik nie ma prawa do wyszukiwania i do innych typów plików (wykluczone dowiązania symboliczne, ponieważ nie są istotne), sprawdza dostęp do zapisu.
Jeśli chcesz również rozważyć dostęp do zapisu do katalogów:
Lub dla arbitralnego
$user
i jego członkostwa w grupie pobranych z bazy danych użytkowników:(to jest 3 procesy w sumie:
id
,sed
afind
)Najlepiej byłoby zejść z drzewa jako root i sprawdzić uprawnienia jako użytkownik dla każdego pliku.
(to jeden
find
proces plus jedensudo
ish
przetwarzaj co kilka tysięcy plików[
iprintf
zwykle są one wbudowane w powłokę).Lub z
perl
:(3 procesy łącznie:
find
,sudo
aperl
).Lub z
zsh
:(W sumie 0 proces, ale przechowuje całą listę plików w pamięci)
Te rozwiązania opierają się na
access(2)
wywołaniu systemowym. Oznacza to, że zamiast odtwarzać algorytm używany przez system do sprawdzania uprawnień dostępu, prosimy system o sprawdzenie tego samego algorytmu (który uwzględnia uprawnienia, listy ACL, niezmienne flagi, systemy plików tylko do odczytu ... ) przydałby się, gdybyś spróbował otworzyć plik do zapisu, więc jest to najbliższe niezawodne rozwiązanie.Aby przetestować podane tutaj rozwiązania z różnymi kombinacjami użytkownika, grupy i uprawnień, możesz:
Zmieniający się użytkownik między 1 a 2 i grupa między 1, 2 i 3 i ograniczający się do niższych 9 bitów uprawnień, ponieważ są to już utworzone pliki 9458694. Dotyczy to katalogów, a następnie plików.
To tworzy wszystkie możliwe kombinacje
u<x>g<y>/<mode1>/u<z>g<w>/<mode2>
. Użytkownik z identyfikatorami UID 1 i GID 1 i 2 miałby dostęp do zapisu,u2g1/010/u2g3/777
ale nieu1g2/677/u1g1/777
na przykład nie.Teraz wszystkie te rozwiązania próbują zidentyfikować ścieżki plików, które użytkownik może otworzyć do zapisu, co różni się od ścieżek, w których użytkownik może modyfikować zawartość. Aby odpowiedzieć na to bardziej ogólne pytanie, należy wziąć pod uwagę kilka rzeczy:
/a/b/file
ale jeśli jest właścicielemfile
(i ma dostęp do wyszukiwania/a/b
, a system plików nie jest tylko do odczytu, a plik nie ma niezmiennej flagi, a on ma dostęp do powłoki z systemu), wtedy będzie mógł zmienić uprawnieniafile
i udzielić sobie dostępu./a/b
ale nie ma dostępu do wyszukiwania./a/b/file
ponieważ nie ma dostępu do wyszukiwania/a
lub/a/b
, ale plik ten może mieć na/b/c/file
przykład twardy link , w którym to przypadku może być w stanie zmodyfikować zawartość/a/b/file
, otwierając go poprzez/b/c/file
ścieżkę./a
, ale/a/b
może wiązać montowane w/c
, więc on może otworzyćfile
na piśmie za pośrednictwem swojej/c/file
drugiej ścieżce./a/b/file
, ale jeśli ma dostęp do zapisu/a/b
, może tam usunąć lub zmienić nazwęfile
i zastąpić go własną wersją. Zmieniłby zawartość pliku,/a/b/file
nawet jeśli byłby to inny plik./a
(mógł zmienić nazwę/a/b
, aby/a/c
utworzyć nowy/a/b
katalog, a nowyfile
w nim.Aby znaleźć ścieżki,
$user
które można modyfikować. W przypadku adresu 1 lub 2 nie możemy już polegać naaccess(2)
wywołaniu systemowym. Możemy dostosować naszefind -perm
podejście, aby zakładać dostęp do wyszukiwania do katalogów lub zapisywać dostęp do plików, gdy tylko będziesz właścicielem:Możemy adresować 3 i 4, rejestrując numery urządzeń i i-węzłów lub wszystkie pliki $ użytkownik ma uprawnienia do zapisu i zgłasza wszystkie ścieżki plików, które mają te numery dev i i-węzłów. Tym razem możemy skorzystać z bardziej niezawodnych
access(2)
podejścia:Coś jak:
5 i 6 są na pierwszy rzut oka skomplikowane przez
t
odrobinę uprawnień. W przypadku katalogów jest to bit z ograniczonym usuwaniem, który uniemożliwia użytkownikom (innym niż właściciel katalogu) usuwanie lub zmianę nazw plików, których nie są właścicielami (nawet jeśli mają dostęp do zapisu w katalogu).Na przykład, jeśli wrócimy do naszego wcześniejszego przykładu, jeśli masz dostęp do zapisu
/a
, powinieneś być w stanie zmienić nazwę/a/b
na/a/c
, a następnie ponownie utworzyć/a/b
katalog i nowyfile
w nim. Ale jeślit
bit jest włączony,/a
a ty nie jesteś właścicielem/a
, możesz to zrobić tylko wtedy, gdy jesteś właścicielem/a/b
. To daje:t
bit nie jest ustawiony, a ty jesteś w takim samym przypadku jak powyżej (wszystkie ścieżki do plików są twoje).Możemy więc rozwiązać wszystkie 1, 2, 5 i 6 za pomocą:
To i rozwiązanie dla 3 i 4 są niezależne, możesz scalić ich wyniki, aby uzyskać pełną listę:
Jak powinno być jasne, jeśli przeczytałeś wszystko do tej pory, jego część przynajmniej dotyczy uprawnień i własności, a nie innych funkcji, które mogą przyznawać lub ograniczać dostęp do zapisu (FS tylko do odczytu, listy ACL, niezmienna flaga, inne funkcje bezpieczeństwa ...) A ponieważ przetwarzamy je na kilku etapach, niektóre z tych informacji mogą być niepoprawne, jeśli pliki / katalogi są tworzone / usuwane / zmieniane nazwy lub ich uprawnienia / własność modyfikowane podczas działania tego skryptu, na przykład na zajętym serwerze plików z milionami plików .
Uwagi na temat przenośności
Cały ten kod jest standardowy (POSIX, Unix dla
t
bitów), z wyjątkiem:-print0
jest rozszerzeniem GNU obsługiwanym teraz także przez kilka innych implementacji. Zfind
wdrożeń, które nie mają poparcia dla niego, można użyć-exec printf '%s\0' {} +
zamiast tego, i wymienić-exec sh -c 'exec find "$@" -print0' sh {} +
z-exec sh -c 'exec find "$@" -exec printf "%s\0" {\} +' sh {} +
.perl
nie jest poleceniem określonym w POSIX, ale jest powszechnie dostępne. Potrzebujeszperl-5.6.0
lub więcej-Mfiletest=access
.zsh
nie jest poleceniem określonym przez POSIX. Powyższyzsh
kod powinien działać z zsh-3 (1995) i nowszymi.sudo
nie jest poleceniem określonym przez POSIX. Kod powinien działać z dowolną wersją, o ile konfiguracja systemu pozwala na działanieperl
jako dany użytkownik.źródło
x
uprawnienia do wyszukiwania ( bitowe) w katalogu. Możesz także mieć uprawnienia do wyszukiwania, ale nie możesz czytać , co oznacza, że pliki w nim są ukryte, ale jeśli znasz ich nazwę, możesz uzyskać do nich dostęp. Typowym przykładem jest katalog plików sesji php (coś w rodzaju / var / lib / php).Możesz łączyć opcje z
find
poleceniem, aby znaleźć pliki o określonym trybie i właścicielu. Na przykład:Powyższe polecenie wyświetli listę wszystkich wpisów należących do grupy „personel” lub „użytkownicy” i mających uprawnienia do zapisu dla tej grupy.
Powinieneś także sprawdzić wpisy, które są własnością użytkownika, a także pliki, które można zapisywać na całym świecie, więc:
Jednak to polecenie nie pasuje do pozycji z rozszerzoną listą ACL. Możesz
su
więc znaleźć wszystkie zapisywalne wpisy:źródło
r-xrwxrwx yourusername:anygroup
lubr-xr-xrwx anyone:staff
jest do zapisu.yourusername
, nie mają dostępu.Podejście zależy od tego, co naprawdę testujesz.
Jest tak, ponieważ istnieje tak wiele sposobów, aby dojść do 2), a odpowiedź Stéphane obejmuje je dobrze (niezmienny należy pamiętać) i przypomnieć, że istnieją również środki fizyczne, takie jak odmontowanie dysku lub uczynienie go tylko do odczytu na poziom sprzętowy (zakładki dyskietek). Zgaduję, że twoje tysiące plików znajdują się w różnych katalogach i chcesz raport lub porównujesz z listą główną. (Kolejne znęcanie się nad kukiełką tylko czeka, aby się wydarzyło).
Prawdopodobnie chcesz przechodzić drzewo Perla przez Stéphane'a i w razie potrzeby łączyć dane wyjściowe z listą (su przechwyci również brakujące wykonanie w katalogach nadrzędnych?). Jeśli macierzyństwo zastępcze stanowi problem z wydajnością, czy robisz to dla „dużej liczby” użytkowników? Czy jest to zapytanie online? Jeśli jest to stały stały wymóg, może być czas na rozważenie produktu innej firmy.
źródło
Możesz to zrobić...
... dla listy wszystkich plików, do których użytkownik nie może zapisać w formie zapisanej na stderr w formie ...
...lub podobne.
Poniższe komentarze zawierają uwagi na temat problemów, jakie może mieć to podejście, oraz wyjaśnienie poniżej, dlaczego może ono działać. Bardziej rozsądnie jednak powinieneś prawdopodobnie tylko
find
zwykłe pliki, takie jak:W skrócie,
tee
wypisze błędy podczas próbyopen()
utworzenia pliku z jedną z dwóch flag ...... i spotyka ...
... jak określono tutaj :
Ponieważ musi to sprawdzić w ten sam sposób
test -w
...Oboje sprawdzają EACCESS .
źródło
tee
zawiesi się, chyba że zostanie wyraźnie przerwane raz na cykl. To była najbliższa rzecz, o której mogłem pomyśleć[ -w
... chociaż - jej efekty powinny być bliskie, ponieważ gwarantuje, że użytkownik może OAPPENDOWAĆ plik. Znacznie łatwiejsze niż którakolwiek z opcji byłobypax
z-o
opcjami formatowania i / lub-t
porównywaniemEACCESS
- ale za każdym razem, gdy sugeruję,pax
ludzie wydają się go wzruszać. Zresztą jedynepax
, jakie znalazłem, które spełnia standard, to AST - w takim przypadku równie dobrze możesz ich użyćls
.