X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filedir.tex;h=c1bb182b55d93865bc3f79cbd79ec761be294b10;hp=88f29647eb7f57ad5bd969cdba9bc94a89dc5924;hb=96e11f1878552c4c4f245448e9dc6d66e1658542;hpb=4ad4523de32d786ae4c24ef157bd4b8fe4aac534 diff --git a/filedir.tex b/filedir.tex index 88f2964..c1bb182 100644 --- a/filedir.tex +++ b/filedir.tex @@ -2,597 +2,873 @@ \label{cha:files_and_dirs} In questo capitolo tratteremo in dettaglio le modalità con cui si gestiscono -file e directory, ed in particolare esamineremo come è strutturato il sistema -base di protezioni e controllo di accesso ai file, e tutta l'interfaccia che -permette la manipolazione dei vari attributi di file e directory. Tutto quello -che riguarda invece la manipolazione del contenuto dei file è lasciato ai -capitoli successivi. +file e directory, iniziando dalle funzioni di libreria che si usano per +copiarli, spostarli e cambiarne i nomi. Esamineremo poi l'interfaccia che +permette la manipolazione dei vari attributi di file e directory ed alla fine +faremo una trattazione dettagliata su come è strutturato il sistema base di +protezioni e controllo dell'accesso ai file e sulle funzioni che ne permettono +la gestione. Tutto quello che riguarda invece la manipolazione del contenuto +dei file è lasciato ai capitoli successivi. -\section{Il controllo di accesso ai file} -\label{sec:file_access_control} +\section{La gestione di file e directory} +\label{sec:file_dir} -Una delle caratteristiche fondamentali di tutti i sistemi unix-like è quella -del controllo di accesso ai file, che viene implementato per qualunque -filesystem standard. In questa sezione ne esamineremo i concetti essenziali e -le funzioni usate per gestirne i vari aspetti. +Come già accennato in \secref{sec:file_filesystem} in un sistema unix-like la +gestione dei file ha delle caratteristiche specifiche che derivano +direttamente dall'architettura del sistema; in questa sezione esamineremo le +funzioni usate per manipolazione nel filesytem di file e directory, per la +creazione di link simbolici e diretti, per la gestione e la lettura delle +directory; il tutto mettendo in evidenza le conseguenze della struttura +standard della gestione dei file in un sistema unix-like, introdotta nel +capitolo precedente. -\subsection{I permessi per l'accesso ai file} -\label{sec:file_perm_overview} +\subsection{Le funzioni \func{link} e \func{unlink}} +\label{sec:file_link} -Il controllo di accesso ai file in unix segue un modello abbastanza semplice -(ma adatto alla gran parte delle esigenze) in cui si dividono i permessi su -tre livelli. Si tenga conto poi che quanto diremo è vero solo per filesystem -di tipo unix, e non è detto che sia applicabile a un filesystem -qualunque\footnote{ed infatti non è vero per il filesystem vfat di Windows, - per il quale i permessi vengono assegnati in maniera fissa con un opzione in - fase di montaggio}. Esistono inoltre estensioni che permettono di -implementare le ACL (\textit{Access Control List}) che sono un meccanismo di -controllo di accesso molto più sofisticato. - -Ad ogni file unix associa sempre l'utente che ne è proprietario (il cosiddetto -\textit{owner}) e il gruppo di appartenenza, secondo il meccanismo degli -identificatori di utenti e gruppi (\acr{uid} e \acr{gid}). Questi valori -sono accessibili da programma tramite i campi \var{st\_uid} e \var{st\_gid} -della struttura \var{stat} (si veda \secref{sec:file_stat}). Ad ogni file -viene inoltre associato un insieme di permessi che sono divisi in tre classi, -e cioè attribuiti rispettivamente all'utente proprietario del file, a un -qualunque utente faccia parte del gruppo cui appartiene il file, e a tutti gli -altri utenti. - -I permessi, così come vengono presi dai comandi e dalle routine di sistema, -sono espressi da un numero di 12 bit; di questi i nove meno significativi sono -usati a gruppi di tre per indicare i permessi base di lettura, scrittura ed -esecuzione (indicati nei comandi di sistema con le lettere \cmd{w}, \cmd{r} e -\cmd{x}) ed applicabili rispettivamente al proprietario, al gruppo, a tutti -gli altri. I restanti tre bit (\acr{suid}, \acr{sgid}, e -\textsl{sticky}) sono usati per indicare alcune caratteristiche più complesse -su cui torneremo in seguito (vedi \secref{sec:file_suid_sgid} e -\secref{sec:file_sticky}). +Una caratteristica comune a diversi sistemi operativi è quella di poter creare +dei nomi fittizi (come gli alias del MacOS o i collegamenti di Windows) che +permettono di fare riferimento allo stesso file chiamandolo con nomi diversi +o accedendovi da directory diverse. -Anche i permessi, come tutte le altre informazioni generali, sono tenuti per -ciascun file nell'inode; in particolare essi sono contenuti in alcuni bit -del campo \var{st\_mode} della struttura letta da \func{stat} (di nuovo si veda -\secref{sec:file_stat} per i dettagli). - -In genere ci si riferisce a questo raggruppamento dei permessi usando le -lettere \cmd{u} (per \textit{user}), \cmd{g} (per \textit{group}) e \cmd{o} -(per \textit{other}), inoltre se si vuole indicare tutti i raggruppamenti -insieme si usa la lettera \cmd{a} (per \textit{all}). Si tenga ben presente -questa distinzione dato che in certi casi, mutuando la terminologia in uso nel -VMS, si parla dei permessi base come di permessi per \textit{owner}, -\textit{group} ed \textit{all}, le cui iniziali possono dar luogo a confusione. -Le costanti che permettono di accedere al valore numerico di questi bit nel -campo \var{st\_mode} sono riportate in \ntab. +Questo è possibile anche in ambiente Unix, dove tali collegamenti sono +usualmente chiamati \textit{link}; ma data la struttura del sistema di +gestione dei file (ed in particolare quanto trattato in +\secref{sec:file_arch_func}) ci sono due metodi sostanzialmente diversi per +fare questa operazione. -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}[c]{|c|l|} - \hline - \textbf{\var{st\_mode}} bit & \textbf{Significato} \\ - \hline - \hline - \macro{S\_IRUSR} & \textit{user-read}, l'utente può leggere \\ - \macro{S\_IWUSR} & \textit{user-write}, l'utente può scrivere \\ - \macro{S\_IXUSR} & \textit{user-execute}, l'utente può eseguire \\ - \hline - \macro{S\_IRGRP} & \textit{group-read}, il gruppo può leggere \\ - \macro{S\_IWGRP} & \textit{group-write}, il gruppo può scrivere \\ - \macro{S\_IXGRP} & \textit{group-execute}, il gruppo può eseguire\\ - \hline - \macro{S\_IROTH} & \textit{other-read}, tutti possono leggere \\ - \macro{S\_IWOTH} & \textit{other-write}, tutti possono scrivere \\ - \macro{S\_IXOTH} & \textit{other-execute}, tutti possono eseguire\\ - \hline - \end{tabular} - \caption{I bit dei permessi di accesso ai file, come definiti in - \texttt{}} - \label{tab:file_bit_perm} -\end{table} +Come spiegato in \secref{sec:file_filesystem} l'accesso al contenuto di un +file su disco avviene attraverso il suo inode\index{inode}, e il nome che si +trova in una directory è solo un'etichetta associata ad un puntatore a che fa +riferimento al suddetto inode. -Questi permessi vengono usati in maniera diversa dalle varie funzioni, e a -seconda che si riferiscano a file, link simbolici o directory, qui ci -limiteremo ad un riassunto delle regole generali, entrando nei -dettagli più avanti. +Questo significa che la realizzazione di un link è immediata in quanto uno +stesso file può avere tanti nomi diversi allo stesso tempo, dati da +altrettante diverse associazioni allo stesso inode; si noti poi che nessuno di +questi nomi viene ad assumere una particolare preferenza o originalità +rispetto agli altri. -La prima regola è che per poter accedere ad un file attraverso il suo pathname -occorre il permesso di esecuzione in ciascuna delle directory che compongono -il pathname, e lo stesso vale per aprire un file nella directory corrente (per -la quale appunto serve il diritto di esecuzione). +Per aggiungere un nome ad un inode si utilizza la funzione \func{link}; si +suole chiamare questo tipo di associazione un collegamento diretto (o +\textit{hard link}). Il prototipo della funzione e le sue caratteristiche +principali, come risultano dalla pagina di manuale, sono le seguenti: +\begin{prototype}{unistd.h} +{int link(const char *oldpath, const char *newpath)} + Crea un nuovo collegamento diretto al file indicato da \var{oldpath} + dandogli nome \var{newpath}. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 in + caso di errore. La variabile \var{errno} viene impostata + opportunamente, i principali codici di errore sono: + \begin{errlist} + \item[\macro{EXDEV}] \var{oldpath} e \var{newpath} non sono sullo + stesso filesystem. + \item[\macro{EPERM}] il filesystem che contiene \var{oldpath} e + \macro{newpath} non supporta i link diretti o è una directory. + \item[\macro{EEXIST}] un file (o una directory) con quel nome esiste di + già. + \item[\macro{EMLINK}] ci sono troppi link al file \var{oldpath} (il + numero massimo è specificato dalla variabile \macro{LINK\_MAX}, vedi + \secref{sec:sys_limits}). + \end{errlist} + ed inoltre \macro{EACCES}, \macro{ENAMETOOLONG}, \macro{ENOTDIR}, + \macro{EFAULT}, \macro{ENOMEM}, \macro{EROFS}, \macro{ELOOP}, + \macro{ENOSPC}, \macro{EIO}.} +\end{prototype} -Per una directory infatti il permesso di esecuzione ha il significato -specifico che essa può essere attraversata nella risoluzione del pathname, ed -è distinto dal permesso di lettura che invece implica che si può leggere il -contenuto della directory. Questo significa che se si ha il permesso di -esecuzione senza permesso di lettura si potrà lo stesso aprire un file in una -directory (se si hanno i permessi opportuni per il medesimo) ma non si potrà -vederlo con \cmd{ls} (per crearlo occorrerà anche il permesso di scrittura per -la directory). - -Avere il permesso di lettura per un file consente di aprirlo con le opzioni di -sola lettura (\macro{O\_RDONLY}) o di lettura/scrittura (\macro{O\_RDWR}) e -leggerne il contenuto. Avere il permesso di scrittura consente di aprire un -file in sola scrittura (\macro{O\_WRONLY}) o lettura/scrittura -(\macro{O\_RDWR}) e modificarne il contenuto, lo stesso permesso è necessario -per poter troncare il file con l'opzione \macro{O\_TRUNC}. +La creazione di un nuovo collegamento diretto non copia il contenuto del file, +ma si limita a creare una voce nella directory specificata con \var{newpath} e +ad aumentare di uno il numero di referenze al file (riportato nel campo +\var{st\_nlink} della struttura \var{stat}, vedi \secref{sec:file_stat}) +aggiungendo il nuovo nome ai precedenti. Si noti che uno stesso file può +essere così chiamato con vari nomi in diverse directory. + +Per quanto dicevamo in \secref{sec:file_filesystem} la creazione di un +collegamento diretto è possibile solo se entrambi i pathname sono nello stesso +filesystem; inoltre il filesystem deve supportare i collegamenti diretti (il +meccanismo non è disponibile ad esempio con il filesystem \acr{vfat} di +Windows). + +La funzione inoltre opera sia sui file ordinari che sugli altri oggetti del +filesystem, con l'eccezione delle directory. In alcune versioni di Unix solo +l'amministratore è in grado di creare un collegamento diretto ad un'altra +directory: questo viene fatto perché con una tale operazione è possibile +creare dei circoli nel filesystem (vedi l'esempio mostrato in +\secref{sec:file_symlink}, dove riprenderemo il discorso) che molti programmi +non sono in grado di gestire e la cui rimozione diventerebbe estremamente +complicata (in genere per questo tipo di errori occorre far girare il +programma \cmd{fsck} per riparare il filesystem). + +Data la pericolosità di questa operazione e la disponibilità dei link +simbolici che possono fornire la stessa funzionalità senza questi problemi, +nei filesystem usati in Linux questa caratteristica è stata completamente +disabilitata, e al tentativo di creare un link diretto ad una directory la +funzione restituisce l'errore \macro{EPERM}. + +La rimozione di un file (o più precisamente della voce che lo referenzia +all'interno di una directory) si effettua con la funzione \func{unlink}; il +suo prototipo è il seguente: +\begin{prototype}{unistd.h}{int unlink(const char *pathname)} + Cancella il nome specificato dal pathname nella relativa directory e + decrementa il numero di riferimenti nel relativo inode. Nel caso di link + simbolico cancella il link simbolico; nel caso di socket, fifo o file di + dispositivo rimuove il nome, ma come per i file i processi che hanno aperto + uno di questi oggetti possono continuare ad utilizzarlo. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso il file non viene toccato. La variabile + \var{errno} viene impostata secondo i seguenti codici di errore: + \begin{errlist} + \item[\macro{EISDIR}] \var{pathname} si riferisce ad una directory + (valore specifico ritornato da Linux che non consente l'uso di + \var{unlink} con le directory, e non conforme allo standard POSIX, che + prescrive invece l'uso di \macro{EPERM} in caso l'operazione non sia + consentita o il processo non abbia privilegi sufficienti). + \item[\macro{EROFS}] \var{pathname} è su un filesystem montato in sola + lettura. + \item[\macro{EISDIR}] \var{pathname} fa riferimento a una directory. + \end{errlist} + ed inoltre: \macro{EACCES}, \macro{EFAULT}, \macro{ENOENT}, \macro{ENOTDIR}, + \macro{ENOMEM}, \macro{EROFS}, \macro{ELOOP}, \macro{EIO}.} +\end{prototype} -Non si può creare un file fintanto che non si disponga del permesso di -esecuzione e di quello di scrittura per la directory di destinazione; gli -stessi permessi occorrono per cancellare un file da una directory (si ricordi -che questo non implica necessariamente la rimozione del contenuto del file dal -disco), non è necessario nessun tipo di permesso per il file stesso (infatti -esso non viene toccato, viene solo modificato il contenuto della directory, -rimuovendo la voce che ad esso fa rifermento). +Per cancellare una voce in una directory è necessario avere il permesso di +scrittura su di essa (dato che si va a rimuovere una voce dal suo contenuto) e +il diritto di esecuzione sulla directory che la contiene (torneremo in +dettaglio sui permessi e gli attributi in \secref{sec:file_access_control}), +se inoltre lo \textit{sticky} bit è impostato occorrerà anche essere +proprietari del file o proprietari della directory (o root, per cui nessuna +delle restrizioni è applicata). -Per poter eseguire un file (che sia un programma compilato od uno script di -shell, od un altro tipo di file eseguibile riconosciuto dal kernel), occorre -avere il permesso di esecuzione, inoltre solo i file regolari possono essere -eseguiti. +Una delle caratteristiche di queste funzioni è che la creazione/rimozione +del nome dalla directory e l'incremento/decremento del numero di riferimenti +nell'inode devono essere effettuati in maniera atomica (si veda +\secref{sec:proc_atom_oper}) senza possibili interruzioni fra le due +operazioni. Per questo entrambe queste funzioni sono realizzate tramite una +singola system call. -I permessi per un link simbolico sono ignorati, contano quelli del file a cui -fa riferimento; per questo in genere \cmd{ls} per un link simbolico riporta -tutti i permessi come concessi; utente e gruppo a cui esso appartiene vengono -ignorati quando il link viene risolto, vengono controllati solo quando viene -richiesta la rimozione del link e quest'ultimo è in una directory con lo -\textsl{sticky bit} settato (si veda \secref{sec:file_sticky}). +Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti +i riferimenti ad esso sono stati cancellati: solo quando il \textit{link + count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A +questo però si aggiunge un'altra condizione, e cioè che non ci siano processi +che abbiano detto file aperto. -La procedura con cui il kernel stabilisce se un processo possiede un certo -permesso (di lettura, scrittura o esecuzione) si basa sul confronto fra -l'utente e il gruppo a cui il file appartiene (i valori di \var{st\_uid} e -\var{st\_gid} accennati in precedenza) e l'\textit{effective user id}, -l'\textit{effective group id} e gli eventuali \textit{supplementary group id} -del processo. +Questa proprietà viene spesso usata per essere sicuri di non lasciare file +temporanei su disco in caso di crash dei programmi; la tecnica è quella di +aprire il file e chiamare \func{unlink} subito dopo, in questo modo il +contenuto del file è sempre disponibile all'interno del processo attraverso il +suo file descriptor (vedi \secref{sec:file_fd}) fintanto che il processo non +chiude il file, ma non ne resta traccia in nessuna directory, e lo spazio +occupato su disco viene immediatamente rilasciato alla conclusione del +processo (quando tutti i file vengono chiusi). -Per una spiegazione dettagliata degli identificatori associati ai processi si -veda \secref{sec:proc_perms}; normalmente, a parte quanto vedremo in -\secref{sec:file_suid_sgid}, l'\textit{effective user id} e -l'\textit{effective group id} corrispondono a \acr{uid} e \acr{gid} -dell'utente che ha lanciato il processo, mentre i \textit{supplementary group - id} sono quelli dei gruppi cui l'utente appartiene. -I passi attraverso i quali viene stabilito se il processo possiede il diritto -di accesso sono i seguenti: -\begin{itemize} -\item Se l'\textit{effective user id} del processo è zero (corrispondente - all'amministratore) l'accesso è sempre garantito senza nessun ulteriore - controllo. Per questo motivo \textsl{root} ha piena libertà di accesso a - tutti i file. -\item Se l'\textit{effective user id} del processo è uguale all'uid del - proprietario del file (nel qual caso si dice che il processo è proprietario - del file) allora: - \begin{itemize} - \item se il relativo\footnote{per relativo si intende il bit di user-read se - il processo vuole accedere in scrittura, quello di user-write per - l'accesso in scrittura, etc.} bit dei permessi d'accesso dell'utente è - settato, l'accesso è consentito - \item altrimenti l'accesso è negato - \end{itemize} -\item Se l'\textit{effective group id} del processo o uno dei - \textit{supplementary group id} dei processi corrispondono al \acr{gid} del - file allora: - \begin{itemize} - \item se il bit dei permessi d'accesso del gruppo è settato, l'accesso è - consentito, - \item altrimenti l'accesso è negato - \end{itemize} -\item se il bit dei permessi d'accesso per tutti gli altri è settato, - l'accesso è consentito, altrimenti l'accesso è negato. -\end{itemize} +\subsection{Le funzioni \func{remove} e \func{rename}} +\label{sec:file_remove} -Si tenga presente che questi passi vengono eseguiti esattamente in -quest'ordine. Questo vuol dire che se un processo è il proprietario di un file -l'accesso è consentito o negato solo sulla base dei permessi per l'utente; i -permessi per il gruppo non vengono neanche controllati; lo stesso vale se il -processo appartiene ad un gruppo appropriato, in questo caso i permessi per -tutti gli altri non vengono controllati. +Al contrario di quanto avviene con altri unix in Linux non è possibile usare +\func{unlink} sulle directory; per cancellare una directory si può usare la +funzione \func{rmdir} (vedi \secref{sec:file_dir_creat_rem}), oppure la +funzione \func{remove}. Questa è la funzione prevista dallo standard ANSI C +per cancellare un file o una directory (e funziona anche per i sistemi che non +supportano i link diretti). Per i file è identica a \func{unlink} e per le +directory è identica a \func{rmdir}: +\begin{prototype}{stdio.h}{int remove(const char *pathname)} + Cancella un nome dal filesystem. Usa \func{unlink} per i file e + \func{rmdir} per le directory. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso il file non viene toccato. Per i codici di + errore vedi quanto riportato nelle descrizioni di \func{unlink} e + \func{rmdir}.} +\end{prototype} +Per cambiare nome ad un file o a una directory (che devono comunque essere +nello stesso filesystem) si usa invece la funzione \func{rename},\footnote{la + funzione è definita dallo standard ANSI C solo per i file, POSIX estende la + funzione anche alle directory.} il cui prototipo è: +\begin{prototype}{stdio.h} + {int rename(const char *oldpath, const char *newpath)} + + Rinomina \var{oldpath} in \var{newpath}, eseguendo se necessario lo + spostamento di un file fra directory diverse. Eventuali altri link diretti + allo stesso file non vengono influenzati. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso il file non viene toccato. La variabile + \var{errno} viene impostata secondo i seguenti codici di errore: + \begin{errlist} + \item[\macro{EISDIR}] \var{newpath} è una directory mentre \var{oldpath} non + è una directory. + \item[\macro{EXDEV}] \var{oldpath} e \var{newpath} non sono sullo stesso + filesystem. + \item[\macro{ENOTEMPTY}] \var{newpath} è una directory già esistente e non + vuota. + \item[\macro{EBUSY}] o \var{oldpath} o \var{newpath} sono in uso da parte di + qualche processo (come directory di lavoro o come radice) o del sistema + (come mount point). + \item[\macro{EINVAL}] \var{newpath} contiene un prefisso di \var{oldpath} o + più in generale si è cercato di creare una directory come sottodirectory + di se stessa. + \item[\macro{ENOTDIR}] Uno dei componenti dei pathname non è una directory o + \var{oldpath} è una directory e \var{newpath} esiste e non è una + directory. + \end{errlist} + ed inoltre \macro{EACCESS}, \macro{EPERM}, \macro{EMLINK}, \macro{ENOENT}, + \macro{ENOMEM}, \macro{EROFS}, \macro{ELOOP} e \macro{ENOSPC}.} +\end{prototype} -\subsection{I bit \acr{suid} e \acr{sgid}} -\label{sec:file_suid_sgid} +Il comportamento della funzione è diverso a seconda che si voglia rinominare +un file o una directory; se ci riferisce a un file allora \var{newpath}, se +esiste, non deve essere una directory (altrimenti si ha l'errore +\macro{EISDIR}). Nel caso \var{newpath} indichi un file esistente questo viene +cancellato e rimpiazzato (atomicamente). + +Se \var{oldpath} è una directory allora \var{newpath}, se esiste, deve essere +una directory vuota, altrimenti si avranno gli errori \macro{ENOTDIR} (se non +è una directory) o \macro{ENOTEMPTY} (se non è vuota). Chiaramente +\var{newpath} non può contenere \var{oldpath} altrimenti si avrà un errore +\macro{EINVAL}. + +Se \var{oldpath} si riferisce a un link simbolico questo sarà rinominato; se +\var{newpath} è un link simbolico verrà cancellato come qualunque altro file. +Infine qualora \var{oldpath} e \var{newpath} siano due nomi dello stesso file +lo standard POSIX prevede che la funzione non dia errore, e non faccia nulla, +lasciando entrambi i nomi; Linux segue questo standard, anche se, come fatto +notare dal manuale delle \textit{glibc}, il comportamento più ragionevole +sarebbe quello di cancellare \var{oldpath}. + +Il vantaggio nell'uso di questa funzione al posto della chiamata successiva di +\func{link} e \func{unlink} è che l'operazione è eseguita atomicamente, non +può esistere cioè nessun istante in cui un altro processo può trovare attivi +entrambi i nomi dello stesso file, o, in caso di sostituzione di un file +esistente, non trovare quest'ultimo prima che la sostituzione sia stata +eseguita. + +In ogni caso se \var{newpath} esiste e l'operazione fallisce per un qualche +motivo (come un crash del kernel), \func{rename} garantisce di lasciare +presente un'istanza di \var{newpath}. Tuttavia nella sovrascrittura potrà +esistere una finestra in cui sia \var{oldpath} che \var{newpath} fanno +riferimento allo stesso file. -Come si è accennato (in \secref{sec:file_perm_overview}) nei dodici bit del -campo \var{st\_mode} usati per il controllo di accesso oltre ai bit dei -permessi veri e propri, ci sono altri tre bit che vengono usati per indicare -alcune proprietà speciali dei file. Due di questi sono i bit detti -\acr{suid} (o \textit{set-user-ID bit}) e \acr{sgid} (o -\textit{set-group-ID bit}) che sono identificati dalle costanti -\macro{S\_ISUID} e \macro{S\_ISGID}. -Come spiegato in dettaglio in \secref{sec:proc_exec}, quando si lancia un -programma il comportamento normale del kernel è quello di settare -l'\textit{effective user id} e l'\textit{effective group id} del nuovo -processo all'\acr{uid} e al \acr{gid} del processo corrente, che normalmente -corrispondono dell'utente con cui si è entrati nel sistema. +\subsection{I link simbolici} +\label{sec:file_symlink} -Se però il file del programma\footnote{per motivi di sicurezza il kernel - ignora i bit \acr{suid} e \acr{sgid} per gli script eseguibili} (che -ovviamente deve essere eseguibile) ha il bit \acr{suid} settato, il kernel -assegnerà come \textit{effective user id} al nuovo processo l'uid del -proprietario del file al posto dell'uid del processo originario. Avere il bit -\acr{sgid} settato ha lo stesso effetto sull'\textit{effective group id} del -processo. - -I bit \textsl{suid} e \textsl{sgid} vengono usati per permettere agli utenti -normali di usare programmi che abbisognano di privilegi speciali; l'esempio -classico è il comando \cmd{passwd} che ha la necessità di modificare il file -delle password, quest'ultimo ovviamente può essere scritto solo -dall'amministratore, ma non è necessario chiamare l'amministratore per -cambiare la propria password. Infatti il comando \cmd{passwd} appartiene a -root ma ha il bit suid settato per cui quando viene lanciato da un utente -normale parte con i privilegi di root. +Come abbiamo visto in \secref{sec:file_link} la funzione \func{link} crea +riferimenti agli inodes, pertanto può funzionare soltanto per file che +risiedono sullo stesso filesystem e solo per un filesystem di tipo Unix. +Inoltre abbiamo visto che in Linux non è consentito eseguire un link diretto +ad una directory. -Chiaramente avere un processo che ha privilegi superiori a quelli che avrebbe -normalmente l'utente che lo ha lanciato comporta vari rischi, e questo tipo di -programmi devono essere scritti accuratamente per evitare che possano essere -usati per guadagnare privilegi non consentiti (torneremo sull'argomento in -\secref{sec:proc_perms}). - -La presenza dei bit \acr{suid} e \acr{sgid} su un file può essere -rilevata con il comando \cmd{ls -l}, in tal caso comparirà la lettera \cmd{s} -al posto della \cmd{x} in corrispondenza dei permessi di utente o gruppo. La -stessa lettera \cmd{s} può essere usata nel comando \cmd{chmod} per settare -questi bit. Infine questi bit possono essere controllati all'interno di -\var{st\_mode} con l'uso delle due costanti \macro{S\_ISUID} e -\macro{S\_IGID}, i cui valori sono riportati in -\tabref{tab:file_mode_flags}. +Per ovviare a queste limitazioni i sistemi Unix supportano un'altra forma di +link (i cosiddetti \textit{soft link} o \textit{symbolic link}), che sono, +come avviene in altri sistemi operativi, dei file speciali che contengono +semplicemente il riferimento ad un altro file (o directory). In questo modo è +possibile effettuare link anche attraverso filesystem diversi, a file posti in +filesystem che non supportano i link diretti, a delle directory, ed anche a +file che non esistono ancora. -Gli stessi bit vengono ad assumere in significato completamente diverso per le -directory, normalmente infatti Linux usa la convenzione di SVR4 per indicare -con questi bit l'uso della semantica BSD nella creazione di nuovi file (si -veda \secref{sec:file_ownership} per una spiegazione dettagliata al -proposito). +Il sistema funziona in quanto i link simbolici sono contrassegnati come tali +al kernel (analogamente a quanto avviene per le directory) per cui per alcune +funzioni di libreria (come \func{open} o \func{stat}) dare come parametro un +link simbolico comporta l'applicazione della funzione al file da esso +specificato. La funzione che permette di creare un nuovo link simbolico è +\func{symlink}; il suo prototipo è: +\begin{prototype}{unistd.h} + {int symlink(const char *oldpath, const char *newpath)} + Crea un nuovo link simbolico di nome \param{newpath} il cui contenuto è + \param{oldpath}. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso la variabile \var{errno} restituisce i valori: + \begin{errlist} + \item[\macro{EPERM}] il filesystem che contiene \param{newpath} non supporta + i link simbolici. + \item[\macro{ENOENT}] una componente di \param{newpath} non esiste o + \param{oldpath} è una stringa vuota. + \item[\macro{EEXIST}] esiste già un file \param{newpath}. + \item[\macro{EROFS}] \param{newpath} è su un filesystem montato in sola + lettura. + \end{errlist} + ed inoltre \macro{EFAULT}, \macro{EACCES}, \macro{ENAMETOOLONG}, + \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, \macro{ENOSPC} e + \macro{EIO}.} +\end{prototype} -Infine Linux utilizza il bit \acr{sgid} per una ulteriore estensione -mutuata da SVR4. Il caso in cui il file abbia il bit \acr{sgid} settato ma -non il corrispondente bit di esecuzione viene utilizzato per attivare per -quel file il \textit{mandatory locking} (argomento che affronteremo nei -dettagli in \secref{sec:xxx_mandatory_lock}). +Si tenga presente che la funzione non effettua nessun controllo sull'esistenza +di un file di nome \param{oldpath}, ma si limita ad inserire quella stringa +nel link simbolico. Pertanto un link simbolico può anche riferirsi ad un file +che non esiste: in questo caso si ha quello che viene chiamato un +\textit{dangling link}, letteralmente un \textsl{link ciondolante}. + +Come accennato i link simbolici sono risolti automaticamente dal kernel +all'invocazione delle varie system call; in \ntab\ si è riportato un elenco +dei comportamenti delle varie funzioni di libreria che operano sui file nei +confronti della risoluzione dei link simbolici, specificando quali seguono il +link simbolico e quali invece possono operare direttamente sul suo contenuto. +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|} + \hline + \textbf{Funzione} & \textbf{Segue il link} & \textbf{Non segue il link} \\ + \hline + \hline + \func{access} & $\bullet$ & \\ + \func{chdir} & $\bullet$ & \\ + \func{chmod} & $\bullet$ & \\ + \func{chown} & & $\bullet$ \\ + \func{creat} & $\bullet$ & \\ + \func{exec} & $\bullet$ & \\ + \func{lchown} & $\bullet$ & $\bullet$ \\ + \func{link} & & \\ + \func{lstat} & & $\bullet$ \\ + \func{mkdir} & $\bullet$ & \\ + \func{mkfifo} & $\bullet$ & \\ + \func{mknod} & $\bullet$ & \\ + \func{open} & $\bullet$ & \\ + \func{opendir} & $\bullet$ & \\ + \func{pathconf} & $\bullet$ & \\ + \func{readlink} & & $\bullet$ \\ + \func{remove} & & $\bullet$ \\ + \func{rename} & & $\bullet$ \\ + \func{stat} & $\bullet$ & \\ + \func{truncate} & $\bullet$ & \\ + \func{unlink} & & $\bullet$ \\ + \hline + \end{tabular} + \caption{Uso dei link simbolici da parte di alcune funzioni.} + \label{tab:file_symb_effect} +\end{table} +Si noti che non si è specificato il comportamento delle funzioni che operano +con i file descriptor, in quanto la risoluzione del link simbolico viene in +genere effettuata dalla funzione che restituisce il file descriptor +(normalmente la \func{open}) e tutte le operazioni seguenti fanno riferimento +solo a quest'ultimo. + +Dato che, come indicato in \tabref{tab:file_symb_effect}, funzioni come la +\func{open} seguono i link simbolici, occorrono funzioni apposite per accedere +alle informazioni del link invece che a quelle del file a cui esso fa +riferimento. Quando si vuole leggere il contenuto di un link simbolico si usa +la funzione \func{readlink}, il cui prototipo è: +\begin{prototype}{unistd.h} +{int readlink(const char *path, char *buff, size\_t size)} + Legge il contenuto del link simbolico indicato da \var{path} nel buffer + \var{buff} di dimensione \var{size}. + + \bodydesc{La funzione restituisce il numero di caratteri letti dentro + \var{buff} o -1 per un errore, nel qual caso la variabile + \var{errno} viene impostata a: + \begin{errlist} + \item[\macro{EINVAL}] \param{path} non è un link simbolico o \param{size} + non è positiva. + \end{errlist} + ed inoltre \macro{ENOTDIR}, \macro{ENAMETOOLONG}, \macro{ENOENT}, + \macro{EACCES}, \macro{ELOOP}, \macro{EIO}, \macro{EFAULT} e + \macro{ENOMEM}.} +\end{prototype} -\subsection{Il bit \textsl{sticky}} -\label{sec:file_sticky} +La funzione apre il link simbolico, ne legge il contenuto, lo scrive nel +buffer, e lo richiude. Si tenga presente che la funzione non termina la +stringa con un carattere nullo e la tronca alla dimensione specificata da +\var{size} per evitare di sovrascrivere oltre le dimensioni del buffer. -L'ultimo dei bit rimanenti, identificato dalla costante \macro{S\_ISVTX}, è in -parte un rimasuglio delle origini dei sistemi unix. A quell'epoca infatti la -memoria virtuale e l'accesso ai files erano molto meno sofisticati e per -ottenere la massima velocità possibile per i programmi usati più comunemente -si poteva settare questo bit. -L'effetto di questo bit era che il segmento di testo del programma (si veda -\secref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la -prima volta che questo veniva lanciato, e vi permaneva fino al riavvio della -macchina (da questo il nome di \textsl{sticky bit}); essendo la swap un file -continuo indicizzato direttamente in questo modo si poteva risparmiare in -tempo di caricamento rispetto alla ricerca del file su disco. Lo -\textsl{sticky bit} è indicato usando la lettera \cmd{t} al posto della -\cmd{x} nei permessi per gli altri. +\begin{figure}[htb] + \centering + \includegraphics[width=7cm]{img/link_loop} + \caption{Esempio di loop nel filesystem creato con un link simbolico.} + \label{fig:file_link_loop} +\end{figure} -Ovviamente per evitare che gli utenti potessero intasare la swap solo -l'amministratore era in grado di settare questo bit, che venne chiamato anche -con il nome di \textit{saved text bit}, da cui deriva quello della costante. -Le attuali implementazioni di memoria virtuale e filesystem rendono -sostanzialmente inutile questo procedimento. +Un caso comune che si può avere con i link simbolici è la creazione dei +cosiddetti \textit{loop}. La situazione è illustrata in \curfig, che riporta +la struttura della directory \file{/boot}. Come si vede si è creato al suo +interno un link simbolico che punta di nuovo a \file{/boot}.\footnote{Questo + tipo di loop è stato effettuato per poter permettere a \cmd{grub} (un + bootloader in grado di leggere direttamente da vari filesystem il file da + lanciare come sistema operativo) di vedere i file in questa directory con lo + stesso path con cui verrebbero visti dal sistema operativo, anche se essi si + trovano, come è solito, su una partizione separata (e che \cmd{grub} + vedrebbe come radice).} -Benché ormai non venga più utilizzato per i file, lo \textsl{sticky bit} ha -assunto un uso corrente per le directory\footnote{lo \textsl{sticky bit} per - le directory è una estensione non definita nello standard POSIX, Linux però - la supporta, così come BSD e SVR4}, in questo caso se il bit è settato un -file potrà essere rimosso dalla directory soltanto se l'utente ha il permesso -di scrittura ed inoltre è vera una delle seguenti condizioni: -\begin{itemize} -\item l'utente è proprietario del file -\item l'utente è proprietario della directory -\item l'utente è l'amministratore -\end{itemize} -un classico esempio di directory che ha questo bit settato è \file{/tmp}, i -permessi infatti di solito sono settati come: +Questo può causare problemi per tutti quei programmi che effettuano la +scansione di una directory senza tener conto dei link simbolici, ad esempio se +lanciassimo un comando del tipo \code{grep -r linux *}, il loop nella +directory porterebbe il comando ad esaminare \file{/boot}, \file{/boot/boot}, +\file{/boot/boot/boot} e così via. + +Per questo motivo il kernel e le librerie prevedono che nella risoluzione di +un pathname possano essere seguiti un numero limitato di link simbolici, il +cui valore limite è specificato dalla costante \macro{MAXSYMLINKS}. Qualora +questo limite venga superato viene generato un errore ed \var{errno} viene +impostata al valore \macro{ELOOP}. + +Un punto da tenere sempre presente è che, come abbiamo accennato, un link +simbolico può fare riferimento anche ad un file che non esiste; ad esempio +possiamo creare un file temporaneo nella nostra directory con un link del +tipo: \begin{verbatim} -$ ls -ld /tmp -drwxrwxrwt 6 root root 1024 Aug 10 01:03 /tmp +$ ln -s /tmp/tmp_file temporaneo \end{verbatim}%$ -in questo modo chiunque può leggere, scrivere ed eseguire i file temporanei -ivi memorizzati, sia crearne di nuovi, ma solo l'utente che ha creato un file -nella directory potrà cancellarlo o rinominarlo, così si può evitare che un -utente possa, più o meno consapevolmente, cancellare i file degli altri. - - -\subsection{La titolarità di nuovi file e directory} -\label{sec:file_ownership} - -Vedremo in \secref{sec:file_base_func} come creare nuovi file, ma se è -possibile specificare in sede di creazione quali permessi applicare ad un -file, non si può indicare a quale utente e gruppo esso deve appartenere. Lo -stesso problema di presenta per la creazione di nuove directory (procedimento -descritto in \secref{sec:file_dir_creat_rem}). - -Lo standard POSIX prescrive che l'uid del nuovo file corrisponda -all'\textit{effective user id} del processo che lo crea; per il \acr{gid} -invece prevede due diverse possibilità: -\begin{itemize} -\item il \acr{gid} del file corrisponde all'\textit{effective group id} del - processo. -\item il \acr{gid} del file corrisponde al gid della directory in cui esso è - creato. -\end{itemize} -in genere BSD usa sempre la seconda possibilità, che viene per questo chiamata -semantica BSD. Linux invece segue quella che viene chiamata semantica SVR4; di -norma cioè il nuovo file viene creato, seguendo la prima opzione, con il -\acr{gid} del processo, se però la directory in cui viene creato il file ha il -bit \acr{sgid} settato allora viene usata la seconda opzione.. - -Usare la semantica BSD ha il vantaggio che il \acr{gid} viene sempre -automaticamente propagato, restando coerente a quello della directory di -partenza, in tutte le sottodirectory. La semantica SVR4 offre una maggiore -possibilità di scelta, ma per ottenere lo stesso risultato necessita che per -le nuove directory venga anche propagato anche il bit \acr{sgid}. Questo è -comunque il comportamento di default di \func{mkdir}, ed é in questo modo ad -esempio che Debian assicura che le sottodirectory create nelle home di un -utente restino sempre con il \acr{gid} del gruppo primario dello stesso. - - -\subsection{La funzione \texttt{access}} -\label{sec:file_access} +anche se \file{/tmp/tmp\_file} non esiste. Questo può generare confusione, in +quanto aprendo in scrittura \file{temporaneo} verrà creato +\file{/tmp/tmp\_file} e scritto; ma accedendo in sola lettura a +\file{temporaneo}, ad esempio con \cmd{cat}, otterremmo: +\begin{verbatim} +$ cat temporaneo +cat: temporaneo: No such file or directory +\end{verbatim}%$ +con un errore che può sembrare sbagliato, dato che un'ispezione con \cmd{ls} +ci mostrerebbe invece l'esistenza di \file{temporaneo}. -Come detto in \secref{sec:file_access_control} il controllo di accesso ad -un file viene fatto usando \textit{effective user id} e \textit{effective - group id} del processo, ma ci sono casi in cui si può voler effettuare il -controllo usando il \textit{real user id} e il \textit{real group id} (cioè -l'uid dell'utente che ha lanciato il programma, che, come accennato in -\secref{sec:file_suid_sgid} e spiegato in \secref{sec:proc_perms} non è -detto sia uguale all'\textit{effective user id}). Per far questo si può usare -la funzione \func{access}, il cui prototipo è: -\begin{prototype}{unistd.h} -{int access(const char *pathname, int mode)} +\subsection{La creazione e la cancellazione delle directory} +\label{sec:file_dir_creat_rem} - La funzione verifica i permessi di accesso, indicati da \var{mode}, per il - file indicato da \var{pathname}. +Per creare e cancellare delle directory si usano le due funzioni (omonime +degli analoghi comandi di shell) \func{mkdir} e \func{rmdir}. Per poter +accedere ai tipi usati da queste funzioni si deve includere il file +\file{sys/types.h}, il prototipo della prima è: +\begin{prototype}{sys/stat.h} + {int mkdir(const char *dirname, mode\_t mode)} + Crea una nuova directory vuota con il nome indicato da \var{dirname}, + assegnandole i permessi indicati da \var{mode}. Il nome può essere indicato + con il pathname assoluto o relativo. - La funzione ritorna 0 se l'accesso è consentito, -1 altrimenti; in - quest'ultimo caso la variabile \texttt{errno} viene settata secondo i codici - di errore: \macro{EACCES}, \macro{EROFS}, \macro{EFAULT}, \macro{EINVAL}, - \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOTDIR}, \macro{ELOOP}, - \macro{EIO}. + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} assumerà i valori: + \begin{errlist} + \item[\macro{EEXIST}] Un file (o una directory) con quel nome esiste di già. + \item[\macro{EACCESS}] + Non c'è il permesso di scrittura per la directory in cui si vuole inserire + la nuova directory. + \item[\macro{EMLINK}] La directory in cui si vuole creare la nuova directory + contiene troppi file. Sotto Linux questo normalmente non avviene perché il + filesystem standard consente la creazione di un numero di file maggiore di + quelli che possono essere contenuti nel disco, ma potendo avere a che + fare anche con filesystem di altri sistemi questo errore può presentarsi. + \item[\macro{ENOSPC}] Non c'è abbastanza spazio sul file system per creare + la nuova directory o si è esaurita la quota disco dell'utente. + \end{errlist} + ed inoltre anche \macro{EPERM}, \macro{EFAULT}, \macro{ENAMETOOLONG}, + \macro{ENOENT}, \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, + \macro{EROFS}.} \end{prototype} +La funzione crea una nuova directory vuota (che contiene solo le due voci +standard \file{.} e \file{..}). I permessi di accesso (vedi la trattazione in +\secref{sec:file_access_control}) specificati da \var{mode} (i cui possibili +valori sono riportati in \tabref{tab:file_permission_const}) sono modificati +dalla maschera di creazione dei file (si veda \secref{sec:file_umask}). La +titolarità della nuova directory è impostata secondo quanto riportato in +\secref{sec:file_ownership}. + +La seconda funzione serve ad eliminare una directory già vuota (la directory +deve cioè contenere soltanto le due voci standard \file{.} e \file{..}); il +suo prototipo è: +\begin{prototype}{sys/stat.h}{int rmdir(const char *dirname)} + Cancella la directory \var{dirname}, che deve essere vuota. Il nome può + essere indicato con il pathname assoluto o relativo. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} assumerà i valori: + \begin{errlist} + \item[\macro{EPERM}] Il filesystem non supporta la cancellazione di + directory, oppure la directory che contiene \var{dirname} ha lo sticky bit + impostato e l'userid effettivo del processo non corrisponde al + proprietario della directory. + \item[\macro{EACCESS}] Non c'è il permesso di scrittura per la directory che + contiene la directory che si vuole cancellare, o non c'è il permesso di + attraversare (esecuzione) una delle directory specificate in + \var{dirname}. + \item[\macro{EBUSY}] La directory specificata è la directory di lavoro o la + radice di qualche processo. + \item[\macro{ENOTEMPTY}] La directory non è vuota. + \end{errlist} + ed inoltre anche \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT}, + \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, \macro{EROFS}.} +\end{prototype} -I valori possibili per il parametro \var{mode} sono esprimibili come -combinazione delle costanti numeriche riportate in \ntab\ (attraverso un OR -binario). I primi tre valori implicano anche la verifica dell'esistenza del -file, se si vuole verificare solo quest'ultima si può usare \macro{F\_OK}, o -anche direttamente \func{stat}. In caso \var{pathname} si riferisca ad un link -simbolico il controllo è fatto sul file a cui esso fa riferimento. - -La funzione controlla solo i bit dei permessi di accesso, si ricordi che il -fatto che una directory abbia permesso di scrittura non significa che ci si -possa scrivere come in un file, e il fatto che un file abbia permesso di -esecuzione non comporta che contenga un programma eseguibile. La funzione -ritorna zero solo se tutte i permessi controllati sono disponibili, in caso -contrario (o di errore) ritorna -1. - -\begin{table}[htb] - \centering - \footnotesize - \begin{tabular}{|c|l|} - \hline - \textbf{\var{mode}} & \textbf{Significato} \\ - \hline - \hline - \macro{R\_OK} & verifica il permesso di lettura \\ - \macro{W\_OK} & verifica il permesso di scritture \\ - \macro{X\_OK} & verifica il permesso di esecuzione \\ - \macro{F\_OK} & verifica l'esistenza del file \\ - \hline - \end{tabular} - \caption{Valori possibile per il parametro \var{mode} della funzione - \func{access}} - \label{tab:file_access_mode_val} -\end{table} - -Un esempio tipico per l'uso di questa funzione è quello di un processo che sta -eseguendo un programma coi privilegi di un altro utente (attraverso l'uso del -suid bit) che vuole controllare se l'utente originale ha i permessi per -accedere ad un certo file. +La modalità con cui avviene la cancellazione è analoga a quella di +\func{unlink}: fintanto che il numero di link all'inode della directory non +diventa nullo e nessun processo ha la directory aperta lo spazio occupato su +disco non viene rilasciato. Se un processo ha la directory aperta la funzione +rimuove il link all'inode e nel caso sia l'ultimo, pure le voci standard +\file{.} e \file{..}, a questo punto il kernel non consentirà di creare più +nuovi file nella directory. -\subsection{Le funzioni \texttt{chmod} e \texttt{fchmod}} -\label{sec:file_chmod} +\subsection{La creazione di file speciali} +\label{sec:file_mknod} -Per cambiare i permessi di un file il sistema mette ad disposizione due -funzioni, che operano rispettivamente su un filename e su un file descriptor, -i cui prototipi sono: +Finora abbiamo parlato esclusivamente di file, directory e link simbolici; in +\secref{sec:file_file_types} abbiamo visto però che il sistema prevede pure +degli altri tipi di file speciali, come i file di dispositivo e le fifo (i +socket sono un caso a parte, che vedremo in \capref{cha:socket_intro}). +La manipolazione delle caratteristiche di questi file e la loro cancellazione +può essere effettuata con le stesse funzioni che operano sui file regolari; ma +quando li si devono creare sono necessarie delle funzioni apposite. La prima +di queste funzioni è \func{mknod}, il suo prototipo è: \begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/stat.h} - - \funcdecl{int chmod(const char *path, mode\_t mode)} Cambia i permessi del - file indicato da \var{path} al valore indicato da \var{mode}. - - \funcdecl{int fchmod(int fd, mode\_t mode)} Analoga alla precedente, ma usa - il file descriptor \var{fd} per indicare il file. + \headdecl{sys/types.h} + \headdecl{sys/stat.h} + \headdecl{fnctl.h} + \headdecl{unistd.h} + \funcdecl{int mknod(const char *pathname, mode\_t mode, dev\_t dev)} Crea un + inode, si usa per creare i file speciali. - Le funzioni restituiscono zero in caso di successo e -1 per un errore, in - caso di errore \texttt{errno} può assumere i valori: + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} assumerà i valori: \begin{errlist} - \item \macro{EPERM} L'\textit{effective user id} non corrisponde a quello - del proprietario del file o non è zero. + \item[\macro{EPERM}] Non si hanno privilegi sufficienti a creare l'inode, o + il filesystem su cui si è cercato di creare \func{pathname} non supporta + l'operazione. + \item[\macro{EINVAL}] Il valore di \var{mode} non indica un file, una fifo o + un dipositivo. + \item[\macro{EEXIST}] \param{pathname} esiste già o è un link simbolico. \end{errlist} - ed inoltre \macro{EROFS} e \macro{EIO}; \func{chmod} restituisce anche - \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOMEM}, - \macro{ENOTDIR}, \macro{EACCES}, \macro{ELOOP}; \func{fchmod} anche - \macro{EBADF}. + ed inoltre anche \macro{EFAULT}, \macro{EACCESS}, \macro{ENAMETOOLONG}, + \macro{ENOENT}, \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, + \macro{ENOSPC}, \macro{EROFS}.} \end{functions} -I valori possibili per \var{mode} sono indicati in \ntab. I valori possono -esser combinati con l'OR binario delle relative macro, o specificati -direttamente, come per l'analogo comando di shell, con il valore ottale. Ad -esempio i permessi standard assegnati ai nuovi file (lettura e scrittura per -il proprietario, sola lettura per il gruppo e gli altri) sono corrispondenti -al valore ottale $0644$, un programma invece avrebbe anche il bit di -esecuzione attivo, con un valore di $0755$, se si volesse attivare il bit suid -il valore da fornire sarebbe $4755$. - -\begin{table}[!htb] - \centering - \footnotesize - \begin{tabular}[c]{|c|c|l|} - \hline - \textbf{\var{mode}} & \textbf{Valore} & \textbf{Significato} \\ - \hline - \hline - \macro{S\_ISUID} & 04000 & set user ID \\ - \macro{S\_ISGID} & 02000 & set group ID \\ - \macro{S\_ISVTX} & 01000 & sticky bit \\ - \hline - \macro{S\_IRWXU} & 00700 & l'utente ha tutti i permessi \\ - \macro{S\_IRUSR} & 00400 & l'utente ha il permesso di lettura \\ - \macro{S\_IWUSR} & 00200 & l'utente ha il permesso di scrittura \\ - \macro{S\_IXUSR} & 00100 & l'utente ha il permesso di esecuzione \\ - \hline - \macro{S\_IRWXG} & 00070 & il gruppo ha tutti i permessi \\ - \macro{S\_IRGRP} & 00040 & il gruppo ha il permesso di lettura \\ - \macro{S\_IWGRP} & 00020 & il gruppo ha il permesso di scrittura \\ - \macro{S\_IXGRP} & 00010 & il gruppo ha il permesso di esecuzione \\ - \hline - \macro{S\_IRWXO} & 00007 & gli altri hanno tutti i permessi \\ - \macro{S\_IROTH} & 00004 & gli altri hanno il permesso di lettura \\ - \macro{S\_IWOTH} & 00002 & gli altri hanno il permesso di scrittura \\ - \macro{S\_IXOTH} & 00001 & gli altri hanno il permesso di esecuzione \\ - \hline - \end{tabular} - \caption{I valori delle costanti usate per indicare i permessi dei file.} - \label{tab:file_permission_const} -\end{table} - -Il cambiamento dei permessi di un file attraverso queste funzioni ha comunque -alcune limitazioni, provviste per motivi di sicurezza. Questo significa che -anche se si è proprietari del file non tutte le operazioni sono permesse, in -particolare: -\begin{itemize} -\item siccome solo l'amministratore può settare lo \textit{sticky bit} se se - l'\textit{effective user id} del processo non è zero esso viene - automaticamente cancellato (senza notifica di errore) qualora sia stato - indicato in \var{mode}. -\item per via della semantica SVR4 nella creazione dei nuovi file, si può - avere il caso in cui il file creato da un processo è assegnato a un gruppo - per il quale il processo non ha privilegi. Per evitare che si possa - assegnare il bit \acr{sgid} ad un file appartenente a un gruppo per cui - non si hanno diritti, questo viene automaticamente cancellato (senza - notifica di errore) da \var{mode} qualora il gruppo del file non corrisponda - a quelli associati al processo (la cosa non avviene quando - l'\textit{effective user id} del processo è zero). -\end{itemize} - -Per alcuni filesystem\footnote{il filesystem \textsl{ext2} supporta questa - caratteristica, che è mutuata da BSD.} è inoltre prevista una ulteriore -misura di sicurezza, volta ad scongiurare l'abuso dei bit \acr{suid} e -\acr{sgid}; essa consiste nel cancellare automaticamente questi bit qualora un -processo che non appartenga all'amministratore scriva su un file. In questo -modo anche se un utente malizioso scopre un file \acr{suid} su cui può -scrivere, un eventuale modifica comporterà la perdita di ogni ulteriore -privilegio. - +La funzione permette di creare un file speciale, ma si può usare anche per +creare file regolari e fifo; l'argomento \param{mode} specifica il tipo di +file che si vuole creare ed i relativi permessi, secondo i valori riportati in +\tabref{tab:file_mode_flags}, che vanno combinati con un OR binario. I +permessi sono comunque modificati nella maniera usuale dal valore di +\var{umask} (si veda \secref{sec:file_umask}). + +Per il tipo di file può essere specificato solo uno fra: \macro{S\_IFREG} per +un file regolare (che sarà creato vuoto), \macro{S\_IFBLK} per un device a +blocchi, \macro{S\_IFCHR} per un device a caratteri e \macro{S\_IFIFO} per una +fifo. Un valore diverso comporterà l'errore \macro{EINVAL}. Qualora si sia +specificato in \param{mode} un file di dispositivo, il valore di \param{dev} +viene usato per indicare a quale dispositivo si fa riferimento. + +Solo l'amministratore può creare un file di dispositivo o un file regolare +usando questa funzione; ma in Linux\footnote{la funzione non è prevista dallo + standard POSIX, e deriva da SVr4, con appunto questa differenza e diversi + codici di errore.} l'uso per la creazione di una fifo è consentito anche +agli utenti normali. + +I nuovi inode creati con \func{mknod} apparterranno al proprietario e al +gruppo del processo che li ha creati, a meno che non si sia attivato il bit +\acr{sgid} per la directory o sia stata attivata la semantica BSD per il +filesystem (si veda \secref{sec:file_ownership}) in cui si va a creare +l'inode. + +Per creare una fifo (un file speciale, su cui torneremo in dettaglio in +\secref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione +\func{mkfifo}, il cui prototipo è: +\begin{functions} + \headdecl{sys/types.h} \headdecl{sys/stat.h} + + \funcdecl{int mkfifo(const char *pathname, mode\_t mode)} Crea una fifo. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} assumerà i valori \macro{EACCESS}, + \macro{EEXIST}, \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOSPC}, + \macro{ENOTDIR} e \macro{EROFS}.} +\end{functions} +\noindent come per \func{mknod} il file \param{pathname} non deve esistere +(neanche come link simbolico); al solito i permessi specificati da +\param{mode} vengono modificati dal valore di \var{umask}. -\subsection{La funzione \texttt{umask}} -\label{sec:file_umask} -Oltre che dai valori indicati in sede di creazione, i permessi assegnati ai -nuovi file sono controllati anche da una maschera di bit settata con la -funzione \func{umask}, il cui prototipo è: -\begin{prototype}{stat.h} -{mode\_t umask(mode\_t mask)} +\subsection{Accesso alle directory} +\label{sec:file_dir_read} - Setta la maschera dei permessi dei bit al valore specificato da \var{mask} - (di cui vengono presi solo i 9 bit meno significativi). - - La funzione ritorna il precedente valore della maschera. È una delle poche - funzioni che non restituisce codici di errore. -\end{prototype} +Benché le directory siano oggetti del filesystem come tutti gli altri non ha +ovviamente senso aprirle come fossero dei file di dati. Può però essere utile +poterne leggere il contenuto ad esempio per fare la lista dei file che esse +contengono o ricerche sui medesimi. Solo il kernel può scrivere direttamente +in una directory (onde evitare inconsistenze all'interno del filesystem), i +processi devono creare i file usando le apposite funzioni. -Questa maschera è una caratteristica di ogni processo e viene utilizzata per -impedire che alcuni permessi possano essere assegnati ai nuovi file in sede di -creazione, i bit indicati nella maschera vengono infatti esclusi quando un -nuovo file viene creato. - -In genere questa maschera serve per impostare un default che escluda alcuni -permessi (usualmente quello di scrittura per il gruppo e gli altri, -corrispondente ad un valore di $022$). Essa è utile perché le routine -dell'interfaccia ANSI C degli stream non prevedono l'esistenza dei permessi, e -pertanto tutti i nuovi file vengono sempre creati con un default di $666$ -(cioè permessi di lettura e scrittura per tutti, si veda -\tabref{tab:file_permission_const} per un confronto); in questo modo è -possibile cancellare automaticamente i permessi non voluti, senza doverlo fare -esplicitamente. +Per accedere al contenuto delle directory si usano i cosiddetti +\textit{directory streams} (chiamati così per l'analogia con i file stream di +\capref{cha:files_std_interface}); la funzione \func{opendir} apre uno di +questi stream e la funzione \func{readdir} legge il contenuto della directory, +i cui elementi sono le \textit{directory entry} (da distinguersi da quelle +della cache di cui parlavamo in \secref{sec:file_vfs}) in un'opportuna +struttura \var{struct dirent}. -In genere il valore di \func{umask} viene stabilito una volta per tutte al -login a $022$, e di norma gli utenti non hanno motivi per modificarlo. Se però -si vuole che un processo possa creare un file che chiunque possa leggere -allora occorrerà cambiare il valore di \func{umask}. +(NdA Il resto va scritto!!! É noioso e lo farò più avanti). -\subsection{Le funzioni \texttt{chown}, \texttt{fchown} e \texttt{lchown}} -\label{sec:file_chown} -Come per i permessi, il sistema fornisce anche delle funzioni che permettano -di cambiare utente e gruppo cui il file appartiene; le funzioni in questione -sono tre e i loro prototipi sono i seguenti: +\subsection{La directory di lavoro} +\label{sec:file_work_dir} -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/stat.h} +A ciascun processo è associato ad una directory nel filesystem che è chiamata +directory corrente o directory di lavoro (\textit{current working directory}) +che è quella a cui si fa riferimento quando un filename è espresso in forma +relativa, dove il ``relativa'' fa riferimento appunto a questa directory. + +Quando un utente effettua il login questa directory viene impostata alla +\textit{home directory} del suo account. Il comando \cmd{cd} della shell +consente di cambiarla a piacere, spostandosi da una directory ad un'altra, il +comando \cmd{pwd} la stampa sul terminale. Siccome la directory corrente +resta la stessa quando viene creato un processo figlio (vedi +\secref{sec:proc_fork}), la directory corrente della shell diventa anche la +directory corrente di qualunque comando da essa lanciato. + +In genere il kernel tiene traccia per ciascun processo dell'inode della +directory di lavoro corrente, per ottenere il pathname occorre usare una +apposita funzione di libreria, \func{getcwd}, il cui prototipo è: +\begin{prototype}{unistd.h}{char *getcwd(char *buffer, size\_t size)} + Restituisce il filename completo della directory di lavoro corrente nella + stringa puntata da \var{buffer}, che deve essere precedentemente + allocata, per una dimensione massima di \var{size}. - \funcdecl{int chown(const char *path, uid\_t owner, gid\_t group)} - \funcdecl{int fchown(int fd, uid\_t owner, gid\_t group)} - \funcdecl{int lchown(const char *path, uid\_t owner, gid\_t group)} + \bodydesc{La funzione restituisce il puntatore \var{buffer} se riesce, + \macro{NULL} se fallisce, in quest'ultimo caso la variabile + \var{errno} è impostata con i seguenti codici di errore: + \begin{errlist} + \item[\macro{EINVAL}] L'argomento \var{size} è zero e \var{buffer} non + è nullo. + \item[\macro{ERANGE}] L'argomento \var{size} è più piccolo della + lunghezza del pathname. + \item[\macro{EACCESS}] Manca il permesso di lettura o di ricerca su uno dei + componenti del pathname (cioè su una delle directory superiori alla + corrente). + \end{errlist}} +\end{prototype} - Le funzioni cambiano utente e gruppo di appartenenza di un file ai valori - specificati dalle variabili \var{owner} e \var{group}. +Il buffer deve essere sufficientemente lungo da poter contenere il pathname +completo più lo zero di terminazione della stringa. Qualora esso ecceda le +dimensioni specificate con \var{size} la funzione restituisce un errore. Si +può anche specificare un puntatore nullo come \var{buffer},\footnote{questa è + un'estensione allo standard POSIX.1, supportata da Linux.} nel qual caso la +stringa sarà allocata automaticamente per una dimensione pari a \var{size} +qualora questa sia diversa da zero, o della lunghezza esatta del pathname +altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una +volta cessato il suo utilizzo. + +Di questa funzione esiste una versione \code{char *getwd(char *buffer)} +fatta per compatibilità all'indietro con BSD, che non consente di specificare +la dimensione del buffer; esso deve essere allocato in precedenza ed avere una +dimensione superiore a \macro{PATH\_MAX} (di solito 256 byte, vedi +\secref{sec:sys_limits}); il problema è che in Linux non esiste una dimensione +superiore per un pathname, per cui non è detto che il buffer sia sufficiente a +contenere il nome del file, e questa è la ragione principale per cui questa +funzione è deprecata. - Le funzioni restituiscono zero in caso di successo e -1 per un errore, in - caso di errore \texttt{errno} viene settato ai valori: +Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è +sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola +differenza che essa ritorna il valore della variabile di ambiente \macro{PWD}, +che essendo costruita dalla shell può contenere un pathname comprendente anche +dei link simbolici. Usando \func{getcwd} infatti, essendo il pathname ricavato +risalendo all'indietro l'albero della directory, si perderebbe traccia di ogni +passaggio attraverso eventuali link simbolici. + +Per cambiare la directory di lavoro corrente si può usare la funzione +\func{chdir} (equivalente del comando di shell \cmd{cd}) il cui nome sta +appunto per \textit{change directory}, il suo prototipo è: +\begin{prototype}{unistd.h}{int chdir(const char *pathname)} + Cambia la directory di lavoro corrente in \param{pathname}. + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 per un errore, + nel qual caso \var{errno} viene impostata a: \begin{errlist} - \item \macro{EPERM} L'\textit{effective user id} non corrisponde a quello - del proprietario del file o non è zero, o utente e gruppo non sono validi + \item[\macro{ENOTDIR}] Non si è specificata una directory. + \item[\macro{EACCESS}] Manca il permesso di ricerca su uno dei componenti di + \param{path}. \end{errlist} - Oltre a questi entrambe restituiscono gli errori \macro{EROFS} e - \macro{EIO}; \func{chown} restituisce anche \macro{EFAULT}, - \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOMEM}, \macro{ENOTDIR}, - \macro{EACCES}, \macro{ELOOP}; \func{fchown} anche \macro{EBADF}. -\end{functions} + ed inoltre \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT}, + \macro{ENOMEM}, \macro{ELOOP} e \macro{EIO}.} +\end{prototype} +\noindent ed ovviamente \param{pathname} deve indicare una directory per la +quale si hanno i permessi di accesso. + +Dato che anche le directory sono file, è possibile riferirsi ad esse anche +tramite il file descriptor, e non solo tramite il filename, per fare questo si +usa \func{fchdir}, il cui prototipo è: +\begin{prototype}{unistd.h}{int fchdir(int fd)} + Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del + pathname. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, in caso di errore \var{errno} viene impostata ai valori + \macro{EBADF} o \macro{EACCES}.} +\end{prototype} +\noindent anche in questo caso \param{fd} deve essere un file descriptor +valido che fa riferimento ad una directory. Inoltre l'unico errore di accesso +possibile (tutti gli altri sarebbero occorsi all'apertura di \func{fd}), è +quello in cui il processo non ha il permesso di accesso alla directory +specificata da \param{fd}. -In Linux soltanto l'amministratore può cambiare il proprietario di un file, -seguendo la semantica di BSD che non consente agli utenti di assegnare i loro -file ad altri (per evitare eventuali aggiramenti delle quote). -L'amministratore può cambiare il gruppo di un file, il proprietario può -cambiare il gruppo dei file che gli appartengono solo se il nuovo gruppo è il -suo gruppo primario o uno dei gruppi a cui appartiene. -La funzione \func{chown} segue i link simbolici, per operare direttamente su -in link simbolico si deve usare la funzione \func{lchown}\footnote{fino alla - versione 2.1.81 in Linux \func{chown} non seguiva i link simbolici, da - allora questo comportamento è stato assegnato alla funzione \func{lchown}, - introdotta per l'occasione, ed è stata creata una nuova system call per - \func{chown} che seguisse i link simbolici}. La funzione \func{fchown} opera -su un file aperto, essa è mutuata da BSD, ma non è nello standard POSIX. -Un'altra estensione rispetto allo standard POSIX è che specificando -1 come -valore per \var{owner} e \var{group} i valori restano immutati. -Quando queste funzioni sono chiamate con successo da un processo senza i -privilegi di root entrambi i bit \acr{suid} e \acr{sgid} vengono -cancellati. Questo non avviene per il bit \acr{sgid} nel caso in cui esso -sia usato (in assenza del corrispondente permesso di esecuzione) per indicare -che per il file è attivo il \textit{mandatory locking}. +\subsection{I file temporanei} +\label{sec:file_temp_file} -%La struttura fondamentale che contiene i dati essenziali relativi ai file è il -%cosiddetto \textit{inode}; questo conterrà informazioni come il -%tipo di file (file di dispositivo, directory, file di dati, per un elenco -%completo vedi \ntab), i permessi (vedi \secref{sec:file_perms}), le date (vedi -%\secref{sec:file_times}). +In molte occasioni è utile poter creare dei file temporanei; benché la cosa +sembri semplice in realtà il problema è più sottile di quanto non appaia a +prima vista. Infatti anche se sembrerebbe banale generare un nome a caso e +creare il file dopo aver controllato che questo non esista, nel momento fra il +controllo e la creazione si ha giusto lo spazio per una \textit{race + condition} (si ricordi quanto visto in \secref{sec:proc_race_cond}). + +Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei, +di cui si abbia certezza di unicità (al momento della generazione); la prima +di queste funzioni è \func{tmpnam} il cui prototipo è: +\begin{prototype}{stdio.h}{char *tmpnam(char *string)} + Restituisce il puntatore ad una stringa contente un nome di file valido e + non esistente al momento dell'invocazione. + \bodydesc{La funzione ritorna il puntatore alla stringa con il nome o + \macro{NULL} in caso di fallimento. Non sono definiti errori.} +\end{prototype} +\noindent se si è passato un puntatore \param{string} non nullo questo deve +essere di dimensione \macro{L\_tmpnam} (costante definita in \file{stdio.h}, +come \macro{P\_tmpdir} e \macro{TMP\_MAX}) ed il nome generato vi verrà +copiato automaticamente; altrimenti il nome sarà generato in un buffer statico +interno che verrà sovrascritto ad una chiamata successiva. Successive +invocazioni della funzione continueranno a restituire nomi unici fino ad un +massimo di \macro{TMP\_MAX} volte. Al nome viene automaticamente aggiunto come +prefisso la directory specificata da \macro{P\_tmpdir}. + +Di questa funzione esiste una versione rientrante, \func{tmpnam\_r}, che non +fa nulla quando si passa \macro{NULL} come parametro. Una funzione simile, +\func{tempnam}, permette di specificare un prefisso per il file +esplicitamente, il suo prototipo è: +\begin{prototype}{stdio.h}{char *tempnam(const char *dir, const char *pfx)} + Restituisce il puntatore ad una stringa contente un nome di file valido e + non esistente al momento dell'invocazione. + + \bodydesc{La funzione ritorna il puntatore alla stringa con il nome o + \macro{NULL} in caso di fallimento, \var{errno} viene impostata a + \macro{ENOMEM} qualora fallisca l'allocazione della stringa.} +\end{prototype} + +La funzione alloca con \code{malloc} la stringa in cui restituisce il nome, +per cui è sempre rientrante, occorre però ricordarsi di disallocare il +puntatore che restituisce. L'argomento \param{pfx} specifica un prefisso di +massimo 5 caratteri per il nome provvisorio. La funzione assegna come +directory per il file temporaneo (verificando che esista e sia accessibili), +la prima valida delle seguenti: +\begin{itemize*} +\item La variabile di ambiente \macro{TMPNAME} (non ha effetto se non è + definita o se il programma chiamante è \acr{suid} o \acr{sgid}, vedi + \secref{sec:file_suid_sgid}). +\item il valore dell'argomento \param{dir} (se diverso da \macro{NULL}). +\item Il valore della costante \macro{P\_tmpdir}. +\item la directory \file{/tmp}. +\end{itemize*} + +In ogni caso, anche se la generazione del nome è casuale, ed è molto difficile +ottenere un nome duplicato, nulla assicura che un altro processo non possa +avere creato, fra l'ottenimento del nome e l'apertura del file, un altro file +con lo stesso nome; per questo motivo quando si usa il nome ottenuto da una di +queste funzioni occorre sempre aprire il nuovo file in modalità di esclusione +(cioè con l'opzione \macro{O\_EXCL} per i file descriptor o con il flag +\code{x} per gli stream) che fa fallire l'apertura in caso il file sia già +esistente. + +Per evitare di dovere effettuare a mano tutti questi controlli, lo standard +POSIX definisce la funzione \func{tempfile}, il cui prototipo è: +\begin{prototype}{stdio.h}{FILE *tmpfile (void)} + Restituisce un file temporaneo aperto in lettura/scrittura. + + \bodydesc{La funzione ritorna il puntatore allo stream associato al file + temporaneo in caso di successo e \macro{NULL} in caso di errore, nel qual + caso \var{errno} viene impostata a + \begin{errlist} + \item[\macro{EINTR}] La funzione è stata interrotta da un segnale. + \item[\macro{EEXIST}] Non è stato possibile generare un nome univoco. + \end{errlist} + ed inoltre \macro{EFAULT}, \macro{EMFILE}, \macro{ENFILE}, \macro{ENOSPC}, + \macro{EROFS} e \macro{EACCESS}.} +\end{prototype} +\noindent essa restituisce direttamente uno stream già aperto (in modalità +\code{r+b}, si veda \secref{sec:file_fopen}) e pronto per l'uso, che viene +automaticamente cancellato alla sua chiusura o all'uscita dal programma. Lo +standard non specifica in quale directory verrà aperto il file, ma le +\acr{glibc} prima tentano con \macro{P\_tmpdir} e poi con \file{/tmp}. Questa +funzione è rientrante e non soffre di problemi di \textit{race + condition}\index{race condition}. + +Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo +caso si possono usare le vecchie funzioni \func{mktemp} e \func{mkstemp} che +modificano una stringa di input che serve da modello e che deve essere +conclusa da 6 caratteri \code{X} che verranno sostituiti da un codice +unico. La prima delle due è analoga a \func{tmpnam} e genera un nome casuale, +il suo prototipo è: +\begin{prototype}{stlib.h}{char *mktemp(char *template)} + Genera un filename univoco sostituendo le \code{XXXXXX} finali di + \param{template}. + + \bodydesc{La funzione ritorna il puntatore \param{template} in caso di + successo e \macro{NULL} in caso di errore, nel qual caso \var{errno} viene + impostata a: + \begin{errlist} + \item[\macro{EINVAL}] \param{template} non termina con \code{XXXXXX}. + \end{errlist}} +\end{prototype} +\noindent dato che \param{template} deve poter essere modificata dalla +funzione non si può usare una stringa costante. Tutte le avvertenze riguardo +alle possibili \textit{race condition}\index{race condition} date per +\func{tmpnam} continuano a valere; inoltre in alcune vecchie implementazioni +il valore di usato per sostituire le \code{XXXXXX} viene formato con il +\acr{pid} del processo più una lettera, il che mette a disposizione solo 26 +possibilità diverse per il nome del file, e rende il nome temporaneo facile da +indovinare. Per tutti questi motivi la funzione è deprecata e non dovrebbe mai +essere usata. + + + +La seconda funzione, \func{mkstemp} è sostanzialmente equivalente a +\func{tmpfile}, ma restituisce un file descriptor invece di uno stream; il suo +prototipo è: +\begin{prototype}{stlib.h}{int mkstemp(char *template)} + Genera un file temporaneo con un nome ottenuto sostituendo le \code{XXXXXX} + finali di \param{template}. + + \bodydesc{La funzione ritorna il file descriptor in caso successo e + -1 in caso di errore, nel qual caso \var{errno} viene impostata a: + \begin{errlist} + \item[\macro{EINVAL}] \param{template} non termina con \code{XXXXXX}. + \item[\macro{EEXIST}] non è riuscita a creare un file temporano, il + contenuto di \param{template} è indefinito. + \end{errlist}} +\end{prototype} +\noindent come per \func{mktemp} anche in questo caso \param{template} non può +essere una stringa costante. La funzione apre un file in lettura/scrittura con +la funzione \func{open}, usando l'opzione \macro{O\_EXCL} (si veda +\secref{sec:file_open}), in questo modo al ritorno della funzione si ha la +certezza di essere i soli utenti del file. I permessi sono impostati al valore +\code{0600}\footnote{questo è vero a partire dalle \acr{glibc} 2.0.7, le + versioni precedenti delle \acr{glibc} e le vecchie \acr{libc5} e \acr{libc4} + usavano il valore \code{0666} che permetteva a chiunque di leggere i + contenuti del file.} (si veda \secref{sec:file_perm_overview}). + +In OpenBSD è stata introdotta un'altra funzione\footnote{introdotta anche in + Linux a partire dalle \acr{glibc} 2.1.91.} simile alle precedenti, +\func{mkdtemp}, che crea una directory temporanea; il suo prototipo è: +\begin{prototype}{stlib.h}{char *mkdtemp(char *template)} + Genera una directory temporaneo il cui nome è ottenuto sostituendo le + \code{XXXXXX} finali di \param{template}. + + \bodydesc{La funzione ritorna il puntatore al nome della directory in caso + successo e \macro{NULL} in caso di errore, nel qual caso \var{errno} viene + impostata a: + \begin{errlist} + \item[\macro{EINVAL}] \param{template} non termina con \code{XXXXXX}. + \end{errlist} + più gli altri eventuali codici di errore di \func{mkdir}.} +\end{prototype} +\noindent la directory è creata con permessi \code{0700} (al solito si veda +\capref{cha:file_unix_interface} per i dettagli); dato che la creazione della +directory è sempre esclusiva i precedenti problemi di \textit{race + condition}\index{race condition} non si pongono. \section{La manipolazione delle caratteristiche dei files} @@ -603,19 +879,19 @@ generali relative alle caratteristiche di ciascun file, a partire dalle informazioni relative al controllo di accesso, sono mantenute nell'inode. Vedremo in questa sezione come sia possibile leggere tutte queste informazioni -usando la funzione \texttt{stat}, che permette l'accesso a tutti i dati +usando la funzione \func{stat}, che permette l'accesso a tutti i dati memorizzati nell'inode; esamineremo poi le varie funzioni usate per manipolare tutte queste informazioni (eccetto quelle che riguardano la gestione del -controllo di accesso, già trattate in in \secref{sec:file_access_control}). +controllo di accesso, trattate in in \secref{sec:file_access_control}). -\subsection{Le funzioni \texttt{stat}, \texttt{fstat} e \texttt{lstat}} +\subsection{Le funzioni \func{stat}, \func{fstat} e \func{lstat}} \label{sec:file_stat} La lettura delle informazioni relative ai file è fatta attraverso la famiglia -delle funzioni \func{stat}; questa è la funzione che il comando \cmd{ls} usa -per poter ottenere e mostrare tutti i dati dei files. I prototipi di queste -funzioni sono i seguenti: +delle funzioni \func{stat}; questa è la funzione che ad esempio usa il comando +\cmd{ls} per poter ottenere e mostrare tutti i dati dei files. I prototipi di +queste funzioni sono i seguenti: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/stat.h} @@ -633,17 +909,21 @@ funzioni sono i seguenti: eccetto che si usa con un file aperto, specificato tramite il suo file descriptor \var{filedes}. - Le funzioni restituiscono zero in caso di successo e -1 per un errore, in - caso di errore \texttt{errno} può assumere uno dei valori: \macro{EBADF}, - \macro{ENOENT}, \macro{ENOTDIR}, \macro{ELOOP}, \macro{EFAULT}, - \macro{EACCESS}, \macro{ENOMEM}, \macro{ENAMETOOLONG}. + \bodydesc{Le funzioni restituiscono zero in caso di successo e -1 per + un errore, in caso di errore \var{errno} può assumere uno dei + valori: \macro{EBADF}, \macro{ENOENT}, \macro{ENOTDIR}, + \macro{ELOOP}, \macro{EFAULT}, \macro{EACCESS}, \macro{ENOMEM}, + \macro{ENAMETOOLONG}.} \end{functions} +\noindent il loro comportamento è identico, solo che operano rispettivamente +su un file, su un link simbolico e su un file descriptor. -La struttura \texttt{stat} è definita nell'header \texttt{sys/stat.h} e in -generale dipende dall'implementazione, la versione usata da Linux è mostrata -in \nfig, così come riportata dalla man page (in realtà la definizione -effettivamente usata nel kernel dipende dall'architettura e ha altri campi -riservati per estensioni come tempi più precisi, o per il padding dei campi). +La struttura \var{stat} usata da queste funzioni è definita nell'header +\file{sys/stat.h} e in generale dipende dall'implementazione, la versione +usata da Linux è mostrata in \nfig, così come riportata dalla pagina di +manuale di \func{stat} (in realtà la definizione effettivamente usata nel +kernel dipende dall'architettura e ha altri campi riservati per estensioni +come tempi più precisi, o per il padding dei campi). \begin{figure}[!htb] \footnotesize @@ -668,29 +948,30 @@ struct stat { \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \texttt{stat} per la lettura delle informazioni dei + \caption{La struttura \var{stat} per la lettura delle informazioni dei file} \label{fig:file_stat_struct} \end{figure} Si noti come i vari membri della struttura siano specificati come tipi nativi del sistema (di quelli definiti in \tabref{tab:xxx_sys_types}, e dichiarati in -\texttt{sys/types.h}). +\file{sys/types.h}). \subsection{I tipi di file} \label{sec:file_types} -Come riportato in \tabref{tab:file_file_types} in Linux oltre ai file e -alle directory esistono vari altri oggetti che possono stare su un filesystem; -il tipo di file è ritornato dalla \texttt{stat} nel campo \texttt{st\_mode} -(che è quello che contiene anche le informazioni relative ai permessi). +Come riportato in \tabref{tab:file_file_types} in Linux oltre ai file e alle +directory esistono vari altri oggetti che possono stare su un filesystem. Il +tipo di file è ritornato dalla \func{stat} come maschera binaria nel campo +\var{st\_mode} (che che contiene anche le informazioni relative ai permessi). Dato che il valore numerico può variare a seconda delle implementazioni, lo standard POSIX definisce un insieme di macro per verificare il tipo di files, -queste vengono usate anche da Linux che supporta pure le estensioni per link -simbolici e socket definite da BSD, l'elenco completo di tutte le macro -definite in GNU/Linux è riportato in \ntab. +queste vengono usate anche da Linux che supporta pure le estensioni allo +standard per i link simbolici e i socket definite da BSD; l'elenco completo +delle macro con cui è possibile estrarre l'informazione da \var{st\_mode} è +riportato in \ntab. \begin{table}[htb] \centering \footnotesize @@ -708,14 +989,21 @@ definite in GNU/Linux \macro{S\_ISSOCK(m)} & socket \\ \hline \end{tabular} - \caption{Macro per i tipi di file (definite in \texttt{sys/stat.h})} + \caption{Macro per i tipi di file (definite in \texttt{sys/stat.h}).} \label{tab:file_type_macro} \end{table} -Oltre a queste macro è possibile usare direttamente il valore di -\var{st\_mode} per ricavare il significato dei vari bit in esso memorizzati, -per questo sempre in \texttt{sys/stat.h} sono definiti i flag riportati in -\ntab: +Oltre alle macro di \tabref{tab:file_type_macro} è possibile usare +direttamente il valore di \var{st\_mode} per ricavare il tipo di file +controllando direttamente i vari bit in esso memorizzati. Per questo sempre in +\file{sys/stat.h} sono definite le costanti numeriche riportate in \ntab. + +Il primo valore dell'elenco di \secref{tab:file_mode_flags} è la maschera +binaria che permette di estrarre i bit nei quali viene memorizzato il tipo di +file, i valori successivi sono le costanti corrispondenti ai singoli bit, e +possono essere usati per effettuare la selezione sul tipo di file voluto, con +un'opportuna combinazione. + \begin{table}[htb] \centering \footnotesize @@ -754,15 +1042,13 @@ per questo sempre in \texttt{sys/stat.h} sono definiti i flag riportati in \hline \end{tabular} \caption{Costanti per l'identificazione dei vari bit che compongono il campo - \var{st\_mode} (definite in \texttt{sys/stat.h})} + \var{st\_mode} (definite in \file{sys/stat.h}).} \label{tab:file_mode_flags} \end{table} -Il primo valore definisce la maschera dei bit usati nei quali viene -memorizzato il tipo di files, mentre gli altri possono essere usati per -effettuare delle selezioni sul tipo di file voluto, combinando opportunamente -i vari flag; ad esempio se si volesse controllare se un file è una directory o -un file ordinario si potrebbe definire la condizione: +Ad esempio se si volesse impostare una condizione che permetta di controllare +se un file è una directory o un file ordinario si potrebbe definire la macro +di preprocessore: \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} #define IS_FILE_DIR(x) (((x) & S_IFMT) & (S_IFDIR | S_IFREG)) \end{lstlisting} @@ -770,12 +1056,12 @@ in cui prima si estraggono da \var{st\_mode} i bit relativi al tipo di file e poi si effettua il confronto con la combinazione di tipi scelta. -\subsection{La dimensione dei file} +\subsection{Le dimensioni dei file} \label{sec:file_file_size} -Il membro \var{st\_size} contiene la dimensione del file in byte (se il file -è un file normale, nel caso di un link simbolico al dimensione è quella del -pathname che contiene). +Il membro \var{st\_size} contiene la dimensione del file in byte (se il file è +un file regolare, nel caso di un link simbolico la dimensione è quella del +pathname che contiene). Il campo \var{st\_blocks} definisce la lunghezza del file in blocchi di 512 byte. Il campo \var{st\_blksize} infine definisce la dimensione preferita per @@ -783,28 +1069,29 @@ i trasferimenti sui file (che per l'interfaccia degli stream); scrivere sul file a blocchi di dati di dimensione inferiore sarebbe inefficiente. -Si tenga conto che lunghezza del file riportata in \var{st\_size} non è detto -che corrisponda all'occupazione dello spazio su disco per via della possibile -esistenza dei cosiddetti \textsl{buchi} (detti normalmente \textit{holes}) che -si formano tutte le volte che si va a scrivere su un file dopo aver eseguito -una \func{seek} (vedi \secref{sec:file_lseek}) oltre la sua conclusione -corrente. +Si tenga conto che la lunghezza del file riportata in \var{st\_size} non è +detto che corrisponda all'occupazione dello spazio su disco per via della +possibile esistenza dei cosiddetti \textit{holes} (letteralmente +\textsl{buchi}) che si formano tutte le volte che si va a scrivere su un file +dopo aver eseguito una \func{lseek} (vedi \secref{sec:file_lseek}) oltre la +sua fine. -In tal caso si avranno differenti risultati a seconda del modi in cui si +In questo caso si avranno risultati differenti a seconda del modo in cui si calcola la lunghezza del file, ad esempio il comando \cmd{du}, (che riporta il numero di blocchi occupati) potrà dare una dimensione inferiore, mentre se si -legge dal file (ad esempio usando \cmd{wc -c}), dato che in tal caso per le -parti non scritte vengono restituiti degli zeri, si avrà lo stesso risultato -di \cmd{ls}. - -Se è sempre possibile allargare un file scrivendoci sopra od usando la -funzione \func{seek} per spostarsi oltre la sua fine. Esistono però anche casi -in cui si può avere bisogno di effettuare un troncamento scartando i dati al -di là della dimensione scelta come nuova fine del file. - -Un file può essere troncato a zero aprendolo con il flag \macro{O\_TRUNC}, ma -questo è un caso particolare; per qualunque altra dimensione si possono usare -le due funzioni: +legge dal file (ad esempio usando il comando \cmd{wc -c}), dato che in tal +caso per le parti non scritte vengono restituiti degli zeri, si avrà lo stesso +risultato di \cmd{ls}. + +Se è sempre possibile allargare un file, scrivendoci sopra od usando la +funzione \func{lseek} per spostarsi oltre la sua fine, esistono anche casi in +cui si può avere bisogno di effettuare un troncamento, scartando i dati +presenti al di là della dimensione scelta come nuova fine del file. + +Un file può sempre essere troncato a zero aprendolo con il flag +\macro{O\_TRUNC}, ma questo è un caso particolare; per qualunque altra +dimensione si possono usare le due funzioni \func{truncate} e +\func{ftruncate}, i cui prototipi sono: \begin{functions} \headdecl{unistd.h} \funcdecl{int truncate(const char *file\_name, off\_t length)} Fa si che la dimensione del file \var{file\_name} sia troncata ad @@ -814,39 +1101,40 @@ le due funzioni: eccetto che si usa con un file aperto, specificato tramite il suo file descriptor \var{fd}. - Le funzioni restituiscono zero in caso di successo e -1 per un errore, in - caso di errore \texttt{errno} viene settato opportunamente; per - \func{ftruncate} si hanno i valori: + \bodydesc{Le funzioni restituiscono zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} viene impostata opportunamente; per + \func{ftruncate} si hanno i valori: \begin{errlist} - \item \macro{EBADF} \var{fd} non è un file descriptor. - \item \texttt{EINVAL} \var{fd} è un riferimento ad un socket, non a un file + \item[\macro{EBADF}] \var{fd} non è un file descriptor. + \item[\macro{EINVAL}] \var{fd} è un riferimento ad un socket, non a un file o non è aperto in scrittura. \end{errlist} per \func{truncate} si hanno: \begin{errlist} - \item \texttt{EACCES} il file non ha permesso di scrittura o non si ha il + \item[\macro{EACCES}] il file non ha permesso di scrittura o non si ha il permesso di esecuzione una delle directory del pathname. - \item \texttt{ETXTBSY} Il file è un programma in esecuzione. + \item[\macro{ETXTBSY}] Il file è un programma in esecuzione. \end{errlist} ed anche \macro{ENOTDIR}, \macro{ENAMETOOLONG}, \macro{ENOENT}, - \macro{EROFS}, \macro{EIO}, \macro{EFAULT}, \macro{ELOOP}. + \macro{EROFS}, \macro{EIO}, \macro{EFAULT}, \macro{ELOOP}.} \end{functions} Se il file è più lungo della lunghezza specificata i dati in eccesso saranno perduti; il comportamento in caso di lunghezza inferiore non è specificato e dipende dall'implementazione: il file può essere lasciato invariato o esteso fino alla lunghezza scelta; in quest'ultimo caso lo spazio viene riempito con -zeri (e in genere si ha la creazione di un hole nel file). +zeri (e in genere si ha la creazione di un \textit{hole} nel file). \subsection{I tempi dei file} \label{sec:file_file_times} Il sistema mantiene per ciascun file tre tempi. Questi sono registrati -nell'inode insieme agli altri attributi del file e possono essere letti tramite -la funzione \func{stat}, che li restituisce attraverso tre campi della -struttura in \figref{fig:file_stat_struct}. Il significato di detti tempi e -dei relativi campi è riportato nello schema in \ntab: +nell'inode insieme agli altri attributi del file e possono essere letti +tramite la funzione \func{stat}, che li restituisce attraverso tre campi della +struttura \var{stat} di \figref{fig:file_stat_struct}. Il significato di detti +tempi e dei relativi campi è riportato nello schema in \ntab, dove si è anche +riportato un esempio delle funzioni che effettuano cambiamenti su di essi. \begin{table}[htb] \centering @@ -854,22 +1142,24 @@ dei relativi campi \begin{tabular}[c]{|c|l|l|c|} \hline \textbf{Membro} & \textbf{Significato} & \textbf{Funzione} - & \textbf{Opzione} \\ + & \textbf{Opzione di \cmd{ls}} \\ \hline \hline - \var{st\_atime}& ultimo accesso ai dati del file &\func{read}& \cmd{-u}\\ - \var{st\_mtime}& ultima modifica ai dati del file &\func{write}& default\\ + \var{st\_atime}& ultimo accesso ai dati del file &\func{read}, + \func{utime} & \cmd{-u}\\ + \var{st\_mtime}& ultima modifica ai dati del file &\func{write}, + \func{utime} & default\\ \var{st\_ctime}& ultima modifica ai dati dell'inode&\func{chmod}, \func{utime} & \cmd{-c} \\ \hline \end{tabular} - \caption{I tre tempi associati a ciascun file} + \caption{I tre tempi associati a ciascun file.} \label{tab:file_file_times} \end{table} Il primo punto da tenere presente è la differenza fra il cosiddetto tempo di modifica (il \textit{modification time} \var{st\_mtime}) e il tempo di -cambiamento di stato (il \textit{chage time} \var{st\_ctime}). Il primo +cambiamento di stato (il \textit{change time} \var{st\_ctime}). Il primo infatti fa riferimento ad una modifica del contenuto di un file, mentre il secondo ad una modifica dell'inode; siccome esistono molte operazioni (come la funzione \func{link} e molte altre che vedremo in seguito) che modificano solo @@ -878,9 +1168,9 @@ l'utilizzo di un altro tempo. Il sistema non tiene conto dell'ultimo accesso all'inode, pertanto funzioni come \func{access} o \func{stat} non hanno alcuna influenza sui tre tempi. Il -tempo di ultimo accesso viene di solito usato per cancellare i file che non -servono più dopo un certo lasso di tempo (ad esempio \cmd{leafnode} cancella i -vecchi articoli sulla base di questo tempo). +tempo di ultimo accesso (ai dati) viene di solito usato per cancellare i file +che non servono più dopo un certo lasso di tempo (ad esempio \cmd{leafnode} +cancella i vecchi articoli sulla base di questo tempo). Il tempo di ultima modifica invece viene usato da \cmd{make} per decidere quali file necessitano di essere ricompilati o (talvolta insieme anche al @@ -893,14 +1183,15 @@ L'effetto delle varie funzioni di manipolazione dei file sui tempi illustrato in \ntab. Si sono riportati gli effetti sia per il file a cui si fa riferimento, sia per la directory che lo contiene; questi ultimi possono essere capiti se si tiene conto di quanto già detto, e cioè che anche le -directory sono files, che il sistema tratta in maniera del tutto analoga agli -altri. +directory sono file (che contengono una lista di nomi) che il sistema tratta +in maniera del tutto analoga a tutti gli altri. -Per questo motivo tutte le volte che compiremo una operazione su un file che -comporta una modifica della sua directory entry, andremo anche a scrivere -sulla directory che lo contiene cambiandone il tempo di modifica. Un esempio -di questo può essere la cancellazione di un file, mentre leggere o scrivere o -cambiarne i permessi ha effetti solo sui tempi del file. +Per questo motivo tutte le volte che compiremo un'operazione su un file che +comporta una modifica del nome contenuto nella directory, andremo anche a +scrivere sulla directory che lo contiene cambiandone il tempo di modifica. Un +esempio di questo può essere la cancellazione di un file, invece leggere o +scrivere o cambiare i permessi di un file ha effetti solo sui tempi di +quest'ultimo. \begin{table}[htb] \centering @@ -908,18 +1199,20 @@ cambiarne i permessi ha effetti solo sui tempi del file. \begin{tabular}[c]{|l|c|c|c|c|c|c|l|} \hline \multicolumn{1}{|p{3cm}|}{\centering{\vspace{6pt}\textbf{Funzione}}} & - \multicolumn{3}{|p{3cm}|}{\centering{File o directory di riferimento}}& - \multicolumn{3}{|p{3cm}|}{\centering{Directory genitrice del riferimento}} + \multicolumn{3}{|p{3.6cm}|}{\centering{ + \textbf{File o directory del riferimento}}}& + \multicolumn{3}{|p{3.6cm}|}{\centering{ + \textbf{Directory contenente il riferimento}}} &\multicolumn{1}{|p{3.6cm}|}{\centering{\vspace{6pt}\textbf{Note}}} \\ \cline{2-7} \cline{2-7} \multicolumn{1}{|p{3cm}|}{} - &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(a)}}} - &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(m)}}} - &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(c)}}} - &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(a)}}} - &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(m)}}} - &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(c)}}} + &\multicolumn{1}{|p{.9cm}|}{\centering{\textsl{(a)}}} + &\multicolumn{1}{|p{.9cm}|}{\centering{\textsl{(m)}}} + &\multicolumn{1}{|p{.9cm}|}{\centering{\textsl{(c)}}} + &\multicolumn{1}{|p{.9cm}|}{\centering{\textsl{(a)}}} + &\multicolumn{1}{|p{.9cm}|}{\centering{\textsl{(m)}}} + &\multicolumn{1}{|p{.9cm}|}{\centering{\textsl{(c)}}} &\multicolumn{1}{|p{3cm}|}{} \\ \hline \hline @@ -950,9 +1243,9 @@ cambiarne i permessi ha effetti solo sui tempi del file. \func{read} &$\bullet$& & & & & & \\ \func{remove} - & & &$\bullet$& &$\bullet$&$\bullet$& using + & & &$\bullet$& &$\bullet$&$\bullet$& se esegue \func{unlink}\\ \func{remove} - & & & & &$\bullet$&$\bullet$& using + & & & & &$\bullet$&$\bullet$& se esegue \func{rmdir}\\ \func{rename} & & &$\bullet$& &$\bullet$&$\bullet$& per entrambi gli argomenti\\ \func{rmdir} @@ -974,29 +1267,30 @@ cambiarne i permessi ha effetti solo sui tempi del file. \end{table} Si noti infine come \var{st\_ctime} non abbia nulla a che fare con il tempo di -creazione del file, usato da molti altri sistemi operativi, che in unix non -esiste. +creazione del file, usato in molti altri sistemi operativi, ma che in Unix non +esiste. Per questo motivo quando si copia un file, a meno di preservare +esplicitamente i tempi (ad esempio con l'opzione \cmd{-p} di \cmd{cp}) esso +avrà sempre il tempo corrente come data di ultima modifica. -\subsection{La funzione \texttt{utime}} +\subsection{La funzione \func{utime}} \label{sec:file_utime} I tempi di ultimo accesso e modifica possono essere cambiati usando la funzione \func{utime}, il cui prototipo è: - \begin{prototype}{utime.h} -{int utime(const char * filename, struct utimbuf *times)} +{int utime(const char *filename, struct utimbuf *times)} Cambia i tempi di ultimo accesso e modifica dell'inode specificato da -\var{filename} secondo i campi \var{actime} e \var{modtime} di \var{times}. Se -questa è \macro{NULL} allora viene usato il tempo corrente. +\param{filename} secondo i campi \var{actime} e \var{modtime} di +\param{times}. Se questa è \macro{NULL} allora viene usato il tempo corrente. -La funzione restituisce zero in caso di successo e -1 in caso di errore, nel -qual caso \var{errno} è settata opportunamente. +\bodydesc{La funzione restituisce zero in caso di successo e -1 in caso + di errore, nel qual caso \var{errno} è impostata opportunamente. \begin{errlist} -\item \texttt{EACCESS} non si ha il permesso di scrittura sul file. -\item \texttt{ENOENT} \var{filename} non esiste. -\end{errlist} +\item[\macro{EACCESS}] non si ha il permesso di scrittura sul file. +\item[\macro{ENOENT}] \param{filename} non esiste. +\end{errlist}} \end{prototype} La struttura \var{utimebuf} usata da \func{utime} è definita come: @@ -1008,10 +1302,10 @@ struct utimbuf { \end{lstlisting} L'effetto della funzione e i privilegi necessari per eseguirla dipendono da -cosa è l'argomento \var{times}; se è \textit{NULL} la funzione setta il tempo -corrente ed è sufficiente avere accesso in scrittura al file; se invece si è -specificato un valore la funzione avrà successo solo se si è proprietari del -file (o si hanno i privilegi di amministratore). +cosa è l'argomento \param{times}; se è \macro{NULL} la funzione imposta il +tempo corrente ed è sufficiente avere accesso in scrittura al file; se invece +si è specificato un valore la funzione avrà successo solo se si è proprietari +del file (o si hanno i privilegi di amministratore). Si tenga presente che non è comunque possibile specificare il tempo di cambiamento di stato del file, che viene comunque cambiato dal kernel tutte le @@ -1019,519 +1313,677 @@ volte che si modifica l'inode (quindi anche alla chiamata di \func{utime}). Questo serve anche come misura di sicurezza per evitare che si possa modificare un file nascondendo completamente le proprie tracce. In realtà la cosa resta possibile, se si è in grado di accedere al device, scrivendo -direttamente sul disco senza passare attraverso il filesystem, ma ovviamente è -molto più complicato da realizzare. +direttamente sul disco senza passare attraverso il filesystem, ma ovviamente +in questo modo la cosa è molto più complicata da realizzare. -\section{La manipolazione di file e directory} +\section{Il controllo di accesso ai file} +\label{sec:file_access_control} -Come già accennato in \secref{sec:file_filesystem} in un sistema unix-like -i file hanno delle caratteristiche specifiche dipendenti dall'architettura del -sistema, esamineremo qui allora le funzioni usate per la creazione di link -simbolici e diretti e per la gestione delle directory, approfondendo quanto -già accennato in precedenza. +Una delle caratteristiche fondamentali di tutti i sistemi unix-like è quella +del controllo di accesso ai file, che viene implementato per qualunque +filesystem standard. In questa sezione ne esamineremo i concetti essenziali e +le funzioni usate per gestirne i vari aspetti. -\subsection{Le funzioni \texttt{link} e \texttt{unlink}} -\label{sec:file_link} +\subsection{I permessi per l'accesso ai file} +\label{sec:file_perm_overview} -Una delle caratteristiche comuni a vari sistemi operativi è quella di poter -creare dei nomi fittizi (alias o collegamenti) per potersi riferire allo -stesso file accedendovi da directory diverse. Questo è possibile anche in -ambiente unix, dove tali collegamenti sono usualmente chiamati \textit{link}, -ma data la struttura del sistema ci sono due metodi sostanzialmente diversi -per fare questa operazione. +Ad ogni file Linux associa sempre l'utente che ne è proprietario (il +cosiddetto \textit{owner}) ed un gruppo di appartenenza, secondo il meccanismo +degli identificatori di utenti e gruppi (\acr{uid} e \acr{gid}). Questi valori +sono accessibili da programma tramite la funzione \func{stat}, e sono +mantenuti nei campi \var{st\_uid} e \var{st\_gid} della struttura \var{stat} +(si veda \secref{sec:file_stat}).\footnote{Questo è vero solo per filesystem + di tipo Unix, ad esempio non è vero per il filesystem vfat di Windows, che + non fornisce nessun supporto per l'accesso multiutente, e per il quale i + permessi vengono assegnati in maniera fissa con un opzione in fase di + montaggio.} + +Il controllo di accesso ai file segue un modello abbastanza semplice che +prevede tre permessi fondamentali strutturati su tre livelli di accesso. +Esistono varie estensioni a questo modello,\footnote{come le \textit{Access + Control List} che possono essere aggiunte al filesystem standard con + opportune patch, e sono presenti in filesystem non ancora inclusi nel kernel + ufficiale come \textsl{xfs}, o meccanismi di controllo ancora più + sofisticati come il \textit{mandatory access control} di SE-Linux.} ma nella +maggior parte dei casi il meccanismo standard è più che sufficiente a +soffisfare tutte le necessità più comuni. I tre permessi di base associati ad +ogni file sono: +\begin{itemize*} +\item il permesso di lettura (indicato con la lettera \texttt{r}, dall'inglese + \textit{read}). +\item il permesso di scrittura (indicato con la lettera \texttt{w}, + dall'inglese \textit{write}). +\item il permesso di esecuzione (indicato con la lettera \texttt{x}, + dall'inglese \textit{execute}). +\end{itemize*} +mentre i tre livelli su cui sono divisi i privilegi sono: +\begin{itemize*} +\item i privilegi per l'utente proprietario del file. +\item i privilegi per un qualunque utente faccia parte del gruppo cui + appartiene il file. +\item i privilegi per tutti gli altri utenti. +\end{itemize*} + +L'insieme dei permessi viene espresso con un numero a 12 bit; di questi i nove +meno significativi sono usati a gruppi di tre per indicare i permessi base di +lettura, scrittura ed esecuzione e sono applicati rispettivamente +rispettivamente al proprietario, al gruppo, a tutti gli altri. + +I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono +usati per indicare alcune caratteristiche più complesse del meccanismo del +controllo di accesso su cui torneremo in seguito (in +\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}). + +Anche i permessi, come tutte le altre informazioni pertinenti al file, sono +memorizzati nell'inode; in particolare essi sono contenuti in alcuni bit del +campo \var{st\_mode} della struttura \func{stat} (si veda di nuovo +\figref{fig:file_stat_struct}). + +In genere ci si riferisce ai tre livelli dei privilegi usando le lettere +\cmd{u} (per \textit{user}), \cmd{g} (per \textit{group}) e \cmd{o} (per +\textit{other}), inoltre se si vuole indicare tutti i raggruppamenti insieme +si usa la lettera \cmd{a} (per \textit{all}). Si tenga ben presente questa +distinzione dato che in certi casi, mutuando la terminologia in uso nel VMS, +si parla dei permessi base come di permessi per \textit{owner}, \textit{group} +ed \textit{all}, le cui iniziali possono dar luogo a confusione. Le costanti +che permettono di accedere al valore numerico di questi bit nel campo +\var{st\_mode} sono riportate in \ntab. -Come spiegato in \secref{sec:file_architecture} l'accesso al contenuto di -un file su disco avviene attraverso il suo inode, e il nome che si trova in -una directory è solo una etichetta associata ad un puntatore a detto inode. -Questo significa che la realizzazione di un link è immediata in quanto uno -stesso file può avere tanti nomi diversi allo stesso tempo, dati da -altrettante diverse associazioni allo stesso inode; si noti poi che nessuno di -questi nomi viene ad assumere una particolare preferenza rispetto agli altri. +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|l|} + \hline + \textbf{\var{st\_mode}} bit & \textbf{Significato} \\ + \hline + \hline + \macro{S\_IRUSR} & \textit{user-read}, l'utente può leggere \\ + \macro{S\_IWUSR} & \textit{user-write}, l'utente può scrivere \\ + \macro{S\_IXUSR} & \textit{user-execute}, l'utente può eseguire \\ + \hline + \macro{S\_IRGRP} & \textit{group-read}, il gruppo può leggere \\ + \macro{S\_IWGRP} & \textit{group-write}, il gruppo può scrivere \\ + \macro{S\_IXGRP} & \textit{group-execute}, il gruppo può eseguire\\ + \hline + \macro{S\_IROTH} & \textit{other-read}, tutti possono leggere \\ + \macro{S\_IWOTH} & \textit{other-write}, tutti possono scrivere \\ + \macro{S\_IXOTH} & \textit{other-execute}, tutti possono eseguire\\ + \hline + \end{tabular} + \caption{I bit dei permessi di accesso ai file, come definiti in + \texttt{}} + \label{tab:file_bit_perm} +\end{table} -Per aggiungere un nome ad un inode si utilizza la funzione \texttt{link}; si -suole chiamare questo tipo di associazione un collegamento diretto (o -\textit{hard link}). Il prototipo della funzione e le sue caratteristiche -principali, come risultano dalla man page, sono le seguenti: -\begin{prototype}{unistd.h} -{int link(const char * oldpath, const char * newpath)} - Crea un nuovo collegamento diretto al file indicato da \texttt{oldpath} - dandogli nome \texttt{newpath}. - - La funzione restituisce zero in caso di successo e -1 in caso di errore. La - variabile \texttt{errno} viene settata opportunamente, i principali codici - di errore sono: - \begin{errlist} - \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo - stesso filesystem. - \item \texttt{EPERM} il filesystem che contiene \texttt{oldpath} e - \texttt{newpath} non supporta i link diretti o è una directory. - \item \texttt{EEXIST} un file (o una directory) con quel nome esiste di - già. - \item \texttt{EMLINK} ci sono troppi link al file \texttt{oldpath} (il - numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi - \secref{sec:xxx_limits}). - \end{errlist} - -\end{prototype} +I permessi vengono usati in maniera diversa dalle varie funzioni, e a seconda +che si riferiscano a dei file, dei link simbolici o delle directory, qui ci +limiteremo ad un riassunto delle regole generali, entrando nei dettagli più +avanti. -La creazione di un nuovo collegamento diretto non copia il contenuto del file, -ma si limita ad aumentare di uno il numero di referenze al file (come si può -controllare con il campo \var{st\_nlink} di \var{stat}) aggiungendo il nuovo -nome ai precedenti. Si noti che uno stesso file può essere così richiamato in -diverse directory. - -Per quanto dicevamo in \secref{sec:file_filesystem} la creazione del -collegamento diretto è possibile solo se entrambi i pathname sono nello stesso -filesystem; inoltre il filesystem deve supportare i collegamenti diretti (non è -il caso ad esempio del filesystem \texttt{vfat} di Windows). - -La funzione opera sui file ordinari, come sugli altri oggetti del filesystem, -in alcuni filesystem solo l'amministratore è in grado di creare un -collegamento diretto ad un'altra directory, questo lo si fa perché in questo -caso è possibile creare dei circoli nel filesystem (vedi -\secref{sec:file_symlink}) che molti programmi non sono in grado di -gestire e la cui rimozione diventa estremamente complicata (in genere occorre -far girare il programma \texttt{fsck} per riparare il filesystem); data la sua -pericolosità in generale nei filesystem usati in Linux questa caratteristica è -stata disabilitata, e la funzione restituisce l'errore \texttt{EPERM}. - -La rimozione di un file (o più precisamente della voce che lo referenzia) si -effettua con la funzione \texttt{unlink}; il suo prototipo è il seguente: - -\begin{prototype}{unistd.h}{int unlink(const char * pathname)} - Cancella il nome specificato dal pathname nella relativa directory e - decrementa il numero di riferimenti nel relativo inode. Nel caso di link - simbolico cancella il link simbolico; nel caso di socket, fifo o file di - dispositivo rimuove il nome, ma come per i file i processi che hanno aperto - uno di questi oggetti possono continuare ad utilizzarlo. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: - \begin{errlist} - \item \texttt{EISDIR} \var{pathname} si riferisce ad una directory - (valore specifico ritornato da Linux che non consente l'uso di - \texttt{unlink} con le directory, e non conforme allo standard POSIX, che - prescrive invece l'uso di \texttt{EPERM} in caso l'operazione non sia - consentita o il processo non abbia privilegi sufficienti). - \item \texttt{EROFS} \var{pathname} è su un filesystem montato in sola - lettura. - \item \texttt{EISDIR} \var{pathname} fa riferimento a una directory. - \end{errlist} -\end{prototype} +La prima regola è che per poter accedere ad un file attraverso il suo pathname +occorre il permesso di esecuzione in ciascuna delle directory che compongono +il pathname; lo stesso vale per aprire un file nella directory corrente (per +la quale appunto serve il diritto di esecuzione). -Per cancellare una voce in una directory è necessario avere il permesso di -scrittura su di essa (dato che si va a rimuovere una voce dal suo contenuto) e -il diritto di esecuzione sulla directory che la contiene (torneremo in -dettaglio sui permessi e gli attributi fra poco), se inoltre lo -\textit{sticky} bit è settato occorrerà anche essere proprietari del file o -proprietari della directory (o root, per cui nessuna delle restrizioni è -applicata). +Per una directory infatti il permesso di esecuzione significa che essa può +essere attraversata nella risoluzione del pathname, ed è distinto dal permesso +di lettura che invece implica che si può leggere il contenuto della directory. +Questo significa che se si ha il permesso di esecuzione senza permesso di +lettura si potrà lo stesso aprire un file in una directory (se si hanno i +permessi opportuni per il medesimo) ma non si potrà vederlo con \cmd{ls} +(mentre per crearlo occorrerà anche il permesso di scrittura per la +directory). + +Avere il permesso di lettura per un file consente di aprirlo con le opzioni +(si veda quanto riportato in \tabref{tab:file_open_flags}) di sola lettura o +di lettura/scrittura e leggerne il contenuto. Avere il permesso di scrittura +consente di aprire un file in sola scrittura o lettura/scrittura e modificarne +il contenuto, lo stesso permesso è necessario per poter troncare il file. -Una delle caratteristiche di queste funzioni è che la creazione/rimozione -della nome dalla directory e l'incremento/decremento del numero di riferimenti -nell'inode deve essere una operazione atomica (cioè non interrompibile da -altri) processi, per questo entrambe queste funzioni sono realizzate tramite -una singola system call. +Non si può creare un file fintanto che non si disponga del permesso di +esecuzione e di quello di scrittura per la directory di destinazione; gli +stessi permessi occorrono per cancellare un file da una directory (si ricordi +che questo non implica necessariamente la rimozione del contenuto del file dal +disco), non è necessario nessun tipo di permesso per il file stesso (infatti +esso non viene toccato, viene solo modificato il contenuto della directory, +rimuovendo la voce che ad esso fa riferimento). -Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti -i riferimenti ad esso sono stati cancellati, solo quando il \textit{link - count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A -questo però si aggiunge una altra condizione, e cioè che non ci siano processi -che abbiano detto file aperto. Come accennato questa proprietà viene spesso -usata per essere sicuri di non lasciare file temporanei su disco in caso di -crash dei programmi; la tecnica è quella di aprire il file e chiamare -\texttt{unlink} subito dopo. +Per poter eseguire un file (che sia un programma compilato od uno script di +shell, od un altro tipo di file eseguibile riconosciuto dal kernel), occorre +avere il permesso di esecuzione, inoltre solo i file regolari possono essere +eseguiti. -\subsection{Le funzioni \texttt{remove} e \texttt{rename}} -\label{sec:file_remove} +I permessi per un link simbolico sono ignorati, contano quelli del file a cui +fa riferimento; per questo in genere il comando \cmd{ls} riporta per un link +simbolico tutti i permessi come concessi; utente e gruppo a cui esso +appartiene vengono pure ignorati quando il link viene risolto, vengono +controllati solo quando viene richiesta la rimozione del link e quest'ultimo è +in una directory con lo \textsl{sticky bit} impostato (si veda +\secref{sec:file_sticky}). -Al contrario di quanto avviene con altri unix in Linux non è possibile usare -\texttt{unlink} sulle directory, per cancellare una directory si può usare la -funzione \texttt{rmdir} (vedi \secref{sec:file_dir_creat_rem}), oppure la -funzione \texttt{remove}. Questa è la funzione prevista dallo standard ANSI C -per cancellare un file o una directory (e funziona anche per i sistemi che non -supportano i link diretti), che per i file è identica alla \texttt{unlink} e -per le directory è identica alla \texttt{rmdir}: +La procedura con cui il kernel stabilisce se un processo possiede un certo +permesso (di lettura, scrittura o esecuzione) si basa sul confronto fra +l'utente e il gruppo a cui il file appartiene (i valori di \var{st\_uid} e +\var{st\_gid} accennati in precedenza) e l'userid effettivo, il groupid +effettivo e gli eventuali groupid supplementari del processo.\footnote{in + realtà Linux, per quanto riguarda l'accesso ai file, utilizza gli gli + identificatori del gruppo \textit{filesystem} (si ricordi quanto esposto in + \secref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai primi, + eccetto il caso in cui si voglia scrivere un server NFS, ignoreremo questa + differenza.} -\begin{prototype}{stdio.h}{int remove(const char *pathname)} - Cancella un nome dal filesystem. Usa \texttt{unlink} per i file e - \texttt{rmdir} per le directory. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. Per i codici di errori vedi quanto - riportato nella descrizione di \texttt{unlink} e \texttt{rmdir}. -\end{prototype} +Per una spiegazione dettagliata degli identificatori associati ai processi si +veda \secref{sec:proc_perms}; normalmente, a parte quanto vedremo in +\secref{sec:file_suid_sgid}, l'userid effettivo e il groupid effectivo +corrispondono ai valori dell'\acr{uid} e del \acr{gid} dell'utente che ha +lanciato il processo, mentre i groupid supplementari sono quelli dei gruppi +cui l'utente appartiene. + +I passi attraverso i quali viene stabilito se il processo possiede il diritto +di accesso sono i seguenti: +\begin{enumerate} +\item Se l'userid effettivo del processo è zero (corrispondente + all'amministratore) l'accesso è sempre garantito senza nessun ulteriore + controllo. Per questo motivo \textsl{root} ha piena libertà di accesso a + tutti i file. +\item Se l'userid effettivo del processo è uguale all'\acr{uid} del + proprietario del file (nel qual caso si dice che il processo è proprietario + del file) allora: + \begin{itemize*} + \item se il relativo\footnote{per relativo si intende il bit di user-read se + il processo vuole accedere in scrittura, quello di user-write per + l'accesso in scrittura, etc.} bit dei permessi d'accesso dell'utente è + impostato, l'accesso è consentito + \item altrimenti l'accesso è negato + \end{itemize*} +\item Se il groupid effettivo del processo o uno dei groupid supplementari dei + processi corrispondono al \acr{gid} del file allora: + \begin{itemize*} + \item se il bit dei permessi d'accesso del gruppo è impostato, l'accesso è + consentito, + \item altrimenti l'accesso è negato + \end{itemize*} +\item se il bit dei permessi d'accesso per tutti gli altri è impostato, + l'accesso è consentito, altrimenti l'accesso è negato. +\end{enumerate} -Per cambiare nome ad un file si usa invece la funzione \texttt{rename}, il -vantaggio nell'uso di questa funzione al posto della chiamata successiva di -\texttt{unlink} e \texttt{link} è che l'operazione è eseguita atomicamente, in -questo modo non c'è la possibilità che un processo che cerchi di accedere al -nuovo nome dopo che il vecchio è stato cambiato lo trovi mancante. +Si tenga presente che questi passi vengono eseguiti esattamente in +quest'ordine. Questo vuol dire che se un processo è il proprietario di un file +l'accesso è consentito o negato solo sulla base dei permessi per l'utente; i +permessi per il gruppo non vengono neanche controllati. Lo stesso vale se il +processo appartiene ad un gruppo appropriato, in questo caso i permessi per +tutti gli altri non vengono controllati. -\begin{prototype}{stdio.h} -{int rename(const char *oldpath, const char *newpath)} - Rinomina un file, spostandolo fra directory diverse quando richiesto. - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: - \begin{errlist} - \item \texttt{EISDIR} \texttt{newpath} è una directory già esistente mentre - \texttt{oldpath} non è una directory. - \item \texttt{EXDEV} \texttt{oldpath} e \texttt{newpath} non sono sullo - stesso filesystem. - \item \texttt{ENOTEMPTY} \texttt{newpath} è una directory già esistente e - non vuota. - \item \texttt{EBUSY} o \texttt{oldpath} o \texttt{newpath} sono in uso da - parte di qualche processo (come directory di lavoro o come root) o del - sistema (come mount point). - \item \texttt{EINVAL} \texttt{newpath} contiene un prefisso di - \texttt{oldpath} o più in generale si è cercato di creare una directory - come sottodirectory di se stessa. - \item \texttt{EMLINK} \texttt{oldpath} ha già il massimo numero di link - consentiti o è una directory e la directory che contiene \texttt{newpath} - ha già il massimo numero di link. - \item \texttt{ENOTDIR} Uno dei componenti dei pathname non è una directory - o\texttt{oldpath} è una directory e \texttt{newpath} esiste e non è una - directory. - \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory in - cui si vuole creare il nuovo link o una delle directory del pathname non - consente la ricerca (permesso di esecuzione). - \item \texttt{EPERM} le directory contenenti \texttt{oldpath} o - \texttt{newpath} hanno lo sticky bit attivo e i permessi del processo non - consentono rispettivamente la cancellazione e la creazione del file, o il - filesystem non supporta i link. - \item \texttt{ENOSPC} Il device di destinazione non ha più spazio per la - nuova voce. - \end{errlist} -\end{prototype} +\subsection{I bit \acr{suid} e \acr{sgid}} +\label{sec:file_suid_sgid} -\subsection{I link simbolici} -\label{sec:file_symlink} +Come si è accennato (in \secref{sec:file_perm_overview}) nei dodici bit del +campo \var{st\_mode} di \var{stat} che vengono usati per il controllo di +accesso oltre ai bit dei permessi veri e propri, ci sono altri tre bit che +vengono usati per indicare alcune proprietà speciali dei file. Due di questi +sono i bit detti \acr{suid} (da \textit{set-user-ID bit}) e \acr{sgid} (da +\textit{set-group-ID bit}) che sono identificati dalle costanti +\macro{S\_ISUID} e \macro{S\_ISGID}. -Siccome la funzione \texttt{link} crea riferimenti agli inodes, essa può -funzionare soltanto per file che risiedono sullo stesso filesystem, dato che -in questo caso è garantita l'unicità dell'inode, e solo per un filesystem di -tipo unix. Inoltre in Linux non è consentito eseguire un link diretto ad una -directory. +Come spiegato in dettaglio in \secref{sec:proc_exec}, quando si lancia un +programma il comportamento normale del kernel è quello di impostare gli +identificatori del gruppo \textit{effective} del nuovo processo al valore dei +corrispondenti del gruppo \textit{real} del processo corrente, che normalmente +corrispondono dell'utente con cui si è entrati nel sistema. -Per ovviare a queste limitazioni i sistemi unix supportano un'altra forma di -link (i cosiddetti \textit{soft link} o \textit{symbolic link}), che sono, -come avviene in altri sistemi operativi, dei file che contengono il -semplicemente il riferimento ad un altro file (o directory). In questo modo è -possibile effettuare link anche attraverso filesystem diversi e a directory, e -pure a file che non esistono ancora. +Se però il file del programma\footnote{per motivi di sicurezza il kernel + ignora i bit \acr{suid} e \acr{sgid} per gli script eseguibili.} (che +ovviamente deve essere eseguibile) ha il bit \acr{suid} impostato, il kernel +assegnerà come userid effettivo al nuovo processo l'\acr{uid} del proprietario +del file al posto dell'\acr{uid} del processo originario. Avere il bit +\acr{sgid} impostato ha lo stesso effetto sul groupid effettivo del processo. + +I bit \acr{suid} e \acr{sgid} vengono usati per permettere agli utenti normali +di usare programmi che abbisognano di privilegi speciali; l'esempio classico è +il comando \cmd{passwd} che ha la necessità di modificare il file delle +password, quest'ultimo ovviamente può essere scritto solo dall'amministratore, +ma non è necessario chiamare l'amministratore per cambiare la propria +password. Infatti il comando \cmd{passwd} appartiene a root ma ha il bit +\acr{suid} impostato per cui quando viene lanciato da un utente normale parte +con i privilegi di root. -Il sistema funziona in quanto i link simbolici sono contrassegnati come tali -al kernel (analogamente a quanto avviene per le directory) per cui la chiamata -ad una \texttt{open} o una \texttt{stat} su un link simbolico comporta la -lettura del contenuto del medesimo e l'applicazione della funzione al file -specificato da quest'ultimo. Invece altre funzioni come quelle per cancellare -o rinominare i file operano direttamente sul link simbolico (per l'elenco vedi -\ntab). Inoltre esistono funzioni apposite, come la \texttt{readlink} e la -\texttt{lstat} per accedere alle informazioni del link invece che a quelle del -file a cui esso fa riferimento. - -Le funzioni per operare sui link simbolici sono le seguenti, esse sono tutte -dichiarate nell'header file \texttt{unistd.h}. +Chiaramente avere un processo che ha privilegi superiori a quelli che avrebbe +normalmente l'utente che lo ha lanciato comporta vari rischi, e questo tipo di +programmi devono essere scritti accuratamente per evitare che possano essere +usati per guadagnare privilegi non consentiti (l'argomento è affrontato in +dettaglio in \secref{sec:proc_perms}). + +La presenza dei bit \acr{suid} e \acr{sgid} su un file può essere rilevata con +il comando \cmd{ls -l}, che visualizza una lettera \cmd{s} al posto della +\cmd{x} in corrispondenza dei permessi di utente o gruppo. La stessa lettera +\cmd{s} può essere usata nel comando \cmd{chmod} per impostare questi bit. +Infine questi bit possono essere controllati all'interno di \var{st\_mode} con +l'uso delle due costanti \macro{S\_ISUID} e \macro{S\_IGID}, i cui valori sono +riportati in \tabref{tab:file_mode_flags}. + +Gli stessi bit vengono ad assumere in significato completamente diverso per le +directory, normalmente infatti Linux usa la convenzione di SVR4 per indicare +con questi bit l'uso della semantica BSD nella creazione di nuovi file (si +veda \secref{sec:file_ownership} per una spiegazione dettagliata al +proposito). + +Infine Linux utilizza il bit \acr{sgid} per una ulteriore estensione mutuata +da SVr4. Il caso in cui un file ha il bit \acr{sgid} impostare senza che lo sia +anche il corrispondente bit di esecuzione viene utilizzato per attivare per +quel file il \textit{mandatory locking} (argomento che affronteremo in +dettagliopiù avanti in \secref{sec:file_mand_locking}). + + +\subsection{Il bit \textsl{sticky}} +\label{sec:file_sticky} + +L'ultimo dei bit rimanenti, identificato dalla costante \macro{S\_ISVTX}, è in +parte un rimasuglio delle origini dei sistemi Unix. A quell'epoca infatti la +memoria virtuale e l'accesso ai files erano molto meno sofisticati e per +ottenere la massima velocità possibile per i programmi usati più comunemente +si poteva impostare questo bit. + +L'effetto di questo bit era che il segmento di testo del programma (si veda +\secref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la +prima volta che questo veniva lanciato, e vi permaneva fino al riavvio della +macchina (da questo il nome di \textsl{sticky bit}); essendo la swap un file +continuo indicizzato direttamente in questo modo si poteva risparmiare in +tempo di caricamento rispetto alla ricerca del file su disco. Lo +\textsl{sticky bit} è indicato usando la lettera \cmd{t} al posto della +\cmd{x} nei permessi per gli altri. + +Ovviamente per evitare che gli utenti potessero intasare la swap solo +l'amministratore era in grado di impostare questo bit, che venne chiamato +anche con il nome di \textit{saved text bit}, da cui deriva quello della +costante. Le attuali implementazioni di memoria virtuale e filesystem rendono +sostanzialmente inutile questo procedimento. + +Benché ormai non venga più utilizzato per i file, lo \textsl{sticky bit} ha +invece assunto un uso importante per le directory;\footnote{lo \textsl{sticky + bit} per le directory è un'estensione non definita nello standard POSIX, + Linux però la supporta, così come BSD e SVR4.} in questo caso se il bit è +impostato un file potrà essere rimosso dalla directory soltanto se l'utente ha +il permesso di scrittura su di essa ed inoltre è vera una delle seguenti +condizioni: +\begin{itemize*} +\item l'utente è proprietario del file +\item l'utente è proprietario della directory +\item l'utente è l'amministratore +\end{itemize*} +un classico esempio di directory che ha questo bit impostato è \file{/tmp}, i +permessi infatti di solito sono impostati come: +\begin{verbatim} +$ ls -ld /tmp +drwxrwxrwt 6 root root 1024 Aug 10 01:03 /tmp +\end{verbatim}%$ +in questo modo chiunque può creare file in questa directory (che infatti è +normalmente utilizzata per la creazione di file temporanei), ma solo l'utente +che ha creato un certo file potrà cancellarlo o rinominarlo. In questo modo si +evita che un utente possa, più o meno consapevolmente, cancellare i file degli +altri. + + +\subsection{La titolarità di nuovi file e directory} +\label{sec:file_ownership} + +Vedremo in \secref{sec:file_base_func} con quali funzioni si possono creare +nuovi file, in tale occasione vedremo che è possibile specificare in sede di +creazione quali permessi applicare ad un file, però non si può indicare a +quale utente e gruppo esso deve appartenere. Lo stesso problema di presenta +per la creazione di nuove directory (procedimento descritto in +\secref{sec:file_dir_creat_rem}). + +Lo standard POSIX prescrive che l'\acr{uid} del nuovo file corrisponda +all'userid effettivo del processo che lo crea; per il \acr{gid} invece prevede +due diverse possibilità: +\begin{itemize*} +\item il \acr{gid} del file corrisponde al group id effettivo del processo. +\item il \acr{gid} del file corrisponde al \acr{gid} della directory in cui + esso è creato. +\end{itemize*} +in genere BSD usa sempre la seconda possibilità, che viene per questo chiamata +semantica BSD. Linux invece segue quella che viene chiamata semantica SVr4; di +norma cioè il nuovo file viene creato, seguendo la prima opzione, con il +\acr{gid} del processo, se però la directory in cui viene creato il file ha il +bit \acr{sgid} impostato allora viene usata la seconda opzione. + +Usare la semantica BSD ha il vantaggio che il \acr{gid} viene sempre +automaticamente propagato, restando coerente a quello della directory di +partenza, in tutte le sottodirectory. La semantica SVr4 offre la possibilità +di scegliere, ma per ottenere lo stesso risultato di coerenza che si ha con +BSD necessita che per le nuove directory venga anche propagato anche il bit +\acr{sgid}. Questo è il comportamento predefinito di \func{mkdir}, ed è in +questo modo ad esempio che Debian assicura che le sottodirectory create nelle +home di un utente restino sempre con il \acr{gid} del gruppo primario dello +stesso. -\begin{prototype}{unistd.h} -{int symlink(const char * oldname, const char * newname)} - Crea un nuovo link simbolico al file indicato da \texttt{oldname} dandogli - nome \texttt{newname}. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore. La variabile \texttt{errno} viene settata secondo i codici di - errore standard di accesso ai file (trattati in dettaglio in - \secref{sec:file_access_control}) ai quali si aggiungono i seguenti: - \begin{errlist} - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di - già. - \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è - su un filesystem montato in sola lettura. - \item \texttt{ENOSPC} La directory o il filesystem in cui si vuole creare il - link è piena e non c'è ulteriore spazio disponibile. - \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione di - \texttt{oldname} o di \texttt{newname}. - \end{errlist} -\end{prototype} -Dato che la funzione \texttt{open} segue i link simbolici, è necessaria usare -un'altra funzione quando si vuole leggere il contenuto di un link simbolico, -questa funzione è la: +\subsection{La funzione \func{access}} +\label{sec:file_access} +Come visto in \secref{sec:file_access_control} il controllo di accesso ad un +file viene fatto utilizzando l'userid ed il groupid effettivo del processo; ci +sono casi però in cui si può voler effettuare il controllo con l'userid reale +ed il groupid reale, vale a dire usando i valori di \acr{uid} e \acr{gid} +relativi all'utente che ha lanciato il programma, e che, come accennato in +\secref{sec:file_suid_sgid} e spiegato in dettaglio in +\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi. Per far +questo si può usare la funzione \func{access}, il cui prototipo è: \begin{prototype}{unistd.h} -{int readlink(const char * path, char * buff, size\_t size)} - Legge il contenuto del link simbolico indicato da \texttt{path} nel buffer - \texttt{buff} di dimensione \texttt{size}. Non chiude la stringa con un - carattere nullo e la tronca a \texttt{size} nel caso il buffer sia troppo - piccolo per contenerla. +{int access(const char *pathname, int mode)} + +Verifica i permessi di accesso, indicati da \var{mode}, per il file indicato +da \var{pathname}. - La funzione restituisce il numero di caratteri letti dentro \texttt{buff} o - -1 per un errore, in caso di errore. La variabile \texttt{errno} viene - settata secondo i codici di errore: - \begin{errlist} - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di - già. - \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è - su un filesystem montato in sola lettura. - \item \texttt{ENOSPC} La directory o il filesystem in cui si vuole creare il - link è piena e non c'è ulteriore spazio disponibile. - \end{errlist} +\bodydesc{La funzione ritorna 0 se l'accesso è consentito, -1 altrimenti; in + quest'ultimo caso la variabile \var{errno} viene impostata secondo i codici + di errore: \macro{EACCES}, \macro{EROFS}, \macro{EFAULT}, \macro{EINVAL}, + \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOTDIR}, \macro{ELOOP}, + \macro{EIO}.} \end{prototype} -In \ntab\ si è riportato un elenco dei comportamenti delle varie funzioni che -operano sui file rispetto ai link simbolici; specificando quali seguono il -link simbolico e quali possono operare direttamente sul suo contenuto. +I valori possibili per l'argomento \param{mode} sono esprimibili come +combinazione delle costanti numeriche riportate in +\tabref{tab:file_access_mode_val} (attraverso un OR binario delle stesse). I +primi tre valori implicano anche la verifica dell'esistenza del file, se si +vuole verificare solo quest'ultima si può usare \macro{F\_OK}, o anche +direttamente \func{stat}. Nel caso in cui \var{pathname} si riferisca ad un +link simbolico, questo viene seguito ed il controllo è fatto sul file a cui +esso fa riferimento. + +La funzione controlla solo i bit dei permessi di accesso, si ricordi che il +fatto che una directory abbia permesso di scrittura non significa che ci si +possa scrivere come in un file, e il fatto che un file abbia permesso di +esecuzione non comporta che contenga un programma eseguibile. La funzione +ritorna zero solo se tutte i permessi controllati sono disponibili, in caso +contrario (o di errore) ritorna -1. \begin{table}[htb] \centering \footnotesize - \begin{tabular}[c]{|l|c|c|} + \begin{tabular}{|c|l|} + \hline + \textbf{\var{mode}} & \textbf{Significato} \\ + \hline + \hline + \macro{R\_OK} & verifica il permesso di lettura \\ + \macro{W\_OK} & verifica il permesso di scritture \\ + \macro{X\_OK} & verifica il permesso di esecuzione \\ + \macro{F\_OK} & verifica l'esistenza del file \\ \hline - \textbf{Funzione} & \textbf{Segue il link} & \textbf{Non segue il link} \\ - \hline - \hline - \func{access} & $\bullet$ & \\ - \func{chdir} & $\bullet$ & \\ - \func{chmod} & $\bullet$ & \\ - \func{chown} & & $\bullet$ \\ - \func{creat} & $\bullet$ & \\ - \func{exec} & $\bullet$ & \\ - \func{lchown} & $\bullet$ & $\bullet$ \\ - \func{link} & & \\ - \func{lstat} & & $\bullet$ \\ - \func{mkdir} & $\bullet$ & \\ - \func{mkfifo} & $\bullet$ & \\ - \func{mknod} & $\bullet$ & \\ - \func{open} & $\bullet$ & \\ - \func{opendir} & $\bullet$ & \\ - \func{pathconf} & $\bullet$ & \\ - \func{readlink} & & $\bullet$ \\ - \func{remove} & & $\bullet$ \\ - \func{rename} & & $\bullet$ \\ - \func{stat} & $\bullet$ & \\ - \func{truncate} & $\bullet$ & \\ - \func{unlink} & & $\bullet$ \\ - \hline \end{tabular} - \caption{Uso dei link simbolici da parte di alcune funzioni.} - \label{tab:file_symb_effect} + \caption{Valori possibile per il parametro \var{mode} della funzione + \func{access}.} + \label{tab:file_access_mode_val} \end{table} -si noti che non si è specificato il comportamento delle funzioni che operano -con i file descriptor, in quanto la gestione del link simbolico viene in -genere effettuata dalla funzione che restituisce il file descriptor -(normalmente la \func{open}). - -\begin{figure}[htb] - \centering - \includegraphics[width=5cm]{img/link_loop.eps} - \caption{Esempio di loop nel filesystem creato con un link simbolico.} - \label{fig:file_link_loop} -\end{figure} - -Un caso comune che si può avere con i link simbolici è la creazione dei -cosiddetti \textit{loop}. La situazione è illustrata in \curfig, che riporta -la struttura della directory \file{/boot}. Come si vede si è creato al suo -interno un link simbolico che punta di nuovo a \file{/boot}\footnote{Questo - tipo di loop è stato effettuato per poter permettere a \cmd{grub} (un - bootloader estremamente avanzato in grado di accedere direttamente - attraverso vari filesystem al file da lanciare come sistema operativo) di - vedere i file in questa directory, che è montata su una partizione separata - (e che grub vedrebbe come radice), con lo stesso path con cui verrebbero - visti dal sistema operativo.}. - -Questo può causare problemi per tutti quei programmi che effettuano la -scansione di una directory senza tener conto dei link simbolici, ad esempio se -lanciassimo un comando del tipo \cmd{grep -r linux *}, il loop nella directory -porterebbe il comando ad esaminare \file{/boot}, \file/{boot/boot}, -\file/{boot/boot/boot} e così via, fino a generare un errore (che poi è -\macro{ELOOP}) quando viene superato il numero massimo di link simbolici -consentiti (uno dei limiti del sistema, posto proprio per poter uscire da -questo tipo di situazione). - -Un secondo punto da tenere presente è che un link simbolico può essere fatto -anche ad un file che non esiste; ad esempio possiamo creare un file temporaneo -nella nostra directory con un link del tipo: -\begin{verbatim} -$ ln -s /tmp/tmp_file temporaneo -\end{verbatim}%$ -ma anche se \file{/tmp/tmp\_file} non esiste (quello che viene chiamato un -\textit{dangling link}, letteralemnte \textsl{link ciondolante}). Aprendo in -scrittura \file{temporaneo} questo verrà scritto; ma se cercassimo di -accederlo in sola lettura (ad esempio con \cmd{cat}) otterremmo: -\begin{verbatim} -$ cat temporaneo -cat: temporaneo: No such file or directory -\end{verbatim}%$ -con un errore che può sembrare sbagliato, dato \cmd{ls} ci mostrerebbe -l'esistenza di \file{temporaneo}. +Un esempio tipico per l'uso di questa funzione è quello di un processo che sta +eseguendo un programma coi privilegi di un altro utente (ad esempio attraverso +l'uso del \acr{suid} bit) che vuole controllare se l'utente originale ha i +permessi per accedere ad un certo file. -\subsection{Le funzioni \texttt{mkdir} e \texttt{rmdir}} -\label{sec:file_dir_creat_rem} -Queste due funzioni servono per creare e cancellare delle directory e sono -omonime degli analoghi comandi di shell. Per poter accedere ai tipi usati -da queste funzioni si deve includere il file \texttt{sys/types.h}, il -protoripo della prima è: +\subsection{Le funzioni \func{chmod} e \func{fchmod}} +\label{sec:file_chmod} -\begin{prototype}{sys/stat.h} - {int mkdir (const char * dirname, mode\_t mode)} - Crea una nuova directory vuota con il nome indicato da \var{dirname}, - assegnandole i permessi indicati da \var{mode}. Il nome può essere indicato - con il pathname assoluto o relativo. +Per cambiare i permessi di un file il sistema mette ad disposizione due +funzioni \func{chmod} e \func{fchmod}, che operano rispettivamente su un +filename e su un file descriptor, i loro prototipi sono: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{sys/stat.h} - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso \var{errno} assumerà i valori: - \begin{errlist} - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di già. - \item \texttt{EACCESS} - Non c'è il permesso di scrittura per la directory in cui si vuole inserire - la nuova directory. - \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory - contiene troppi file. Sotto Linux questo normalmente non avviene perché il - filesystem standard consente la creazione di un numero di file maggiore di - quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che - fare anche con filesystem di altri sistemi questo errore può presentarsi. - \item \texttt{ENOSPC} Non c'è abbastanza spazio sul file system per creare - la nuova directory o si è esaurita la quota disco dell'utente. - \end{errlist} - ed inoltre anche \macro{EPERM}, \macro{EFAULT}, \macro{ENAMETOOLONG}, - \macro{ENOENT}, \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, - \macro{EROFS}. -\end{prototype} - - - -\begin{prototype}{sys/stat.h} - {int rmdir (const char * dirname)} - Cancella la directory \var{dirname}, che deve essere vuota. Il nome può - essere indicato con il pathname assoluto o relativo. + \funcdecl{int chmod(const char *path, mode\_t mode)} Cambia i permessi del + file indicato da \var{path} al valore indicato da \var{mode}. - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso \var{errno} assumerà i valori: + \funcdecl{int fchmod(int fd, mode\_t mode)} Analoga alla precedente, ma usa + il file descriptor \var{fd} per indicare il file. + + \bodydesc{Le funzioni restituiscono zero in caso di successo e -1 per + un errore, in caso di errore \var{errno} può assumere i valori: \begin{errlist} - \item \texttt{EPERM} Il filesystem non supporta la cancellazione di - directory, oppure la directory che contiene \var{dirname} ha lo sticky bit - settato e l'\textit{effective user id} del processo non corrisponde al - proprietario della directory. - \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory che - contiene la directory che si vuole cancellare, o non c'è il permesso di - attraversare (esecuzione) una delle directory specificate in - \var{dirname}. - \item \texttt{EBUSY} La directory specificata è la directory di lavoro o la - radice di qualche processo. - \item \texttt{ENOTEMPTY} La directory non è vuota. + \item[\macro{EPERM}] L'userid effettivo non corrisponde a quello del + proprietario del file o non è zero. \end{errlist} - ed inoltre anche \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT}, - \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, \macro{EROFS}. -\end{prototype} - - - + ed inoltre \macro{EROFS} e \macro{EIO}; \func{chmod} restituisce anche + \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOMEM}, + \macro{ENOTDIR}, \macro{EACCES}, \macro{ELOOP}; \func{fchmod} anche + \macro{EBADF}.} +\end{functions} +I valori possibili per \var{mode} sono indicati in +\tabref{tab:file_permission_const}. I valori possono esser combinati con l'OR +binario delle relative costanti simboliche, o specificati direttamente, come +per l'analogo comando di shell, con il valore numerico (la shell lo vuole in +ottale, dato che i bit dei permessi sono divisibili in gruppi di tre). Ad +esempio i permessi standard assegnati ai nuovi file (lettura e scrittura per +il proprietario, sola lettura per il gruppo e gli altri) sono corrispondenti +al valore ottale $0644$, un programma invece avrebbe anche il bit di +esecuzione attivo, con un valore di $0755$, se si volesse attivare il bit +\acr{suid} il valore da fornire sarebbe $4755$. -\subsection{Accesso alle directory} -\label{sec:file_dir_read} +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|c|l|} + \hline + \textbf{\var{mode}} & \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \macro{S\_ISUID} & 04000 & set user ID \\ + \macro{S\_ISGID} & 02000 & set group ID \\ + \macro{S\_ISVTX} & 01000 & sticky bit \\ + \hline + \macro{S\_IRWXU} & 00700 & l'utente ha tutti i permessi \\ + \macro{S\_IRUSR} & 00400 & l'utente ha il permesso di lettura \\ + \macro{S\_IWUSR} & 00200 & l'utente ha il permesso di scrittura \\ + \macro{S\_IXUSR} & 00100 & l'utente ha il permesso di esecuzione \\ + \hline + \macro{S\_IRWXG} & 00070 & il gruppo ha tutti i permessi \\ + \macro{S\_IRGRP} & 00040 & il gruppo ha il permesso di lettura \\ + \macro{S\_IWGRP} & 00020 & il gruppo ha il permesso di scrittura \\ + \macro{S\_IXGRP} & 00010 & il gruppo ha il permesso di esecuzione \\ + \hline + \macro{S\_IRWXO} & 00007 & gli altri hanno tutti i permessi \\ + \macro{S\_IROTH} & 00004 & gli altri hanno il permesso di lettura \\ + \macro{S\_IWOTH} & 00002 & gli altri hanno il permesso di scrittura \\ + \macro{S\_IXOTH} & 00001 & gli altri hanno il permesso di esecuzione \\ + \hline + \end{tabular} + \caption{I valori delle costanti usate per indicare i permessi dei file.} + \label{tab:file_permission_const} +\end{table} -Benché le directory siano oggetti del filesystem come tutti gli altri non ha -ovviamente senso aprirle come fossero dei file di dati. Può però essere utile -poterne leggere il contenuto ad esempio per fare la lista dei file che esse -contengono o ricerche sui medesimi. +Il cambiamento dei permessi di un file attraverso queste funzioni ha comunque +alcune limitazioni, provviste per motivi di sicurezza. Questo significa che +anche se si è proprietari del file non tutte le operazioni sono permesse, in +particolare: +\begin{enumerate} +\item siccome solo l'amministratore può impostare lo \textit{sticky bit}, se + l'userid effettivo del processo non è zero esso viene automaticamente + cancellato (senza notifica di errore) qualora sia stato indicato in + \var{mode}. +\item per via della semantica SVr4 nella creazione dei nuovi file, si può + avere il caso in cui il file creato da un processo è assegnato a un gruppo + per il quale il processo non ha privilegi. Per evitare che si possa + assegnare il bit \acr{sgid} ad un file appartenente a un gruppo per cui non + si hanno diritti, questo viene automaticamente cancellato (senza notifica di + errore) da \var{mode} qualora il gruppo del file non corrisponda a quelli + associati al processo (la cosa non avviene quando l'userid effettivo del + processo è zero). +\end{enumerate} + +Per alcuni filesystem\footnote{il filesystem \acr{ext2} supporta questa + caratteristica, che è mutuata da BSD.} è inoltre prevista una ulteriore +misura di sicurezza, volta a scongiurare l'abuso dei bit \acr{suid} e +\acr{sgid}; essa consiste nel cancellare automaticamente questi bit qualora un +processo che non appartenga all'amministratore scriva su un file. In questo +modo anche se un utente malizioso scopre un file \acr{suid} su cui può +scrivere, un'eventuale modifica comporterà la perdita di ogni ulteriore +privilegio. -Per accedere al contenuto delle directory si usano i cosiddetti -\textit{directory streams} (chiamati così per l'analogia con i file stream); -la funzione \texttt{opendir} apre uno di questi stream e la funzione -\texttt{readdir} legge il contenuto della directory, i cui elementi sono le -\textit{directory entry} (da distinguersi da quelle della cache di cui -parlavamo in \secref{sec:file_vfs}) in una opportuna struttura -\texttt{struct dirent}. +\subsection{La funzione \func{umask}} +\label{sec:file_umask} -(NdA Il resto va scritto!!! É noioso e lo farò più avanti). +Oltre che dai valori indicati in sede di creazione, i permessi assegnati ai +nuovi file sono controllati anche da una maschera di bit impostata con la +funzione \func{umask}, il cui prototipo è: +\begin{prototype}{stat.h} +{mode\_t umask(mode\_t mask)} + Imposta la maschera dei permessi dei bit al valore specificato da \var{mask} + (di cui vengono presi solo i 9 bit meno significativi). + + \bodydesc{La funzione ritorna il precedente valore della maschera. È una + delle poche funzioni che non restituisce codici di errore.} +\end{prototype} +Questa maschera è una caratteristica di ogni processo\footnote{è infatti + contenuta nel campo \var{umask} di \var{fs\_struct}, vedi + \figref{fig:proc_task_struct}.} e viene utilizzata per impedire che alcuni +permessi possano essere assegnati ai nuovi file in sede di creazione. I bit +indicati nella maschera vengono infatti esclusi quando un nuovo file viene +creato. + +In genere questa maschera serve per impostare un valore predefinito dei +permessi che ne escluda alcuni (usualmente quello di scrittura per il gruppo e +gli altri, corrispondente ad un valore di $022$). Essa è utile perché le +routine dell'interfaccia ANSI C degli stream non prevedono l'esistenza dei +permessi, e pertanto tutti i nuovi file vengono sempre creati con un valore di +$666$ (cioè permessi di lettura e scrittura per tutti, si veda +\tabref{tab:file_permission_const} per un confronto); in questo modo è +possibile cancellare automaticamente i permessi non voluti, senza doverlo fare +esplicitamente. -\subsection{La directory di lavoro} -\label{sec:file_work_dir} +In genere il valore di \func{umask} viene stabilito una volta per tutte al +login a $022$, e di norma gli utenti non hanno motivi per modificarlo. Se però +si vuole che un processo possa creare un file che chiunque possa leggere +allora occorrerà cambiare il valore di \func{umask}. -A ciascun processo è associato ad una directory nel filesystem che è chiamata -directory corrente o directory di lavoro (\textit{current working directory}) -che è quella a cui si fa riferimento quando un filename è espresso in forma -relativa (relativa appunto a questa directory). -Quando un utente effettua il login questa directory viene settata alla -cosiddetta \textit{home directory} del suo account, il comando \texttt{cd} -della shell consente di cambiarla a piacere, spostandosi da una directory ad -un'altra. Siccome la directory corrente resta la stessa quando viene creato -un processo figlio, la directory corrente della shell diventa anche la -directory corrente di qualunque comando da essa lanciato. +\subsection{Le funzioni \func{chown}, \func{fchown} e \func{lchown}} +\label{sec:file_chown} -Le funzioni qui descritte servono esaminare e cambiare la directory di lavoro -corrente. +Come per i permessi, il sistema fornisce anche delle funzioni che permettano +di cambiare utente e gruppo cui il file appartiene; le funzioni in questione +sono tre e i loro prototipi sono i seguenti: +\begin{functions} + \headdecl{sys/types.h} + \headdecl{sys/stat.h} + + \funcdecl{int chown(const char *path, uid\_t owner, gid\_t group)} + \funcdecl{int fchown(int fd, uid\_t owner, gid\_t group)} + \funcdecl{int lchown(const char *path, uid\_t owner, gid\_t group)} -\begin{prototype}{unistd.h}{char * getcwd (char * buffer, size\_t size)} - Restituisce il filename completo della directory di lavoro corrente nella - stringa puntata da \texttt{buffer}, che deve essere precedentemente - allocata, per una dimensione massima di \texttt{size}. Si può anche - specificare un puntatore nullo come \textit{buffer}, nel qual caso la - stringa sarà allocata automaticamente per una dimensione pari a - \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta - del pathname altrimenti. In questo caso si deve ricordare di disallocare la - stringa una volta cessato il suo utilizzo. + Le funzioni cambiano utente e gruppo di appartenenza di un file ai valori + specificati dalle variabili \var{owner} e \var{group}. - La funzione restituisce il puntatore \texttt{buffer} se riesce, - \texttt{NULL} se fallisce, in quest'ultimo caso la variabile - \texttt{errno} è settata con i seguenti codici di errore: + \bodydesc{Le funzioni restituiscono zero in caso di successo e -1 per + un errore, in caso di errore \var{errno} viene impostata ai valori: \begin{errlist} - \item \texttt{EINVAL} L'argomento \texttt{size} è zero e \texttt{buffer} non - è nullo. - \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della - lunghezza del pathname. - \item \texttt{EACCESS} Manca il permesso di lettura o di ricerca su uno dei - componenti del pathname (cioè su una delle directory superiori alla - corrente). + \item[\macro{EPERM}] L'userid effettivo non corrisponde a quello del + proprietario del file o non è zero, o utente e gruppo non sono validi \end{errlist} -\end{prototype} + Oltre a questi entrambe restituiscono gli errori \macro{EROFS} e + \macro{EIO}; \func{chown} restituisce anche \macro{EFAULT}, + \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOMEM}, \macro{ENOTDIR}, + \macro{EACCES}, \macro{ELOOP}; \func{fchown} anche \macro{EBADF}.} +\end{functions} -Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} -fatta per compatibilità all'indietro con BSD, che non consente di specificare -la dimensione del buffer; esso deve essere allocato in precedenza ed avere una -dimensione superiore a \texttt{PATH\_MAX} (di solito 256 byte, vedi -\secref{sec:xxx_limits}); il problema è che in Linux non esiste una dimensione -superiore per un pathname, per cui non è detto che il buffer sia sufficiente a -contenere il nome del file, e questa è la ragione principale per cui questa -funzione è deprecata. +In Linux soltanto l'amministratore può cambiare il proprietario di un file, +seguendo la semantica di BSD che non consente agli utenti di assegnare i loro +file ad altri (per evitare eventuali aggiramenti delle quote). +L'amministratore può cambiare il gruppo di un file, il proprietario può +cambiare il gruppo dei file che gli appartengono solo se il nuovo gruppo è il +suo gruppo primario o uno dei gruppi a cui appartiene. -Una seconda funzione simile è \texttt{char * get\_current\_dir\_name(void)} -che è sostanzialmente equivalente ad una \texttt{getcwd(NULL, 0)}, con la sola -differenza che essa ritorna il valore della variabile di ambiente -\texttt{PWD}, che essendo costruita dalla shell può contenere anche dei -riferimenti simbolici. - -Come già detto in unix anche le directory sono file, è possibile pertanto -riferirsi ad esse tramite il file descriptor dell'interfaccia a basso livello, -e non solo tramite il filename; per questo motivo ci sono due diverse funzioni -per cambiare directory di lavoro. - -\begin{prototype}{unistd.h}{int chdir (const char * pathname)} - Come dice il nome (che significa \textit{change directory}) questa funzione - serve a cambiare la directory di lavoro a quella specificata dal pathname - contenuto nella stringa \texttt{pathname}. -\end{prototype} - -\begin{prototype}{unistd.h}{int fchdir (int filedes)} - Analoga alla precedente, ma usa un file descriptor invece del pathname. - - Entrambe le funzioni restituiscono zero in caso di successo e -1 per un - errore, in caso di errore \texttt{errno} viene settata secondo i codici di - errore standard di accesso ai file (trattati in dettaglio in - \secref{sec:file_access_control}) ai quali si aggiunge il codice - \texttt{ENOTDIR} nel caso il \texttt{filename} indichi un file che non sia - una directory. -\end{prototype} +La funzione \func{chown} segue i link simbolici, per operare direttamente su +un link simbolico si deve usare la funzione \func{lchown}.\footnote{fino alla + versione 2.1.81 in Linux \func{chown} non seguiva i link simbolici, da + allora questo comportamento è stato assegnato alla funzione \func{lchown}, + introdotta per l'occasione, ed è stata creata una nuova system call per + \func{chown} che seguisse i link simbolici.} La funzione \func{fchown} opera +su un file aperto, essa è mutuata da BSD, ma non è nello standard POSIX. +Un'altra estensione rispetto allo standard POSIX è che specificando -1 come +valore per \var{owner} e \var{group} i valori restano immutati. + +Quando queste funzioni sono chiamate con successo da un processo senza i +privilegi di root entrambi i bit \acr{suid} e \acr{sgid} vengono +cancellati. Questo non avviene per il bit \acr{sgid} nel caso in cui esso +sia usato (in assenza del corrispondente permesso di esecuzione) per indicare +che per il file è attivo il \textit{mandatory locking}. +%La struttura fondamentale che contiene i dati essenziali relativi ai file è il +%cosiddetto \textit{inode}; questo conterrà informazioni come il +%tipo di file (file di dispositivo, directory, file di dati, per un elenco +%completo vedi \ntab), i permessi (vedi \secref{sec:file_perms}), le date (vedi +%\secref{sec:file_times}). +\subsection{La funzione \func{chroot}} +\label{sec:file_chroot} + +Benché non abbia niente a che fare con permessi, utenti e gruppi, questa +funzione viene usata spesso per restringere le capacità di acccesso di un +programma ad una sezione limitata del filesystem, per cui ne parleremo in +questa sezione. + +Come accennato in \secref{sec:proc_fork} ogni processo oltre ad una directory +di lavoro corrente, ha anche una directory radice,\footnote{entrambe sono + contenute in due campi di \var{fs\_struct}, vedi + \figref{fig:proc_task_struct}.} che è la directory che per il processo +costituisce la radice dell'albero dei file e rispetto alla quale vengono +risolti i pathname assoluti (si ricordi quanto detto in +\secref{sec:file_organization}). La radice viene eredidata dal padre per ogni +processo figlio, e quindi di norma coincide con la \file{/} del sistema. + +In certe situazioni però per motivi di sicurezza non si vuole che un processo +possa accedere a tutto il filesystem; per questo si può cambiare la directory +radice con la funzione \func{chroot}, il cui prototipo è: +\begin{prototype}{unistd.h}{int chroot(const char *path)} + Cambia la directory radice del processo a quella specificata da + \param{path}. + +\bodydesc{La funzione restituisce zero in caso di successo e -1 per + un errore, in caso di errore \var{errno} viene impostata ai valori: + \begin{errlist} + \item[\macro{EPERM}] L'userid effettivo del processo non è zero. + \end{errlist} + ed inoltre \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT}, + \macro{ENOMEM}, \macro{ENOTDIR}, \macro{EACCES}, \macro{ELOOP}; + \macro{EROFS} e \macro{EIO}.} +\end{prototype} +\noindent in questo modo la directory radice del processo diventerà +\param{path} (che ovviamente deve esistere) ed ogni pathname assoluto sarà +risolto a partire da essa, rendendo impossibile accedere alla parte di albero +sovrastante; si ha cioè quella che viene chiamata una \textit{chroot jail}. + +Solo l'amministratore può usare questa funzione, e la nuova radice, per quanto +detto in \secref{sec:proc_fork}, sarà ereditata da tutti i processi figli. Si +tenga presente che la funzione non cambia la directory di lavoro corrente, che +potrebbe restare fuori dalla \textit{chroot jail}. + +Questo è il motivo per cui la funzione è efficace solo se dopo averla eseguita +si cedono i privilegi di root. Infatti se in qualche modo il processo ha una +directory di lavoro corrente fuori dalla \textit{chroot jail}, potrà comunque +accedere a tutto il filesystem usando pathname relativi. + +Ma quando ad un processo restano i privilegi di root esso potrà sempre portare +la directory di lavoro corrente fuori dalla \textit{chroot jail} creando una +sottodirectory ed eseguendo una \func{chroot} su di essa. Per questo motivo +l'uso di questa funzione non ha molto senso quando un processo necessita dei +privilegi di root per le sue normali operazioni. + +Un caso tipico di uso di \func{chroot} è quello di un server ftp anonimo, in +questo caso infatti si vuole che il server veda solo i file che deve +trasferire, per cui in genere si esegue una \func{chroot} sulla directory che +contiene i file. Si tenga presente però che in questo caso occorrerà +replicare all'interno della \textit{chroot jail} tutti i file (in genere +programmi e librerie) di cui il server potrebbe avere bisogno. + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: