Connexion sécurisé avec ssh

Transcription

Connexion sécurisé avec ssh
Connexion sécurisé avec ssh
Éric Doutreleau <[email protected]>
30 octobre 2003
Résumé
Ce document décrit l’utilisation des logiciels ”ssh” à l’INT. Il n’est en rien une présentation complète de ces logiciels mais se borne à donner quelques informations pour aider à
leurs bonne utilisations.
Table des matières
1 Préambule
2
2 Introduction
2
3 Versions disponibles
2
4 Principes de fonctionnement.
3
5 Ne plus rentrer son mot de passe
5.1 Première étape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 Deuxième étape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3 Étape finale : la connexion . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
4
4
6 Ne plus rentrer la pass phrase.
6.1 Problématique . . . . . . .
6.2 Principes . . . . . . . . .
6.3 Mise en place pratique . .
6.4 Utilisation . . . . . . . . .
4
4
5
5
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7 Le client Windows
7.1 Génération des clés . . . . .
7.2 Configuration de l’agent ssh
7.3 Configuration de putty . . .
7.4 Importation des clés . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
. 8
. 10
. 10
. 10
1
2
1 Préambule
8 SSH le tunnel du pauvre
8.1 Principe . . . . . . . . . . .
8.2 Exemple sous linux . . . . .
8.3 Exemple sous windows . . .
8.3.1 Création des tunnels
8.3.2 Création du tunnel .
8.3.3 Telnet . . . . . . . .
8.3.4 ftp . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9 Utilisation à l’INT
.
.
.
.
.
.
.
.
.
.
.
.
.
.
19
19
20
20
21
22
22
22
25
1 Préambule
Vous trouverez ci dessous des pointeurs vers des formats de documents plus appropriés pour
des consultations ”hors Web”
Texte http://www.int-evry.fr/mci/user/doutrele/ssf/ssf.txt
Postscript http://www.int-evry.fr/mci/user/doutrele/ssf/ssf.ps
PDF http://www.int-evry.fr/mci/user/doutrele/ssf/ssf.pdf
2 Introduction
La possibilité de travailler ”à distance” a toujours été une fonctionnalité très appréciée des
utilisateurs de machines UNIX. Cela est traditionnellement possible suivant plusieurs modes de
connexion.
– telnet
– rlogin
– ftp
Le gros problème avec ces modes de connexions c’est que l’authentification que vous devez
fournir pour vous connecter sur la machine distante circule ”en clair” sur le réseau. C’est à
dire que n’importe quelle personne qui a accès au réseau où vous vous trouver peut à l’aide de
programmes appelés ”sniffeurs” récupéré votre mot de passe.
Cela est tout de même relativement gênant
3 Versions disponibles
Il existe un certain nombres de logiciels utilisant les connexions sécurisées.
Une version UNIX openssh Cette version contient les partie serveurs et clientes de ssh
Une version Windows putty Cette version contient une partie cliente pour Windows.
Eric Doutreleau
3
4 Principes de fonctionnement.
4 Principes de fonctionnement.
ssh est basé sur un mécanisme de clé publique clé privé. Ces deux clés sont ”mathématiquement” reliée. Typiquement la clé publique sert à crypter un message et la clé privé sert à le
décrypter. Prenons un exemple.
Je suis sur la machine rezo et je veux me connecter sur la machine elaphe. Je tape
ssh elaphe
J’obtiens alors le message suivant :
The authenticity of host ’elaphe (157.159.15.20)’ can’t be established.
RSA key fingerprint is
d7 :69 :a7 :db :89 :71 :ff :13 :54 :ce :b4 :0d :55 :f6 :a9 :04.
Are you sure you want to continue connecting
(yes/no) ? yes
Comme je ne me suis jamais connecté sur elaphe je ne connais pas sa clé publique. Je vais
donc répondre yes. J’obtiens alors les messages suivants :
Warning : Permanently added ’elaphe,157.159.15.20’ (RSA)
to the list of known hosts.
[email protected]’s password :
Je rentre alors mon mot de passe qui va être crypté avec la clé publique de la machine elaphe.
La machine elaphe va utilisé sa clé privée pour décrypter le mot de passe et ainsi va pouvoir
vérifier mon identité.
On ne peux donc pas me ”sniffer” mon mot de passe.
Si je me Re connecte sur elaphe j’obtiens immédiatement la ligne
[email protected]’s password :
5 Ne plus rentrer son mot de passe
On peut aller encore plus loin et générer des clés d’identification personnelle. Le principe est
de générer une clé associée à un texte et de propager la partie publique de la clé sur toutes les
machines auxquelles vous souhaitez vous connecter.
Voici comment il faut procéder si vous voulez vous connecter d’une machine rezo sur la
machine elaphe.
5.1 Première étape
Sur la machine rezo il faut générer les clés d’authentification. Ces clés d’authentifications
sont liées à un compte particulier. On va donc créer ces clés pour notre compte courant. Nous
allons donc travailler avec le compte grocanar. Cela se fait en tapant la commande
Eric Doutreleau
4
5.2 Deuxième étape
ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/grocanar/.ssh/id_rsa) :
Enter passphrase (empty for no passphrase) :
On doit donc alors entrer une ”passphrase” qui va protéger la clé privée générée. Il faut que
cette phrase ait au moins 20 caractères.
Même si il est possible de ne pas rentrer cette pass phrase cela n’est pas du tout conseillé. En
effet c’est le seul moyen de protéger vos clés si quelqu’un arrive à accéder à votre compte.
Après avoir tapé deux fois cette phrase on obtient alors les messages suivants :
Enter same passphrase again :
Your identification has been saved in /home/grocanar/.ssh/id_rsa.
Your public key has been saved in
/home/grocanar/.ssh/id_rsa.pub.
The key fingerprint is :
ea :9c :c8 :0f :89 :5a :12 :52 :81 :3e :c1 :21 :0e :fd :37 :07
[email protected]
On voit donc que le clé privée est sauvegardée dans le fichier .ssh/id_rsa et la clé publique
dans le fichier .ssh/id_rsa.pub
5.2 Deuxième étape
Sur la machine elaphe on va créer le fichier authorized_keys dans le répertoire .ssh et l’on
va y rajouter la clé publique de la machine rezo avec un simple éditeur de texte. On complique
un peu la chose en utilisant un compte différent sur le machine elaphe. en effet on va utiliser le
compte doutrele
5.3 Étape finale : la connexion
On va donc maintenant se connecter sur la machine elaphe depuis la machine elaphe en
tapant
ssh doutrele@elaphe
On obtient alors le message suivant :
Enter passphrase for key ’/home/grocanar/.ssh/id_rsa’ :
On rentre alors la ”pass phrase” que l’on a utilisé pour ”protéger” la clé privée.
6 Ne plus rentrer la pass phrase.
6.1 Problématique
Dans la manipulation décrite ci dessus on a perdu en simplicité d’utilisation. En effet au lieu
de rentrer son login et mot de passe, on dois donner son login et sa “pass phrase”. Cette opération
est bien plus longue que l’opération habituelle.
Eric Doutreleau
5
6.2 Principes
Il existe un moyen de s’affranchir de ces opérations qui peuvent s’avérer fastidieuse si on
multiplie les connexions distantes : ssh-agent et sh-add
6.2 Principes
ssh-agent est un démon dont le rôle est :
– Intercepter la clé privée lorsque le programme ssh-add l’aura décryptée en utilisant la
passphrase que vous allez rentrer une et une seule fois.
– La transmettre à tous programmes dont il sera l’ancêtre et qui le lui demandera. On verra
que cette contrainte de “descendance UNIX” amène a certaines contraintes de mise en
place.
Ainsi vous n’avez plus qu’a rentrer une seule fois votre passphrase à votre connexion initiale sur
la machine et vous n’avez plus besoin de la rentrer lors de vos connexions sur d’autres machines.
6.3 Mise en place pratique
Dans cet exemple de mise en place je prends l’exemple d’une machine Linux utilisant une
distribution RedHat 7.3 ou ultérieur avec un environnement Gnome. Cela donne néanmoins une
idée générale sur la manière de procéder.
Aller dans le menu principal symbolisé par un chapeau rouge.
Sélectionnez le menu Préférences => Préférences supplémentaires => Sessions
On obtient alors une fenêtre comme ci dessous (voir 1)
Il faut alors cliquer sur le menu Programme au démarrage.
On obtient alors la fenêtre suivante (voir 2)
Il faut alors rentrer la commande /usr/bin/ssh-add dans le champs Commande de démarrage et ajuster la priorité ( champs ordre ) afin que cette commande ait la plus grande valeur. Une
bonne valeur est 70. On obtient alors la fenêtre suivante (voir3)
6.4 Utilisation
L’utilisation est alors très simple. A la connexion une fenêtre s’ouvre et demande de rentrer
la ”passphrase” (voir 4).
Une fois celle ci tapée la session se déroule normalement et on ne demandera plus la passphrase ni de mot de passe pour toutes les connexions sur les machines où l’on a propagé sa clé
publique.
7 Le client Windows
On pourra trouver le client Windows sur le serveur FTP de l’int à l’url suivante :
ftp://ftp.int-evry.fr/pub/local/ssh
Il suffit alors de récupérer le fichier putty-0.53b-installer.exe et de l’éxécuter. Ce programme
va installer un ensemble de programme.
Eric Doutreleau
6
7 Le client Windows
F IG . 1 – Session
F IG . 2 – Programme au démarrage
Eric Doutreleau
7
7 Le client Windows
F IG . 3 – configuration
F IG . 4 – Demande de la passphrase
Eric Doutreleau
8
7.1 Génération des clés
F IG . 5 – Génération des clés Etape1
putty un émulateur terminal compatible ssh
puttygen Un générateur de clé
psftp un client ftp compatible ssh
pageant un équivalent à ssh-agent
7.1 Génération des clés
La génération des clés se fait avec puttygen.
On lance le logiciel et on obtient la fenêtre suivante (voir 5)
On doit alors générer la clé en faisant bien attention de générer une clé SSH2(DSA) de 1024
bits. On clique alors sur Generate.
On obtient alors la fenêtre suivante (voir 6)
Il faut alors :
Eric Doutreleau
9
7.1 Génération des clés
F IG . 6 – Génération des clés Etape 2
Eric Doutreleau
10
7.2 Configuration de l’agent ssh
– copier et coller dans le fichier authorized_keys comme on a vu precedement pour unix (
voir 5.2). En particulier notez bien que l’indication donné par putty est fausse. Le fichier à
modifier est authorized_keys et non pas authorized_keys2
– Entrez une pass phrase pour protéger sa clé privée
– Sauvegardez ses clés publiques et privées.
On en a fini avec ce programme
7.2 Configuration de l’agent ssh
l’agent ssh est le logiciel pageant. Quand on lance celui ci il va se nicher dans la barre des
applications. Il faut alors aller cliquer dessus pour l’utiliser. On obtient alors la fenêtre suivante
(voir 7)
On clique alors sur Add key et on ajoute la clé privé que l’on a précedement sauvegardé. On
obtient alors la fenêtre suivante (voir 8)
Il faut donc alors rentrez la pass-phrase qui protège notre clé privée (voir 9).
7.3 Configuration de putty
On va maintenant passer à la configuration de putty. Il faut noter qu’il est préférable de lancer
putty à partir de pageant.
On configure d’abord le protocole ssh utilisé (voir 10)
Puis la clé utilisée (voir11 )
Voici alors la fenêtre de connexion de putty (voir 12)
On se connecte alors au serveur sans rentrer son mot de passe.
Ouf ! ! !
Il est préférable de sauvegarder la configuration que l’on va appeler comme le serveur sur
lequel on se connecte ; On va donc sauvegarder tout cela dans la configuration elaphe. (voir13)
7.4 Importation des clés
Il peut être intéréssant de ne pas multiplier le couple de clés privées publiques sur les différents systèmes sur lesquelles on va travailler. En particulier si on doit travailler sous windows et
linux depuis la même machine il est un peu ridicule de générer deux couples de clés. On va donc
montrer ici comment importer dans puttygen la clé privé précédement généré avec openssh.
On lance puttygen et on obtient la fenêtre de gestion de clé (voir)
Il suffit alors de cliquer sur load. On charge alors le fichier la clé privée générée par openssh
que l’on aura préalablement transféré par un moyen adéquat et alors on obtient une clé privé tout
a fait utilisable dans putty comme montrée précedement.
Eric Doutreleau
11
7.4 Importation des clés
F IG . 7 – Ajout de clé
Eric Doutreleau
12
7.4 Importation des clés
F IG . 8 – passphrase
Eric Doutreleau
13
7.4 Importation des clés
F IG . 9 – etape finale
Eric Doutreleau
14
7.4 Importation des clés
F IG . 10 – protocole ssh
Eric Doutreleau
15
7.4 Importation des clés
F IG . 11 – clé utilisée
Eric Doutreleau
16
7.4 Importation des clés
F IG . 12 – Fenêtre de connexion de putty
Eric Doutreleau
17
7.4 Importation des clés
F IG . 13 – puttysave
Eric Doutreleau
18
7.4 Importation des clés
F IG . 14 – importation de clé
Eric Doutreleau
19
8 SSH le tunnel du pauvre
F IG . 15 – tunnel
8 SSH le tunnel du pauvre
SSH est souvent appelé le ”tunnel du pauvre” car il permet à un utilisateur donné de pallier
pour la majorité des fonctionnalités à l’usage d’un VPN.
8.1 Principe
On part du principe que l’on a acces a une connexion sur un serveur ssh accessible depuis sa
machine et que l’on veut acceder à un service sur son réseau interne mais que le firewall l’interdit
directement pour des raisons de sécurité.
On va pouvoir grace à ssh ”contourner” cette interdiction mais en toute sécurité.
Ce n’est donc pas un contournement de la sécurité.
Voici ce qui se passe quand un portable sur internet crée un tunnel sécurisé depuis internet
pour accéder à un serveur FTP sur l’intranet (voir15)
On procéde en deux étapes.
– On crée un tunnel ssh entre le portable et le serveur ssh librement accessible.
Eric Doutreleau
20
8.2 Exemple sous linux
– On utilise un client FTP ”classique” pour accéder au serveur FTP qui n’est pas directement
accessible et on a tout le confort ”comme si on y accédait directement”.
Nous allons maintenant donner deux exemples de mise en place.
8.2 Exemple sous linux
Un petit exemple étant plus parlant qu’une grande explication voila ce que nous allons faire.
Nous imaginons qu’un utilisateur nomade a besoin d’acceder à un serveur qui se trouve dans
l’INT, par exemple pollux depuis son portable qui s’appelle rezo. Evidement l’adminstrateur ne
tolère pas à juste titre que des connexions passent à travers internet sur cette machine.
Par contre Il peut se connecter en ssh sur la machine elaphe depuis n’importe quelle point de
l’internet.
On va donc creer un tunnel ssh entre la machine rezo et elaphe afin de pouvoir se connecter en
telnet sur pollux. Evidement il faut que le réseau entre la machine elaphe et pollux soit ”sécurisé”
pour que la démonstration soit valable.
On tape donc dans une fenêtre la commande suivante
ssh -N -L2023 :pollux.int-evry.fr :23 [email protected]
Si on a scrupuleusement suivi les directives présentées dans les chapitres précédents ( et si
cela fonctionne ) on ne doit recevoir aucun message. Le tunnel est en place. On remarque que
le port local du tunnel est 2023 . On ne peut en effet créer de tunnel avec un numéro de port
inférieur à 1024 si on est pas le super utilisateur.
On tape alors sur la machine locale
telnet 127.0.0.1 2023
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is ’^]’.
SunOS 5.7
login : doutrele
Password : *********
Last login : Mon Nov 17 17 :16 :45 from elaphe.int-evry.
Sun Microsystems Inc. SunOS 5.7 Generic October 1998
/sim/mci/doutrele
<pollux.doutrele : 1>
On a pu donc accéder au service telnet sur une machine qui n’était pas accessible directement
et en toute sécurité.
8.3 Exemple sous windows
Nous allons utiliser la configuration précédente sauvegardée sous le nom d’elaphe et y rajouter deux tunnels.
Eric Doutreleau
21
8.3 Exemple sous windows
F IG . 16 – tunnel windows etape 1
– Un tunnel pour faire du FTP sur la machine pollux
– Un tunnel pour faire du telnet sur la machine pollux
Voici les différents étapes
8.3.1 Création des tunnels
On crée les tunnels de la façon suivante : (voir)
– Il faut choisir un port local : 2021
– On choisit la destination pollux.int-evry.fr :21
– On coche local
– On clique sur Add
– On répete la même opération pour le tunnel pour telnet
– On sauvegarde la configuration dans le menu Session
Eric Doutreleau
22
8.3 Exemple sous windows
F IG . 17 – tunnel windows etape 2
8.3.2 Création du tunnel
Une fois configuré on va lancer pageant. On effectue les opérations decrites auparavant. (voir
7.2). On lance alors la session elaphe. Si tout à été bien configuré auparavant on obtient la fenêtre
suivante : (voir 17)
Le tunnel est crée. On va pouvoir l’utiliser.
8.3.3 Telnet
On lance le telnet comme ci dessous (voir 18)
Comme on le voit on se connecte au port local du tunnel. En l’occurence c’est le port 2023.
On obtient alors la fenêtre suivante : (voir19 )
Comme vous le constatez on s’est connecté en telnet sur python.
8.3.4 ftp
on va utiliser le logiciel filezilla. Celui nécéssite quand même une certaine configuration. On
va donc lancer le gestionnaire de site sur de filezilla. On obtient la fenêtre suivante : (voir 20)
On constate qu’on rentre l’adresse de l’extrémité locale du tunnel ssh comme adresse de
destination. En l’occurence localhost pour la nom de machine et 2021 pour le port. On clique
Eric Doutreleau
23
8.3 Exemple sous windows
F IG . 18 – tunnel windows telnet etape 1
F IG . 19 – tunnel windows telnet etape 2
Eric Doutreleau
24
8.3 Exemple sous windows
F IG . 20 – tunnel windows ftp etape 1
Eric Doutreleau
25
9 Utilisation à l’INT
F IG . 21 – tunnel windows ftp etape 2
alors sur le bouton Avancé. On obtient alors la fenêtre suivante : (voir 21)
On indique alors qu’on veut utiliser le mode passif pour se connecter. Tout est alors prêt.
On lance filezilla en sélectionnant le site que l’on vient de sauvegarder et on obtient la fenêtre
suivante : (voir )
Cela fonctionne ! ! !.
9 Utilisation à l’INT
La seule machine joignable de l’extérieur de l’INT par internet en utilisant le protocole SSH
est elaphe.int-evry.fr
Table des figures
1
2
3
4
5
6
7
8
9
10
11
Session . . . . . . . . . .
Programme au démarrage .
configuration . . . . . . .
Demande de la passphrase
Génération des clés Etape1
Génération des clés Etape 2
Ajout de clé . . . . . . . .
passphrase . . . . . . . . .
etape finale . . . . . . . .
protocole ssh . . . . . . .
clé utilisée . . . . . . . . .
Eric Doutreleau
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
7
7
8
9
11
12
13
14
15
26
RÉFÉRENCES
F IG . 22 – tunnel windows ftp etape 3
12
13
14
15
16
17
18
19
20
21
22
Fenêtre de connexion de putty
puttysave . . . . . . . . . . .
importation de clé . . . . . . .
tunnel . . . . . . . . . . . . .
tunnel windows etape 1 . . . .
tunnel windows etape 2 . . . .
tunnel windows telnet etape 1 .
tunnel windows telnet etape 2 .
tunnel windows ftp etape 1 . .
tunnel windows ftp etape 2 . .
tunnel windows ftp etape 3 . .
.
.
.
.
.
.
.
.
.
.
.
Références
[openssh] openssh www.openssh.org
Eric Doutreleau
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
16
17
18
19
21
22
23
23
24
25
26