Als je een harddisk onder Unix bekijkt, zie je een structuur met benoemde directory's en bestanden. Normaal gesproken zul je niet dieper hoeven te kijken, maar het zou handig zijn om te weten wat er zich afspeelt als er zich een diskcrash voordoet en je bestanden moet proberen te redden. Helaas is er geen goede manier om de diskorganisatie bekeken vanaf het bestandsniveau te beschrijven, dus ik zal het vanaf de kant van de hardware moeten beschrijven.
Het oppervlaktegebied van je disk, waar de gegevens worden opgeslagen, is onderverdeeld op iets dat lijkt op een dartbord, -- in circulaire sporen die weer als taartstukken zijn onderverdeeld in sectoren. Omdat sporen dichtbij de buitenrand uit een grotere oppervlakte bestaan dan die dichtbij de as in het midden van de disk, bevinden er zich op de buitenste sporen meer sectorstukken dan op de binnenste sporen. Iedere sector (of diskblok) heeft dezelfde grootte, die onder moderne Unixes in het algemeen 1 binary K (1024 8-bit woord) groot is. Ieder diskblok heeft een uniek adres of diskbloknummer.
Unix verdeelt de disk in diskpartities. Iedere partitie is een onafgebroken span blokken die gescheiden wordt gebruikt ten opzichte van enige andere partitie, als een bestandssysteem of als swap space. De oorspronkelijke redenen voor partities had te maken met het herstellen bij een crash in een wereld van veel langzamere en veel meer fouten bevattende disks; door de grenzen ertussen neemt vermoedelijk de kans af dat het deel van je disk ontoegankelijk of beschadigd raakt door een willekeurige slechte plek op de disk. Tegenwoordig is het veel belangrijker dat partities voor alleen lezen kunnen worden gedeclareerd (om te voorkomen dat een indringer kritieke systeembestanden kan wijzigen) of met diverse bedoelingen over een netwerk kunnen worden gedeeld wat we hier niet zullen bespreken. Met de laagst-genummerde partitie wordt vaak speciaal omgegaan, als een boot partitie, waar je een kernel kunt plaatsen om te worden geboot.
Iedere partitie bestaat óf uit swap space (wordt gebruikt om virtueel memory aan te vullen óf een bestandssysteem, dat wordt gebruikt om bestanden vast te houden. Swap-space partities worden behandeld als een lineaire reeks blokken. Aan de andere kant hebben bestandssystemen een manier nodig om bestandsnamen naar reeksen diskblokken in te delen. Omdat bestanden groter worden, kleiner worden en gedurende de tijd wijzigen, zullen de gegevensblokken van een bestand niet bestaan uit een lineaire reeks maar het kan zijn dat ze over de partitie verspreid zijn (waar het besturingssysteem dan ook een vrij blok kan vinden als het er één nodig heeft).
Binnen elk bestandssysteem, wordt de indeling van namen naar blokken verwerkt door een structuur die een i-node wordt genoemd. Er is een pool van deze zaken dichtbij de ``onderkant'' (laagst-genummerde blokken) van ieder bestandssysteem (de allerlaagste worden gebruikt voor huishoudelijke zaken en etiketteringsdoeleinden die hier niet zullen worden beschreven). Iedere i-node beschrijft een bestand. Datablokken van een bestand komen voor boven de inodes (in hoger genummerde blokken).
Iedere i-node bestaat uit een lijst met de diskbloknummers in het bestand dat het beschrijft. (In werkelijkheid is dit niet helemaal waar, slechts correct voor kleine bestanden, maar de rest van de details zijn hier niet van belang). Merk op dat de i-node niet de naam van het bestand bevat.
Namen van bestanden komen voor in directorystructuren. Een directorystructuur deelt namen in naar i-node nummers. Daarom kan een bestand in Unix meerdere echte namen hebben (of hard links); het zijn slechts meerdere directory-ingangen die naar dezelfde inode verwijzen.
In het eenvoudigste geval, komt je volledige Unix bestandssysteem voor in slechts één diskpartitie. Ondanks dat je dit op een aantal kleine persoonlijke Unix systemen zal tegenkomen, is het niet gebruikelijk. Het is waarschijnlijker dat ze verspreid zijn over verscheidene diskpartities, mogelijk op verschillende fysieke disks. Dus het kan zijn dat er op je systeem bijvoorbeeld een kleine partitie voorkomt met de kernel, een wat grotere waar de OS utilites op voorkomen, en een veel grotere waar de home directory's op voorkomen.
De enige partitie waar je onmiddellijk na de systeemstart toegang toe zal hebben is je rootpartitie, welke (bijna altijd) degene is waarvan je bootte. Het bevat de root directory van het bestandssysteem, de top node waaraan al het andere hangt.
De andere partities in het systeem moeten aan deze root zijn gekoppeld opdat je volledige, uit meerdere-partities bestaande bestandssysteem toegankelijk is. Ongeveer halverwege het bootproces zal Unix deze niet-rootpartities toegankelijk maken. Het zal iedere partitie aan een directory op de rootpartitie mounten.
Als je bijvoorbeeld een Unix directory met de naam `/usr' hebt, is het waarschijnlijk een mount point naar een partitie die veel geïnstalleerde programma's op je Unix bevat maar niet is vereist gedurende de initiële boot.
We kunnen nu van boven naar onder het bestandssysteem bekijken. Als je een bestand opent (zoals, laten we zeggen, /home/esr/WWW/ldp/fundamentals.sgml) gebeurt er het volgende:
Je kernel begint bij de root van je Unix bestandssysteem (in de root partitie). Het zoekt van daar uit naar een directory met de naam `home'. Gewoonlijk is `home' een mountpoint naar een grote gebruikerspartitie elders, dus zal het daar naartoe gaan. In de top-level directorystructuur van deze gebruikerspartitie, zal het naar een ingang met de naam `esr' zoeken en een inode-nummer extraheren. Het zal naar die i-node gaan, opmerken dat het een directorystructuur is, en `WWW' opzoeken. Die i-node extraherend, zal het naar de corresponderende subdirectory gaan en `ldp' opzoeken. Dat zal het weer naar een andere directory-inode brengen. Die openend, zal het een i-node nummer voor `fundamentals.sgml' vinden. Die inode is geen directory, maar bevat in plaats daarvan de lijst met diskblokken die met het bestand overeenkomen.
Om te voorkomen dat programma's per ongeluk of met opzet gegevens in de weg zitten, heeft Unix permissies. Deze werden oorspronkelijk ontworpen om timesharing te ondersteunen door meerdere gebruikers op dezelfde computer tegen elkaar te beschermen, in de tijd dat Unix hoofdzakelijk op dure gedeelde minicomputers werd gedraaid.
Je moet onze beschrijving van gebruikers en groepen in de sectie Wat gebeurt er als je inlogt? even terughalen, om bestandspermissies te kunnen begrijpen. Ieder bestand heeft een gebruiker en een groep als eigenaar. Dit zijn in eerste instantie degenen die het bestand aanmaakten; ze kunnen met de programma's chown(1) en chgrp(1) worden gewijzigd.
De basis-permissies die met een bestand kunnen worden geassocieerd zijn `read' (permissie de gegevens erin te lezen), `write' (permissie het te wijzigen) en `execute' (permissie het als een programma uit te voeren). Ieder bestand heeft drie sets met permissies; één voor de eigenaar ervan, één voor iedere gebruiker uit de groep ervan, en één voor alle anderen. De `privileges' die je krijgt, als je inlogt, bestaan uit de mogelijkheden om die bestanden waarvan de permissie-bits overeenkomen met je gebruikers-ID of één van de groepen waartoe je behoort, te lezen, schrijven en uit te voeren.
Laten we eens een aantal listings van bestanden op een hypothetisch Unix-systeem bekijken om te bezien hoe deze op elkaar inwerken en hoe Unix ze toont. Hier is er één:
snark:~$ ls -l notes
-rw-r--r-- 1 esr users 2993 Jun 17 11:00 notes
Dit is een gewoon gegevensbestand. De listing vertelt ons dat `esr' de eigenaar ervan is en dat het werd aangemaakt met de groep `users'. Waarschijnlijk plaatst de computer waar we ons nu op bevinden, alle gewone gebruikers standaard in deze groep; andere groepen die je vaak zal zien op timesharing computers zijn `staff', `admin', of `wheel' (om vanzelfsprekende redenen zijn groepen op een single-user systeem of op PC's niet zo belangrijk). Op je UNIX-systeem kan het een andere standaardgroep zijn, misschien één die is benoemd naar je gebruikers-ID.
De string `-rw-r--r--' stelt de permissie-bits voor van het bestand. Het allereerste streepje is de positie van de directory-bit; het zou een `d' tonen als het bestand een directory was. De eerste posities daarna zijn de drie plaatsen met gebruikerspermissies, het tweede drietal de permissies van de groep en het derde drietal zijn de permissies voor alle anderen (worden vaak `world' permissies genoemd). Bij dit bestand mag de eigenaar van het bestand `esr' het bestand lezen en beschrijven, andere mensen in de groep `users' mogen het lezen, en alle anderen in de wereld mogen het lezen. Dit is een typische set permissies voor een gewoon gegevensbestand.
Laten we nu eens kijken naar een bestand met totaal andere permissies. Dit bestand is de GCC, de GNU C-compiler.
snark:~$ ls -l /usr/bin/gcc
-rwxr-xr-x 3 root bin 64796 Mar 21 16:41 /usr/bin/gcc
Dit bestand behoort toe aan een gebruiker genaamd `root' en een groep genaamd `bin'; het kan alleen door root worden beschreven (gewijzigd), maar door iedereen worden gelezen of uitgevoerd. Dit is een typische eigenaarschap en set permissies voor een voorgeïnstalleerd systeemcommando. Op een aantal Unixes bestaat de `bin' groep om systeemcommando's te groeperen (de naam is een historisch overblijfsel, een afkorting van `binary'). Het kan zijn dat er onder jouw Unix in plaats daarvan een `root' groep wordt gebruikt (niet geheel hetzelfde als de `root' gebruiker!).
De `root' gebruiker is de conventionele naam voor numeriek gebruiker ID 0, een speciaal, account met privileges waarmee alle andere privileges kunnen worden overheerst. Root-toegang is handig maar gevaarlijk; een typische fout, als je als root bent ingelogd, kan kritieke systeembestanden in de war schoppen wat met hetzelfde commando, uitgevoerd met een gewoon gebruikersaccount, niet kan.
Omdat het root-account zo krachtig is, is waakzaamheid bij de toegang ertoe geboden. Je root-wachtwoord is het enige meest kritieke stukje beveiligingsinformatie op je systeem, en dat is wat alle crackers en indringers, die ooit zullen komen, zullen proberen te verkrijgen.
(over wachtwoorden: Schrijf ze niet op -- en kies geen wachtwoorden uit die makkelijk te raden zijn, zoals de voornaam van je vriendin/vriend/echtgenote. Dit is een verbazingwekkende algemene slechte gewoonte waarmee crackers worden geholpen...). In het algemeen, kies geen woord uit het woordenboek; er zijn programma's genaamd `woordenboekkrakers' die naar waarschijnlijke wachtwoorden zoeken door woordenlijsten met algemene keuzes door te nemen. Een goede techniek bestaat uit een combinatie van een bestaand woord, een cijfer, een ander woord, zoals `shark6cider' of `jump3joy'; dat zal er voor zorgen dat de zoekruimte voor een woordenboekkraker te groot is. Maak echter geen gebruik van deze voorbeelden -- crackers zouden daar vanuit kunnen gaan en ze in hun woordenboeken kunnen plaatsen.
Laten we nu eens een derde situatie bekijken:
snark:~$ ls -ld ~
drwxr-xr-x 89 esr users 9216 Jun 27 11:29 /home2/esr
snark:~$
Dit bestand is een directory (merk de `d' op in het eerste permissie slot). We zien dat het alleen door esr kan worden beschreven, maar door alle anderen kan worden gelezen en uitgevoerd.
Leespermissie geeft je de mogelijkheid de directory weer te geven -- dat wil zeggen, de namen van bestanden en directory's die erin staan te zien. Schrijfpermissie geeft je de mogelijkheid bestanden in de directory aan te maken en te verwijderen. Als je je een lijst namen van bestanden en subdirectory's in de directory herinnert, zijn deze regels begrijpelijk.
Execute-permissie op een directory betekent dat je via de directory bestanden en daaronderliggende directory's kunt openen. Als resultaat geeft het je permissie de inodes in de directory te benaderen. Een directory met de execute-bit volledig uitgeschakeld zou nutteloos zijn.
Zo nu en dan zal je een directory tegenkomen die voor iedereen leesbaar, maar niet voor iedereen uitvoerbaar is; dit betekent dat een willekeurige gebruiker alleen bij de daaronder liggende bestanden en directory's kan komen als het de exacte namen kent (de directory kan niet worden weergegeven).
Het is belangrijk eraan te denken dat lees, schrijf- of permissie om uit te voeren op een directory onafhankelijk staat van de bestandspermissies en daaronderliggende directory's. In het bijzonder betekent schrijftoegang op een directory dat je nieuwe bestanden erin aan kunt maken en bestaande bestanden kunt verwijderen, maar het geeft je niet automatisch schrijftoegang tot bestaande bestanden.
Laten we als laatste eens kijken naar de permissies van het login-programma.
snark:~$ ls -l /bin/login
-rwsr-xr-x 1 root bin 20164 Apr 17 12:57 /bin/login
Dit heeft de permissies zoals we ze zouden verwachten van een systeemcommando -- behalve dan die `s', waar de execute-bit van de eigenaar zou moeten staan. Dit is de zichtbare manifestatie van een speciale permissie genaamd de `set-user-id' of setuid bit.
De setuid bit is normaliter verbonden met programma's die gewone gebruikers root-privileges toe moeten kennen, maar dan op een gecontroleerde wijze. Als het op een uitvoerbaar programma is ingesteld, krijg je de privileges van de eigenaar van dat programmabestand terwijl het programma namens jou draait, of 't nu wel of niet met jou overeenkomt.
Net als het root-account, zijn setuid programma's handig maar gevaarlijk. Iedereen die een setuid programma met als eigenaar root, kan verwerpen of kan wijzigen, kan het gebruiken om een shell met root-privileges voort te brengen. Om deze reden, wordt op de meeste Unixes het setuid-bit uitgezet, als het bestand voor schrijven wordt geopend. Veel aanvallen op de Unix-beveiliging proberen bugs te exploiteren in setuid programma's om ze te kunnen verwerpen. Beveiligings bewuste systeembeheerders zijn daarom extra voorzichtig met deze programma's en installeren met tegenzin nieuwe programma's.
Er zijn een paar belangrijke details die we verdoezelde toen we hiervoor
de permissies bespraken; namelijk hoe de eigenaar en de permissies van de
groep worden toegekend, wanneer een bestand of directory voor 't eerst wordt
aangemaakt. De groep is een probleem omdat gebruikers deel uit kunnen maken van
meerdere groepen, maar één daarvan (aangegeven in het record
van de gebruiker in /etc/passwd
) is de
standaardgroep van de gebruiker en hierin zullen normaal
gesproken de bestanden staan die door de gebruiker zijn aangemaakt.
Het verhaal met initiïle permissie-bits is iets gecompliceerder. Een programma dat een bestand aanmaakt, zal er om te beginnen de permissies aan toekennen. Maar deze zullen door een variabele in de gebruikersomgeving met de naam umask worden gewijzigd. De umask geeft aan welke permissie-bits worden uitgezet als een bestand wordt aangemaakt; de meest algemene waarde, en op de meeste systemen de standaard, is -------w- of 002, waarmee de world-write bit wordt uitgezet. Zie de documentatie van het umask commando in de manual-page van je shell voor details.
De initiële directorygroep is ook wat gecompliceerd. Op een aantal Unix-systemen krijgt een nieuwe directory de standaardgroep van de gebruiker die het aanmaakt (dit is de System V conventie); op andere systemen krijgt de directory als eigenaar de groep van de parent-directory waarin het is aangemaakt (dit is de BSD-conventie). Op een aantal moderne Unixen, waaronder Linux, kan die laatste worden geselecteerd door het instellen van de set-group-ID op de directory (chmod g+s).
Er is een nuttige discussie over bestandspermissies in het artikel van eric Goebelbecker Take Command.
Eerder lieten we doorschemeren dat bestandssystemen kwetsbare zaken kunnen zijn. Nu weten we dat je je door iets wat een willekeurig lange reeks directory en i-node verwijzingen kan zijn, moet manoeuvreren. Veronderstel nu dat je harddisk een slechte plek ontwikkelt?
Als je geluk hebt, zullen er alleen maar wat bestandsgegevens beschadigd raken. Als je geen geluk hebt, is het mogelijk dat een directorystructuur of i-node nummer wordt verknoeid en een volledige subtree van je systeem in het niets terechtkomt -- of nog erger, in een verknoeide structuur resulteert die op meerdere manieren naar hetzelfde diskblok of een inode verwijst. Dergelijke corruptie kan door normale bestandsbewerkingen worden verspreid, door gegevens te ruïneren, welke zich niet op de originele slechte plek bevonden.
Gelukkig, zijn dit soort onvoorziene omstandigheden heel ongewoon geworden, aangezien diskhardware betrouwbaarder is geworden. Nog steeds betekent het dat je Unix een periodieke integriteits-controle uit zal willen voeren op het bestandssysteem om er zeker van te zijn dat er niks aan scheelt. Moderne Unixes voeren op iedere partitie tijdens het opstarten vlak voor het mounten een snelle integriteits-controle uit. Iedere paar reboots doen ze een veel grondiger controle die een paar minuten langer in beslag neemt.
Als dit alles klinkt alsof Unix verschrikkelijk complex en vatbaar voor storingen is, kan het geruststellend zijn te weten dat deze opstartcontroles kenmerkend normale problemen afvangen en corrigeren voordat ze echt noodlottig worden. Andere besturingssystemen hebben deze faciliteiten niet, wat het booten een beetje versnelt, maar je veel serieuzer onder pressie zet als je probeert met de hand te herstellen. (en in de eerste plaats in de veronderstelling dat je een kopie van de Norton Utilities of iets dergelijks hebt...).