Version Fonctionnelle : STEP 3 Terminée

This commit is contained in:
Paul Faure 2021-01-08 23:04:54 +01:00
parent 606807e2be
commit 28b1a6a7b0
3 changed files with 222 additions and 30 deletions

View file

@ -17,6 +17,9 @@
/* pour memcpy */
#include <string.h>
/* pour le scanf permissif */
#define SIZE_MAX 32767
int main (int argc, char * argv[]) {
if (argc != 3) {
@ -52,23 +55,29 @@ int main (int argc, char * argv[]) {
exit(1);
}
//On envoie les messages
/*for (cmpt_message_envoye = 1; cmpt_message_envoye <= nb_message; cmpt_message_envoye++){
// On construit le message à envoyer
construire_message(message_envoie,(96 + (cmpt_message_envoye % 26)), longueur_message, cmpt_message_envoye);
//On envoie les messages
nb_carac_envoye = send(sock, message_envoie, longueur_message, 0);
if (nb_carac_envoye == -1){
printf("ERREUR lors de l'envoi du message numéro %d\n", cmpt_message_envoye);
exit(1);
} else{
printf("CLIENT EMMETEUR : Envoi n°%d (%d) [", cmpt_message_envoye, nb_carac_envoye);
afficher_message(message_envoie, longueur_message);
printf("]\n");
}
}*/
printf("Que souhaitez vous faire : [PRINT|ADD|SUB|MUL|DIV|RESET|GET]\n");
// Lecture de la requette
char buff[SIZE_MAX];
scanf("%s", buff);
// Envoi de la requette
send(sock, buff, strlen(buff), 0);
// Si arg en envoyer ou réponse a recevoir
if (!strcmp(buff, "ADD") || !strcmp(buff, "SUB") || !strcmp(buff, "MUL") || !strcmp(buff, "DIV")) {
printf("Veuillez saisir l'argument\n");
// Lecture de l'argument
int arg;
scanf("%d", &arg);
// Envoi de la requette
sprintf(buff, "%d", arg);
send(sock, buff, strlen(buff), 0);
} else if (!strcmp(buff, "GET")) {
char buffer[SIZE_MAX];
read(sock, buffer, SIZE_MAX);
printf("La valeur est : %s\n", buffer);
}
close(sock);
return 0;

View file

@ -17,18 +17,18 @@ Tuteurs :
Programmes SERVEUR et CLIENT, principe général :
- Le serveur : En écoute sur un port passé en paramètre, des qu'une connexion arrive, il fork, traite la connexion dans le fils, le père se remet en attente
- Le serveur : Gere un entier (init 0) En écoute sur un port passé en paramètre, des qu'une connexion arrive, il fork, traite la connexion dans le fils, le père se remet en attente
- Gestion de la connexion : Attends une chaine de caractère du client, et, en fonction de son contenu effectue les actions adéquates
- Chaine attendues :
* Nombre de connexions : Le serveur renverra le nombre de connexion qu'il y a eu depuis le début de son lancement
* Heure : Le serveur renverra l'heure actuelle
* Reset : Le serveur remettra le nombre de connexions a 0 et renverra un message indiquant que le nombre de connexions est réinitialisé
* Chaine inconnue : Le serveur renverra un message d'erreur
* ADD/SUB/MUL/DIV : Le serveur additionne, soustrait, multiplie, divise la valeur actuelle par l'argument passé
* RESET : Le serveur remet l'entier a 0
* GET : Le serveur envoi la valeur de l'entier
* PRINT : Le serveur affiche la valeur de l'entier
- Le client : Demande a l'utilisateur de saisir une chaine, puis, affiche la réponse du serveur
- Le client : Demande a l'utilisateur de saisir une chaine, puis, affiche la réponse du serveur (si elle a lieu d'être)
- Failles :
* Le serveur copie la chaine reçue avec strcpy -> risque de buffer Overflow
* Le serveur copie la chaine reçue avec le read mal fait -> risque de buffer Overflow
* Le serveur fork, l'attaquant peut accumuler de la connaissance
Etapes de dévellopement :
@ -37,14 +37,17 @@ Etapes de dévellopement :
* Le serveur : Gere le nombre de connexions, à chaque connexions, il l'affiche juste.
* Le client : Se connecte et ferme la connexion aussitôt.
* Utilité : Test de l'établissement des connexions.
* Retour test : OK.
- Step 2 : FAIT
* Le serveur : Gere le nombre de connexions, à chaque connexions, dans le fils, il appelle une fonction d'affichage.
* La fonction : Reçoit la nombre de connexion, l'affiche, ainsi que son adresse mémoire.
* Le client : Se connecte et ferme la connexion aussitôt.
* Utilité : Verification que les adresses ne changent pas dans la pile d'un fork à l'autre.
- Step 3 : A FAIRE
* Le serveur : Gere le nombre de connexions, à chaque connexions, dans le fils, récupere la chaine, appelle une fonction de traitement.
* La fonction : Copie la chaine et appelle une autre fonction de traitement.
* Retour test : Adresses identiques a chaque connexions.
- Step 3 : FAIT
* Le serveur : Gere l'entier, à chaque connexions, dans le fils, on appelle une fonction de lecture de la requette (read avec BOF possible) puis traite la requete.
* La fonction : Lit la chaine et renvoi une structure correspondant a l'action a faire.
* Le client : Se connecte, demande a l'utilisateur de saisir la chaine, affiche la réponse, et ferme la connexion.
* Utilité : Test du serveur dans son fonctionnement normal.
- Step 4 : A DEFINIR
* Utilité : Test du serveur dans son fonctionnement normal. Test BOF possible
* Retour test : Serveur OK, BOF OK (detecté par le canary).
- Step 4 : TESTER LES PREMIERES EXPLOITATIONS

182
Serveur.c
View file

@ -14,6 +14,58 @@
/* pour le fork */
#include <unistd.h>
/* pour la SHM */
#include <sys/shm.h>
#include <sys/sem.h>
/* pour la manipulation des strings */
#include <string.h>
/* pour le read permissif */
#define SIZE_MAX 32767
// Pour la SHM
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
// L'adresse de la SHM en variable globale pour qu'elle soit accessible depuis les fonctions
int * addr_shm;
// fonctions de manipulation de la SHM
void print_shm() {
printf("La valeur est : %d\n", *addr_shm);
}
void add(int n) {
*addr_shm += n;
}
void sub(int n) {
*addr_shm -= n;
}
void mul(int n) {
*addr_shm *= n;
}
void divi(int n) {
*addr_shm /= n;
}
void reset() {
*addr_shm = 0;
}
int get() {
return *addr_shm;
}
// affichage du nombre de connexions
void print_nb_connexions(int nb_connexions) {
if (nb_connexions == 1) {
printf("Nouvelle connexion, 1ere connexion\n");
@ -24,7 +76,49 @@ void print_nb_connexions(int nb_connexions) {
}
printf("L'adresse du nombre de connexions est : %p\n", &nb_connexions);
}
// Structure pour le traitement des requettes client
struct traitement {
int action;
int arg;
};
// Fonction traitant la phrase reçu et renvoyant une structure traitement
// Fonction qui sera exploitable
struct traitement process(int sock) {
char buff[200];
// PRIMITIVE READ TRES MAL UTILISEE VOLONTAIREMENT
read(sock, buff, SIZE_MAX);
struct traitement ret;
if (!strncmp(buff, "PRINT", 5)) {
ret.action = 1;
} else if (!strncmp(buff, "ADD", 3)) {
ret.action = 2;
read(sock, buff, SIZE_MAX);
ret.arg = atoi(buff);
} else if (!strncmp(buff, "SUB", 3)) {
ret.action = 3;
read(sock, buff, SIZE_MAX);
ret.arg = atoi(buff);
} else if (!strncmp(buff, "MUL", 3)) {
ret.action = 4;
read(sock, buff, SIZE_MAX);
ret.arg = atoi(buff);
} else if (!strncmp(buff, "DIV", 3)) {
ret.action = 5;
read(sock, buff, SIZE_MAX);
ret.arg = atoi(buff);
} else if (!strncmp(buff, "RESET", 5)) {
ret.action = 6;
} else if (!strncmp(buff, "GET", 3)) {
ret.action = 7;
} else {
ret.action = 8;
}
return ret;
}
int main(int argc, char * argv[])
{
@ -33,6 +127,56 @@ int main(int argc, char * argv[])
exit(2);
}
// Variable pour le test sur le retour des fonctions des librairies
int rt;
// Déclaration des clés
int key_sema = 327;
int key_mem = 328;
// Création de la SHM (dans les deux processus)
int ma_shm;
ma_shm = shmget((key_t)key_mem, sizeof(int), 0666 | IPC_CREAT);
if (ma_shm == -1) {
perror("ERREUR. Echec shmget((key_t)key_mem, sizeof(int), 0666 | IPC_CREAT) \n");
fprintf(stderr, "ERREUR. Echec shmget((key_t)key, sizeof(int), 0666 | IPC_CREAT) \n");
exit(2);
}
addr_shm = (int *)shmat(ma_shm, 0, 0);
if (addr_shm == NULL) {
perror("ERREUR. Echec shmat(ma_shm, 0, 0) \n");
fprintf(stderr, "ERREUR. Echec shmat(ma_shm, 0, 0) \n");
exit(2);
}
// Initialisation de la SHM
*addr_shm = 0;
// Création du semaphore (dans les deux processus)
int sema;
sema = semget((key_t)key_sema, 1, 0666 | IPC_CREAT);
if (sema == -1) {
perror("ERREUR. Echec semget((key_t)key_sema, 1, 0666 | IPC_CREAT) \n");
fprintf(stderr, "ERREUR. Echec semget((key_t)key, 1, 0666 | IPC_CREAT) \n");
exit(2);
}
// Initialisation du sémaphore
union semun arg;
arg.val = 1;
rt = semctl(sema, 0, SETVAL, arg);
if (rt != 0) {
perror("ERREUR. Echec semctl(sema, 0, SETVAL, arg) \n");
fprintf(stderr, "ERREUR. Echec semctl(sema, 0, SETVAL, arg) \n");
exit(2);
}
// La structure pour manipuler les semaphores
struct sembuf buf;
buf.sem_flg = 0;
buf.sem_num = 0;
// On crée le socket local
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
@ -80,7 +224,43 @@ int main(int argc, char * argv[])
printf("ERREUR lors de l'acceptation de la connexion\n");
exit(1);
} else {
print_nb_connexions(nb_connexions);
// Recupération du traitement
struct traitement taf = process(sock_connexion);
// Prise du Semaphore
buf.sem_op = -1;
rt = semop(sema, &buf, 1);
if (rt != 0) {
perror("ERREUR. EChec semop(sema, &buf, 1) \n");
fprintf(stderr, "ERREUR. Echec semop(sema, &buf, 1) \n");
exit(2);
}
// Traitement
if (taf.action == 1) {
print_shm();
} else if (taf.action == 2) {
add(taf.arg);
} else if (taf.action == 3) {
sub(taf.arg);
} else if (taf.action == 4) {
mul(taf.arg);
} else if (taf.action == 5) {
divi(taf.arg);
} else if (taf.action == 6) {
reset();
} else if (taf.action == 7) {
int val = get();
char val_string[10];
sprintf(val_string, "%d", val);
send(sock_connexion, val_string, strlen(val_string), 0);
}
// Libération du Semaphore
buf.sem_op = 1;
rt = semop(sema, &buf, 1);
if (rt != 0) {
perror("ERREUR. EChec semop(sema, &buf, 1) \n");
fprintf(stderr, "ERREUR. Echec semop(sema, &buf, 1) \n");
exit(2);
}
}
}
}