Cours 7 : Privilèges, Utilisateurs et Fichiers

Mots de passe

/etc/passwd : ne contient plus de mdp cryptés, car tout le monde pouvait récupérer le fichier essayer de cracker les mdp (mots de passe) par force brute.

⟶ les mdp sont dans /etc/shadow : il faut l’accès root

Lorsqu’on initialise son mdp, on utilise une fonction de cryptage, et l’image de notre mdp par cette fonction est stockée dans /etc/shadow : puis, à chaque fois qu’on se logue : l’image de l’input est comparé à cette image.

/bin/false : on n’est pas censé utiliser ce compte avec un login.

Utilisateurs virtuels : root, daemons, etc…

Groupes :

Chaque utilisateur appartient à un groupe primaire, et éventuellement des groupes supplémentaires.

Les groupes :

  • primaires sont dans /etc/passwd
  • supplémentaires dans /etc/groups

Commande id : affiche tous les ids des groupes auxquels l’utilisateur courant appartient.

Utilisateurs

getuid : id de l’utilisateur réel, i.e celui qui a lancé le processus.

geteuid : id de l’utilisateur effectif, i.e celui qui détermine les droits sur le processus.

En remplaçant u par g ⟶ idem pour les groupes

NB :

  • Normalement, ce sont les mêmes.

    • Mais pas toujours : quand on veut changer son mdp (sans être root), par ex, car on n’a pas accès à /etc/shadow
    • Par contre, quand on fait un sudo : c’est carrément l’utilisateur réel qui devient le root

Fichiers

Sur UNIX :

Fichier :

toutes les entrées/sorties, qui ont des opérations de lecture et d’écriture. Selon le type du fichier, la relation entre read et write est différente

  • ex: pour certains fichiers (buffers temporaires, connexion réseau, etc…) : écriture “destructive”

Exs de fichiers :

  • un fichier réel sur le disque dur
  • buffer - zone de mémoire temporaire
  • stdin / stdout
  • imprimantes / CDs / périphériques
  • processus

Avec read/write : l’interface est la même pour toutes les lectures/écritures sur tous les fichiers : mais le noyau renvoie sur un pilote qui convient la lecture/l’écriture selon le fichier.

NB : le terme “système de fichiers” est ambigu : c’est

  • la gestion des fichiers sur une partition
  • ou : l’ensemble des fichiers.s

Entrées/Sorties :

Deux aspects à considérer :

  1. l’aspect statique :

    • stockage des données au delà de la vie d’un processus donné
  2. La gestion des

1. Système de fichiers

C’est une arborescence, dont :

  • les noeuds internes sont les dossiers
  • les feuilles sont les fichiers

Chemin absolu/relatif : le dossier actuel est un attribut du processus ⟶ le processus fils hérite de celui-ci, par un fork

ex :

void main(){
  chdir("tmp"); // va dans tmp
  system("cat toto");
}

Après avoir exécuté ce fichier, le shell reste dans son répertoire de départ.

void main(){
  unlink("tmp/toto"); // supprime le fichier -> interprété de manière relative au dossier actuel, indépendamment de l'endroit où se trouve le programme
}

Les fonctions du système font l’interprétation (caractère relatif des chemins) pour nous.

Métadonnées VS données

Les métadonnées d’un fichier (propriétaire, droits d’accès, etc…, mais pas son nom) sont stockées de manière particulière :

un partie des blocs du disque dur est dédiée au stockage des métadonnées, alors qu’une autre stocke les fichiers proprement dits.

Un fichier = une référence

ls -i :

affichage (en premier) en plus d’un numéro inoeud (inode)

Il y a 3 références pour un répertoire donné : . dans le répertoire courant, nom dans répertoire parent, .. dans les répertoires enfants.

Toutes ces références ont le même inode.

stat repertoire :

affichage des métadonnées.

ln toto tata :

création d’un lien de toto vers tata : ils ont alors le même numéro inoeud (inode).

Inoeud : normalement, ne se voit pas, sauf des cas particuliers :

ex :

  • Erreur : “lost inode”

Noms de fichiers

Un inode existe tant qu’il y a une référence vers lui dans une entrée quelconque.

⟶ existence de la métadonnée Links : nombre de liens pointant vers cet inoeud.

unlink : en C, supprime les liens vers l’inoeud.

  • Si on fait rm tata : le lien toto existe toujours.
  • Puis : quand on supprime toto : le dernier lien vers l’inoeud est supprimé ⟶ on ne peut plus accéder au fichier
Un répertoire :

un fichier qui contient une liste de paires (nom, inoeud)

Quand on fait ls : la liste est obtenue, puis un stat est fait sur chaque fichier pour obtenir les métadonnées.

UGO

User - Group - Others : droits rwx

Il y a au total 12 bits pour les droits d’accès : les 9 bits ordinaires rwx (pour l’utilsateur, son groupe primaire ET ses groupes supplémentaires, et les autres)

Pour les fichiers :

chmod a+r fichier :

donner tous les droits de lecture de fichier (o : others, u : user, a : all)

chmod u-r fichier :

m’enlever les droits de lecture de fichier

NB : un fichier peut être lisible pour les autres sans l’être pour moi.

Pour les dossiers :

  • le bit r : droit de lire la liste des fichiers du dossier

    • ex : ls requiert ce droit
  • le bit r : droit de modifier la liste des fichiers du dossier ⟶ modifier/supprimer les fichiers qui y sont
  • le bit x : droit de faire un stat, et l’appel système chdir dans ce dossier

    • NB : ce droit est nécessaire pour le traverser.

Ex :

Si on fait

chmod -x repertoire

⟶ on peut faire un ls, mais pas un ls -l

⟶ on ne peut faire un cd : chdir : droit refusé

  • le bit s : droit x + de faire un setuid

    • les fichiers créés dans le répertoire appartiennent au groupe du répertoire.
  • le bit S : de faire un setuid seulement

(s’affiche en rouge avec ls)

Quand un processus crée un fichier, normalement : le groupe du processus = le groupe du fichier créé

  • Sticky bit : sémantique pas très bien définie, mais typiquement : permet de créer des fichiers personnels dans le répertoire, sans toucher à ceux des autres

    • ex : le répertoire /tmp/ a le sticky bit

Descripteurs

Un entier qui représente un accès à un fichier.

Un même fichier peut avoir différents descripteurs.

open("fichier") :

si la lecture réussit, renvoie le descripteur du fichier.

read(descripteur, adresse, nb_octets_souhaites :

lire nb_octets_souhaites et les renvoyer à l’adresse adresse (renvoie 0 si on arrive à la fin du fichier).

Plusieurs processus peuvent écrire en même temps dans un même fichier

main(){
char c;
int f = open("foo", O_RDONLY);
while(read(f,&c,1)){
  putchar(c);
  fflush(sdtout);
  sleep(2);
}
}

Dans le noyau :

inoeud, node d’accès, position dans le fichier

void do_read(char *name, int fd)
{
  char c;
while(read(f,&c,1)){
  printf("%s : %c\n", name, c);
  sleep(2);
}
}
main(){
int fd = open("foo", O_RDONLY);
int pid = fork();
if (pid) do_read("parent", fd);
else {sleep(1); do_read("child", fd))}
}

Lecture tour à tour du parent et du fils dans le même fichier : alternance père/fils de l’affichage de la lecture des caractères du fichier.

  • le père lit le premier caractère
  • le fils le second
  • le père le troisième
  • le fils le quatrième

NB : si on fait open après fork : il y a répétition des caractères du fichier lu :

  • le père lit le premier caractère
  • le fils le premier
  • le père le second
  • le fils le second

0xxx : en octal

umask :

affichage des droits enlevés aux fichiers créés par les processus avec open (par défaut):

  • ex : si umask affiche 0002 : on retire les droits d’exécution aux autres.

Descripteurs standard :

  • 0 : entrée standard
  • 1 : sortie standard
  • 2 : sortie erreur
dup(nombre) :

crée un nouveau descripteur dupliqué (pointant vers le même fichier) du descripteur numéro nombre

ex :

  • g = dup(3) : duplique le descripteur 3
dup2(nombre1, nombre2) :

fait pointer le descripteur nombre2 vers le même fichier que celui vers lequel pointe nombre1

NB : c’est ce qui est utilisé par le shell quand on fait echo xxx > sortie par exemple.


Mini-Shell : PIPE

  • Père :
    • pipefd[0]
    • pipefd[1]

⇓ 1

  • Fils 1 :
    • pipefd[0]
    • pipefd[1]

  • Fils 2:
    • pipefd[0]
    • pipefd[1]

⇓ 0


ANSI-C :

standard C valable sur n’import quel système.


man :
  • Section 2 : fonctions faisant des appels système.
  • Section 3 : fonction ayant recours à des fonctions de de la section 2 (printf, etc…)

```{c id:”iw24ujr0”} char *t[100]; // sur la pile char *s = malloc(100); // sur le tas

scanf(“%100s”, t); // 100 octets max scanf(“%ms”, &t); // on donne un pointeur ⟶ alloue la place nécessaire

```

cf.

  • asprintf : pour allocation variable
  • snprintf : taille limite en octet spécifiée
fopen :

fait open, et crée un FILE avec ce descripteur, et en fait une string.

strace / ltrace :

affichage des appels systèmes

NB : printf, etc… : économisent les appels noyaux avec un système de tamponnage (printf sort q’une fois qu’on a fait un retour à la ligne)

Pour vider le tampon : fflush(stdout)

voir aussi :

  • setlinebuf(f)
  • setbuf(f, NULL)
    • ex: setbuf(stdout, NULL) : mode non temponné

Threads

Structure pthread_t

pthread_create(&t1, NULL, titi, NULL)

Quand on compile avec gcc : le faire avec l’option -pthread

Pas de hiérarchie chez les threads : un thread lancé après un autre a la même “priorité” que celui-ci.

pthread_join :

équivalent de wait, mais pour les threads

pthread_detach :

si le thread termine, il ne devient pas zombie (il est directement effacé de la mémoire) : mais attention, on ne peut plus faire de pthread_join.

fork VS threads :

  • fork pour avoir des processus totalement indépendants (si le fils d’un thread est tué, tout le monde l’est)
  • threads : mémoire partagée entre tous les threads.

    • ex: Firefox utilise beacoup de threads : si il y a un plugin qui bogue ⟶ ça tue tout le navigateur entier.
    • exit dans un thread : tue tous les autres.
  • NB: exit dans le main tue tous le processus, peu importe qu’il reste des threads ou non.

  • Attention : certains appels suystèmes ne peuvent êtres appelés deux fois en parallèle dans un même processus.

Sémaphores :

init(s, 1)

wait(s) :

attend tant que s=0

post(s) :

passe le flambeau (libère le créneau).

Leave a Comment