Od przeszło roku jestem szczęśliwym posiadaczem NAS-a firmy Synology. O ile samo urządzenie sobie chwalę, zwłaszcza ze względu na oprogramowanie, to nie jest ono pozbawione wad i błędów. Jednym z nich jest właśnie błędne działanie automatycznego czyszczenia starych plików z kosza.
DSM pozwala na włączenie kosza – skasowane pliki nie są wtedy kasowane od razu, ale przenoszone są do kosza, gdzie cierpliwie czekają aż ktoś je ostatecznie skasuje. Uzupełnieniem tego mechanizmu jest możliwość włączenie automatycznego kasowania z kosza plików o zadanych kryteriach. I całość zapowiadała się całkiem nieźle – na Ubuntu już od kilku lat korzystam z programu autotrash, który kasuje mi pliki będące w koszu dłużej niż miesiąc. Kosz działa wtedy jak kwarantanna, dzięki której bez obaw mogę usuwać potencjalnie niepotrzebne już pliki – nawet jeśli po kilku dniach okaże się, że w wyniku jakiegoś błędu będę potrzebował ich z powrotem, bez trudu odzyskam je z kosza. Liczyłem że DSM pozwala na podobną konfigurację, ale trochę się przeliczyłem. Owszem, DSM pozwala kasować starsze pliki z kosza, ale kryterium jest data ostatniej modyfikacji pliku, a nie data jego usunięcia. Oznacza to, że jeśli usunę stary plik (np. edytowany 2 miesiące temu), zadanie czyszczenia kosza skasuje go przy najbliższym uruchomieniu, co cały mechanizm czyni bezużytecznym. Błąd ten jest znany już od dawna i nie mogąc się doczekać jego naprawmy stworzyłem pewne jego obejście.
O uprawnieniach słów kilka
Problem rozwiązałem poprzez napisanie prostego skryptu w bashu, który aktualizuje datę ostatniej modyfikacji wszystkich nowych plików w kosztu. Skrypt uruchamiam za pomocą crona (a właściwie „Harmonogramu zadań” z panelu DSM) przed zadaniem czyszczenia kosza. Rozwiązanie może niezbyt wyrafinowane, ale spełnia swoje zadanie. Jednak uruchamianie skryptów w ten sposób, zawsze niesie pewne ryzyko i trzeba mieć świadomość konsekwencji niektórych rozwiązań. Skrypt musi być uruchomiony z prawami jakiegoś użytkownika – ma wtedy takie same możliwości, jak sam użytkownik, czyli może odczytywać, modyfikować i kasować jego pliki, nawet jeśli są one prywatne i tylko właściciel ma do nich dostęp. I nawet jeśli nasz skrypt jest bezpieczny i jesteśmy pewni, że nie robi żadnych podejrzanych rzeczy, ważne jest, żeby nikt niepowołany nie mógł go zmodyfikować, gdyż daje to praktycznie pełny dostęp do danego konta. A to nie jest wcale takie proste i oczywiste, jak początkowo mogłoby się wydawać.
Sam wybór konta, na którym będzie uruchomiony skrypt, też jest dość ważny, bo z jednej strony powinno mieć ono na tyle niskie uprawnienia, aby niczego nie zepsuć i nie mieć dostępu do żadnych prywatnych plików, a z drugiej strony powinno mieć na tyle wysokie uprawnienia, aby móc modyfikować pliki znajdujące się w koszu. W zależności więc od tego do czego służy nam NAS, ilu mamy tam użytkowników i jak wygląda struktura uprawnień, możemy zastosować różne podejścia o różnym stopniu skomplikowania. Jeśli z NAS-a korzystamy praktycznie tylko my i nie martwimy się złośliwe działanie innych użytkowników, bo ich po prostu nie ma, skrypt możemy uruchomić na własnym użytkowniku. Jeśli NAS jest współdzielony, można pomyśleć o założeniu specjalnego konta wykorzystywanego tylko do uruchamiania skryptu, nie ma wtedy ryzyka dostępu do prywatnych plików, bo dane konto ich po prostu nie posiada. Należy jednak pamiętać, że konto musi mieć uprawnienia do modyfikacji plików w koszu (konieczne do zmiany daty ostatniej modyfikacji pliku). Jeśli chodzi o kosz dla zasobu współdzielonego, w którym wszystkie pliki są dostępne dla wszystkich jego użytkowników, nie ma większego problemu – wystarczy nadać dla naszego konta uprawnienia do danego zasobu i wszystko powinno działać. Problem pojawia się, gdy mamy bardziej skomplikowane zestawy uprawnień, np niektóre pliki są dostępne tylko dla wybranego użytkownika lub grupy, a inne dla innego użytkownika lub grupy. W praktyce oznacza to, że skrypt powinien być uruchomiony na prawach roota, co niesie ze sobą szczególne ryzyko, bo root z zasady może wszystko. Stawką więc nie jest wtedy dostęp do prywatnych plików użytkownika, ale przejęcie pełnej kontroli nad urządzeniem, ważne jest więc wtedy szczególne zabezpieczenie skryptów przed niepowołaną modyfikacją. Poniżej zaprezentuję 3 sposoby wdrożenia skryptu, polecam przeczytać całość i dopiero wtedy wybrać coś dla siebie.
Prosty sposób
Najprostszy scenariusz zakłada po prostu wrzucenie skryptu do katalogu współdzielonego, na tym samym poziomie co katalog #recycle
i uruchamianie go stamtąd na uprawnieniach twojego użytkownika. Jeśli jesteś jedynym użytkownikiem NAS-a, sposób powinien być wystarczająco dobry, ale o ile nie jesteś nałogowym ryzykantem albo ekstremalnym leniem, polecam jednak zastosować się do porad z następnego scenariusza.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#! /bin/sh cd ${0%/*} if [ ! -d "#recycle" ]; then echo "#recycle directory does not exist." exit 1 fi cd "#recycle" find -type f ! -path './.bin-meta/*/touch' \ | sed "s|^\./||" \ | while read file; do if [ ! -e "./.bin-meta/$file/touch" ]; then mkdir -p "./.bin-meta/$file" touch "./.bin-meta/$file/touch" touch "./$file" echo "$file" fi done |
Powyższy skrypt zapisujemy w pliku fix-dsm-bin.sh
w tym samym katalogu, w którym znajduje się kosz, który chcemy naprawić, najlepiej za pomocą File Station z DSM.
Tak zapisanemu plikowi musimy nadać odpowiednie uprawnienia. W tym celu klikamy prawym przyciskiem myszy na pliku i wybieramy „Właściwości”. W okienku, które się pojawi, wybieramy zakładkę uprawnienia. Stamtąd usuwamy wszystkie uprawnienia, jakie są przypisane do pliku (jeśli uprawnienie jest wyszarzone i nie można nic z nim zrobić, wybierz „Zaawansowane opcje” -> „Nadaj jawność uprawnieniom odziedziczonym”). Gdy lista uprawnień jest pusta, dodajemy jedno nowe dla właściciela pliku (grupa „Owner”) i zaznaczamy tam wszystkie uprawniania z grupy „Odczyt”. Zatwierdzamy zmiany w obu okienkach. Taki zestaw uprawnień powinien umożliwić dostęp do pliku jedynie jego właścicielowi.
W następnej kolejności musimy dodać nasz skrypt do harmonogramu, tak aby uruchamiał się przed zadaniem czyszczenia kosza ze starych plików. Najlepiej oba skryptu uruchamiać w nocy, gdy mamy pewność, że pomiędzy jednym i drugim skryptem do kosza nie trafią nowe pliki. Odstęp pomiędzy skryptami zależy od liczby plików w koszu i wydajności urządzenia. U mnie przy około 100 plikach w koszu skrypt działa jakieś 4 sekundy, ale dla pewności warto zostawić większy margines błędu, zwłaszcza jeśli mamy pewność, że o 5 nad ranem wszyscy smacznie śpią i nie usuwają żadnych plików. 🙂
Aby dodać zadanie do harmonogramu przechodzimy do „Panelu starowania” i klikamy zakładkę „Harmonogram zadań”. Tam z panelu „Utwórz” wybieramy „Skrypt zdefiniowany przez użytkownika”. W zakładce „Ogólne” podajemy bezwzględną ścieżkę do naszego skryptu (jeśli jej nie znacie, jest dostępna we właściwościach pliku w zakładce „Ogólne” -> „Lokalizacja”) oraz wybieramy użytkownika, na którym go uruchomimy. W zakładce „Harmonogram” ustalamy kiedy skrypt ma się uruchamiać – najlepiej robić to codziennie przed czyszczeniem kosza.
Taka konfiguracja powinna działać i być teoretycznie bezpieczna, bo odebraliśmy uprawnienia do edycji i odczytu pliku wszystkim poza właścicielem. Uprawnienia w DSM są jednak zdradliwe i łatwo jest zupełnie przypadkiem je zmienić lub ominąć. Przykładowo jeśli udostępniasz dany zasób przez NFS bardzo łatwo jest udzielić wszystkim z twojej sieci uprawnienia do odczytu i modyfikacji danego pliku, ponieważ NFS w zasadzie nie ma żadnego mechanizmu obsługi kont i każdy działa z takimi samymi uprawnieniami. Dlatego jest to ryzykowana konfiguracja, która w niektórych wypadkach może być potencjalnie niebezpieczna – sprawdza się tylko w najprostszych wypadkach.
Lepszy sposób
Potencjalne zagrożenia można dość łatwo zniwelować umieszczając skrypt poza ogólnie dostępnym katalogiem współdzielonym. Najprościej jest oczywiście umieścić skrypt w katalogu domowym naszego użytkownika, który domyślnie jest chroniony i nikt poza właścicielem nie powinien mieć do niego dostępu. Cała procedura jest więc podobna jak wcześniej, z tym że zamiast skrypt wrzucić bezpośrednio do katalogu współdzielonego (u mnie /volume1/video
) wrzucamy go do katalogu domowego użytkownika (u mnie /volume1/homes/media-center
). Zmiana uprawnień przebiega bez zmian, ale sam skrypt wymaga pewnych zmian, ponieważ musimy mu wskazać katalog, z którego kosz ma obsłużyć.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#! /bin/sh cd "/volume1/video" if [ ! -d "#recycle" ]; then echo "#recycle directory does not exist." exit 1 fi cd "#recycle" find -type f ! -path './.bin-meta/*/touch' \ | sed "s|^\./||" \ | while read file; do if [ ! -e "./.bin-meta/$file/touch" ]; then mkdir -p "./.bin-meta/$file" touch "./.bin-meta/$file/touch" touch "./$file" echo "$file" fi done |
W oznaczonej linii podajemy ścieżkę do odpowiedniego katalogu. Wszystkie operacje powinny dotyczyć jednego użytkownika – właściciel pliku ze skryptem powinien być taki sam jak właściciel katalogu domowego oraz użytkownik, z którego uprawnieniami skrypt jest uruchamiany.
Dobry sposób
Trzeci sposób wymaga dostępu do NAS-a przez ssh. O ile nie korzystasz na NAS-ie z rozbudowanego systemu uprawnień prawdopodobnie wystarczy ci rozwiązanie ze sposobu drugiego. W przeciwnym razie potrzebujesz uruchamiać skrypt z uprawnieniami roota, a wtedy najlepiej w ogóle ukryć plik ze skryptem przed dostępem przez interfejs webowy i inne usługi udostępniania plików. Jeśli jesteś power-userem i korzystasz już z ssh na NAS-ie będzie to prawdopodobnie najszybsze i najwygodniejsze rozwiązanie – wystarczy przejść do katalogu roota (cd /root
), tam utworzyć plik ze skryptem w formie ze sposobu drugiego i nadać mu uprawnienia do uruchamiania jednocześnie blokując jakikolwiek dostęp do pliku wszystkim innym (chmod 700 fix-dsm-bin.sh
). Po tym wystarczy (tym razem już z poziomu DSM) dodać zadanie do crona, które będzie uruchamiało skrypt przed czyszczeniem kosza – ważne jest, aby użytkownikiem wykonującym skrypt był root. W efekcie jest najbezpieczniejsze i najmniej zawodne rozwiązanie – pliki z kosza powinny być aktualizowane niezależnie od ich uprawnień, a położenie pliku i jego uprawnienia powinny wystarczająco zabezpieczać go przed modyfikacja i niepowołanym uruchomieniem. Wadą jest wysoki próg wejście – konieczność skorzystania z ssh i konsola wielu może przerazić.
Podsumowanie
Z rozwiązania korzystam od kilku tygodni i jak dla mnie działa bez zarzutu. Trzeba jednak zdawać sobie sprawę z jego skutków ubocznych – ponieważ skrypt zmienia datę ostatniej modyfikacji pliku, tracimy w ten sposób pewne informacje – jeśli data ostatniej modyfikacji pliku jest dla ciebie istotna, prawdopodobnie to rozwiązanie będzie dla ciebie bezużyteczne. Skrypt tworzy też dodatkowe pliki w których przechowuje informacje o zaktualizowanych plikach – w praktyce podwaja to liczbę plików w koszu. O ile same pliki są puste i zajmowane przez nie miejsce nie powinno być zmartwieniem, to wykorzystują też wolne węzły w systemie plików – warto mieć to na uwadze jeśli liczba plików w koszu dochodzi do kilku milionów.