From a7d4cadd1b97195edef4bb99cd989e6018c0c77b Mon Sep 17 00:00:00 2001 From: Deville Date: Sat, 11 Jul 2026 20:48:56 +0200 Subject: [PATCH 1/7] Dynamic demon executing Execute en mode demon si la fin du nom de l'exe est 'd' --- api.c | 1173 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 587 insertions(+), 586 deletions(-) diff --git a/api.c b/api.c index c80e0fd..beb2705 100644 --- a/api.c +++ b/api.c @@ -1,586 +1,587 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "errno.h" -#include -#include - -/* compilation : gcc -o api api.c -Wall -lssl -lcrypto */ - -#define TRUE 1 -#define FALSE 0 - -char * certificat; -char * cleprivee; - -// comm ssl -long mSockServeur; // 1 socket serveur mere en ecoute, 0 socket serveur fille connectee -int mSocket; // socket creee -int mSecu; // si comm securise (TLS OpenSSL) -unsigned int mIpClient; // ip du client qui se connecte (socket type 1 uniquement) -char mIp[16]; -long mDateExpirationCert; // aaaammjjhhmmss - -sigset_t mOldBlockSig,mBlockSig; // gestion des signaux sur socket serveur en ecoute - -SSL_CTX * mSslCtx; /* contexte SSL */ -SSL * mClientSsl; /* etat SSL du client */ - - -// process -int mServeur; // TRUE si serveur, FALSE si client ou fork fils du serveur -int mFin; // pour arret du process -int mSignal; // indique si fin demandee par un signal (kill ou dmd arret depuis le serveur) -long mNbFils; // > 0 si serveur -long mPid; // pid du process - -// ----------------------------------------------------------- -void libereSecu() -{ - if(!mSecu) - return; - // libere les ressources d'OpenSSL - if(mClientSsl != NULL) - { - SSL_shutdown(mClientSsl); - /* liberation liee a openssl */ - SSL_free(mClientSsl); - } - // - if(mSslCtx != NULL) - SSL_CTX_free(mSslCtx); - /* EVP_cleanup(); */ /* ?? */ - mSecu = FALSE; -} - -void arret(int socket, int forceShutdown) -{ - if(mSecu) - libereSecu(); - if(0) - shutdown(socket, 2); - close(socket); -} - -int ssl_verify(int ok, X509_STORE_CTX * ctx) -{ - return 1; -} - -int secuSocket() -{ - int cr; - if((mClientSsl = SSL_new(mSslCtx)) == NULL) - { - printf("Erreur SSL_new\n"); - /* erreur gestion etat SSL */ - libereSecu(); - return FALSE; - } - if(!SSL_set_fd(mClientSsl, mSocket)) - { - printf("Erreur SSL_set_fd\n"); - /* erreur assoc socket */ - libereSecu(); - return FALSE; - } - if((cr = SSL_accept(mClientSsl)) <= 0) /* accept pour la partie "serveur" */ - { - int sslcr, cpt = 0; - /* erreur acceptation requetes SSL */ - sslcr = SSL_get_error(mClientSsl, cr); - while(cr != 1 && sslcr == 2 && cpt < 3) - { - /* */ - cpt++; - cr = SSL_accept(mClientSsl); - sslcr = SSL_get_error(mClientSsl, cr); - } - if(cr != 1) - { - printf("Erreur SSL_accept, code %d error %d\n", sslcr, errno); - libereSecu(); - return FALSE; - } - } - return TRUE; -} - -int securise(char * certificat, char * privateKey, int socket) -{ - mSslCtx = NULL; - mClientSsl = NULL; - if(1) - { - if((mSslCtx = SSL_CTX_new(TLS_server_method())) == NULL) - { - printf("Erreur SSL_CTX_new\n"); - libereSecu(); - return FALSE; - } - SSL_CTX_set_options(mSslCtx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION); - /* pas de controle du client ici par certificat (login/mdp ou sso) */ - SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_NONE, NULL); // NULL a la place de "ssl_verify" ?? - /* pas de reutilisation de session (mode par defaut normalement) */ - SSL_CTX_set_session_cache_mode(mSslCtx, SSL_SESS_CACHE_OFF); - /* */ - SSL_CTX_set_ecdh_auto(mSslCtx, 1); - /* */ - if (SSL_CTX_use_certificate_file(mSslCtx, certificat, SSL_FILETYPE_PEM) <= 0) - { - printf("Erreur SSL_CTX_use_certificate_file\n"); - libereSecu(); - return FALSE; - } - if (SSL_CTX_use_PrivateKey_file(mSslCtx, privateKey, SSL_FILETYPE_PEM) <= 0) - { - printf("Erreur SSL_CTX_use_PrivateKey_file\n"); - libereSecu(); - return FALSE; - } - if (!SSL_CTX_check_private_key(mSslCtx)) - { - printf("Erreur SSL_CTX_check_private_key\n"); - libereSecu(); - return FALSE; - } - mSecu = TRUE; - if(socket) - { - return secuSocket(); - } - else - { - return TRUE; - } - } - else - { - /* client */ - /* option "non bloquant" empeche le bon fonctionnement en securise : remettre bloquant */ - int ret, arg = 0; - ioctl(mSocket, FIONBIO, &arg); /* socket bloquant (arg = 0) */ - if((mSslCtx = SSL_CTX_new(TLS_client_method())) == NULL) - { - libereSecu(); - return FALSE; /* erreur creation contexte SSL */ - } - if((mClientSsl = SSL_new(mSslCtx)) == NULL) - { - /* erreur gestion etat SSL */ - libereSecu(); - return FALSE; - } - SSL_set_fd(mClientSsl, mSocket); - if((ret = SSL_connect(mClientSsl)) != 1) /* connect pour partie "client" */ - { - /* erreur connexion a un serveur TLS/SSL */ - libereSecu(); - return FALSE; - } - return TRUE; - } -} - -int creerServeur(long port) -{ - struct sockaddr_in addr; - struct linger l_s; /* Structure pour setsockopt */ - int sockopt, sock, buf = 64000; /* taille buffer send/rec = 64 ko environ */ - int arg = 1; /* pour ioctl */ - // cree une socket serveur prete a ecouter - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(port); - /* mise en place de la socket serveur d'ecoute */ - if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - printf("Erreur creation socket\n"); - return FALSE; // erreur - } - ioctl(sock, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */ - if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */ - { - printf("Erreur setsockopt SO_REUSEADDR\n"); - /* erreur */ - close(sock); - return FALSE; - } - if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) - { - printf("Erreur setsockopt SO_RCVBUF\n"); - /* erreur */ - close(sock); - return FALSE; - } - if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) - { - printf("Erreur setsockopt SO_SNDBUF\n"); - /* erreur */ - close(sock); - return FALSE; - } - // linger n'impacte QUE le close de la socket - l_s.l_onoff = 1; - l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP - if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s))) - { - printf("Erreur setsockopt SO_LINGER\n"); - /* erreur */ - close(sock); - return FALSE; - } - if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) - { - printf("Erreur bind, errno %d\n", errno); - close(sock); - return FALSE; - } - else - if(listen(sock, 10) < 0) - { - printf("Erreur listen\n"); - close(sock); - return FALSE; - } - else - { - mSocket = sock; - sigemptyset(&mOldBlockSig); - sigfillset(&mBlockSig); - return TRUE; // ok - } -} - -long attente(long timeOut) -{ - fd_set masque; /* struct sur aix */ - struct timeval delai; - long cr; - // attend une activite sur la socket, timeOut en 1/10 de sec. - delai.tv_sec = timeOut / 10; /* x sec */ - delai.tv_usec = (timeOut % 10) * 100000; /* y µsec */ - FD_ZERO(&masque); - FD_SET(mSocket, &masque); - // - if(mSockServeur) - { - /* pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour */ - /* les variables "delai" et "masque fd" ; il faut aussi imperativement */ - /* bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante) */ - //sigprocmask(SIG_SETMASK, &mBlockSig, &mOldBlockSig); - cr = select(mSocket + 1, &masque, NULL, NULL, &delai); - //sigprocmask(SIG_SETMASK, &mOldBlockSig, NULL); - } - else - { - while((cr=select(mSocket + 1, &masque, NULL, NULL, &delai)) < 0 && errno == EINTR) errno = 0; - if(cr > 0) - cr = FD_ISSET(mSocket, &masque); - } - return cr; // si > 0 : ok pour continuer et lire la socket -} - -int lireConnexion(char * data) -{ - int nblu = 0, arg = 1; - int flagInProgress = FALSE; - int pas = 2000; - // lire par paquets de longueur fixe et s'arrêter dès que plus rien à lire - // lecture par paquets de octets - ioctl(mSocket, FIONBIO, &arg); // socket non bloquant (sys/ioctl.h) necessaire quand la longueur n'est pas connue (sinon lire sur la longueur et laisser(?) la socket bloquante) - do - { - //if(!data.ctrl(data.getLen() + pas, TRUE)) - // return FALSE; // erreur mem - int lg = strlen(data); - if(lg + pas >= 64000) - ; // TODO : taille maxi du buffer atteinte : quid ?? - while((nblu = SSL_read(mClientSsl, data + lg, pas)) < 0 && errno == EWOULDBLOCK && (strlen(data) == 0 || flagInProgress)) ; - if(errno == EINPROGRESS) // 115 - flagInProgress = TRUE; // indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! - else if(nblu > 0) - data[lg + nblu] = 0; //data.setLen(data.getLen() + nblu); - else - { - int err = SSL_get_error(mClientSsl, nblu); - if(err == SSL_ERROR_ZERO_RETURN || err == SSL_ERROR_SYSCALL) - { - printf("Fermeture de la connexion par le client\n"); - return FALSE; - } - - } - // - } while(nblu > 0); - return TRUE; -} - -int ecrireConnexion(char * data) -{ - int nbecrit = 0; - int retSsl; - do - { - nbecrit = SSL_write(mClientSsl, data, strlen(data)); - retSsl = SSL_get_error(mClientSsl, nbecrit); - // pour gerer les envois partiels de SSLwrite - } while(retSsl == SSL_ERROR_WANT_WRITE || retSsl == SSL_ERROR_WANT_READ); - return (nbecrit == strlen(data)); -} - -void setFin(int fin, int depuisSignal) -{ - mFin = fin; - mSignal = depuisSignal; -} - -void attenteFinFils() -{ - if(mNbFils) - { - while(waitpid(-1, NULL, WNOHANG) > 0) - mNbFils--; /* compte tous les fils terminés "en meme temps" (si un fils se termine quand le pere est dans ce handler) */ - } -} - -void demandeArretFilsEtAttente() -{ - /* demander aux fils de s'arrêter */ - kill(0, SIGUSR1); // 0 = tous les process du groupe : tous les fils - // attente fin fils - while(mNbFils) - { - while(waitpid(-1, NULL, WNOHANG) > 0) - mNbFils--; - } -} - -void verifierFinFils() -{ - waitpid(-1, NULL, WNOHANG); -} - -void trt_exit() -{ - // comment sortir ? - demandeArretFilsEtAttente(); - arret(mSocket, TRUE); - exit(-2); -} - -void trt_sig(int sig) -{ - switch(sig) - { - case SIGCHLD: - if(mServeur) - { - //un process fils se termine (forcement recu par le pere/le serveur) - attenteFinFils(); - } - else - { - // fin depuis un fils (session client) d'un module/batch : waitpid ? - } - break; - // - case SIGINT: - case SIGHUP: - case SIGQUIT: - case SIGTERM: // (kill pid) - mFin = TRUE; - mSignal = TRUE; - break; - // - case SIGSEGV: - trt_exit(); - // - case SIGTTOU: - break; // ignorer si sortie terminal depuis arriere plan - // - case SIGUSR1: - if(! mServeur) - { - mFin = TRUE; - mSignal = TRUE; - } // arret des fils a reception de ce signal - break; - // pour lister les numeros de signaux, taper "kill -l" - } -} - -// ----------------------------------------------------------- -char data[64000]; // buffer de lecture/ecriture sur la socket securisee -void trt_connexion() -{ - //Dynamic req, methode, uri, rep, tmp, fld; - //long meth, cr, nb; - int keepAlive; - printf("trt demande\n"); - // - *data = 0; - keepAlive = TRUE; - while(keepAlive) - { - //tmp.let("GET;HEAD;POST"); - //// lire les donnees entrantes sur la socket // pbm ici bloquant : sans doute pbm de longueur attendue !? a tester - //printf("debut boucle\n"); - if ( ! lireConnexion(data)) - break; // fin du client - printf("lu:\n%s\n", data); - //if(strstr(data,"keep-alive") == NULL) - // keepAlive = FALSE; - // - strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); - printf("Reponse:\n%s\n", data); - ecrireConnexion(data); - *data = 0; - //// faire une attente passive ici (sinon consomme trop de CPU) - //printf("Attente fin boucle\n"); - //while(attente(10) <= 0 && ! mFin) ; - //if ( ! lireConnexion(data)) - // break; - //if(mFin) - break; // sortie sur signal - } - printf("fin cnx client\n"); -} - -// ---------------------------------------------------------- -int main(int argc, char *argv[]) -{ - if(argc != 4) - { - printf("Usage : %s \n", argv[0]); - exit(1); - } - /* */ - int port = atoi(argv[1]); - certificat = argv[2]; - cleprivee = argv[3]; - /* */ - mServeur = TRUE; - mFin = FALSE; - mSignal = FALSE; - mPid = getpid(); - mNbFils = 0; - signal(SIGHUP, trt_sig); - signal(SIGSEGV, trt_sig); - signal(SIGINT, trt_sig); /* ctrl-C */ - signal(SIGQUIT, trt_sig); - signal(SIGTERM, trt_sig); - signal(SIGTTOU, trt_sig); /* ecriture terminal arriere plan */ - signal(SIGCHLD, trt_sig); /* prevenu quand un process fils se termine */ - signal(SIGUSR1, trt_sig); /* sert a demander au fils de s'arrêter suite arrêt du pere */ - signal(SIGUSR2, trt_sig); /* sert a avertir un fils qu'une requête asynchrone est terminee */ - signal(SIGPIPE, SIG_IGN); /* ignorer ce signal pour eviter une erreur lors du sock.write */ - // - mSocket = 0; - mSockServeur = 1; - mSslCtx = NULL; - mClientSsl = NULL; - // - if(1) - { - if((mPid = fork()) != 0) - { - printf("Lancement en tache de fond du process pid %ld\n", mPid); - exit(0); /* sortie du pere */ - } - mPid = getpid(); - chdir("/"); // permet de ne pas bloquer un filesystem avec ce process - setsid(); - for(int i=0;i < FOPEN_MAX; i++) /* OPEN_MAX sous AIX */ - close(i); - } - // - printf("Demarrage serveur, port %d pid %d mode %d bits\n", port, getpid(), sizeof(long)==4?32:64); - /* initialisations internes openssl */ - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); - // verification du contexte securise avant de continuer - if( ! securise(certificat, cleprivee, FALSE)) - { - printf("Erreur lors de la mise en place du contexte securise SSL/TLS\n"); - exit(4); - } - else - { - libereSecu(); - } - if(creerServeur(port)) - { - while( ! mFin) - { - if(attente(10) > 0 && ! mFin) // 10 = 1 seconde - { - struct sockaddr_in addr_cnx; - unsigned int size_addr_cnx = sizeof(addr_cnx); - int sock_fils; - if((sock_fils = accept(mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) > 0) - { - unsigned int ipClient = htonl(addr_cnx.sin_addr.s_addr); - long pid_fils = fork(); - if(pid_fils > 0) - { - // dans le pere - mNbFils++; - signal(SIGCHLD, trt_sig); /* SIGCHLD : prevenu quand un process fils se termine */ - printf("Connexion depuis ip %d.%d.%d.%d : creation process pid %ld\n", (ipClient >> 24) & 0xFF, (ipClient >> 16) & 0xFF, (ipClient >> 8) & 0xFF, (ipClient & 0xFF), pid_fils); - arret(sock_fils, TRUE); - } - else if(pid_fils == 0) - { - // dans le fils - mServeur = FALSE; - mNbFils = 0; - mPid = getpid(); - printf("Connexion entrante pid %ld socket %d\n", mPid, sock_fils); - close(mSocket); // le fils n'a pas besoin de la socket serveur mere - mSocket = sock_fils; - mSockServeur = 0; - int arg = 0; - ioctl(mSocket, FIONBIO, &arg); // mettre bloquant : ok en secu SSL - // - if( ! securise(certificat, cleprivee, TRUE)) - { - // erreur : handshake securise SSL/TLS ko avec le client - printf("Erreur de handshake securise SSL/TLS\n"); - break; - } - // - trt_connexion(); - // - break; - } - else - printf("Erreur de fork() creation fils - demande non traitee\n"); - } - verifierFinFils(); - } - else - printf("Attente... %d\n", mSocket); - } - // arret socket en cours - arret(mSocket, TRUE); - if(mServeur) - { - demandeArretFilsEtAttente(); - printf("Arret du serveur\n"); - } - else - printf("Arret du client\n"); - } - else - { - printf("Erreur d'initialisation du socket serveur - ARRET\n"); - } - return(0); -} +#include +#include +#include +#include +#include +#include +#include +#include +#include "errno.h" +#include +#include + +/* compilation : gcc -o api api.c -Wall -lssl -lcrypto */ + +#define TRUE 1 +#define FALSE 0 + +char * certificat; +char * cleprivee; + +// comm ssl +long mSockServeur; // 1 socket serveur mere en ecoute, 0 socket serveur fille connectee +int mSocket; // socket creee +int mSecu; // si comm securise (TLS OpenSSL) +unsigned int mIpClient; // ip du client qui se connecte (socket type 1 uniquement) +char mIp[16]; +long mDateExpirationCert; // aaaammjjhhmmss + +sigset_t mOldBlockSig,mBlockSig; // gestion des signaux sur socket serveur en ecoute + +SSL_CTX * mSslCtx; /* contexte SSL */ +SSL * mClientSsl; /* etat SSL du client */ + + +// process +int mServeur; // TRUE si serveur, FALSE si client ou fork fils du serveur +int mFin; // pour arret du process +int mSignal; // indique si fin demandee par un signal (kill ou dmd arret depuis le serveur) +long mNbFils; // > 0 si serveur +long mPid; // pid du process + +// ----------------------------------------------------------- +void libereSecu() +{ + if(!mSecu) + return; + // libere les ressources d'OpenSSL + if(mClientSsl != NULL) + { + SSL_shutdown(mClientSsl); + /* liberation liee a openssl */ + SSL_free(mClientSsl); + } + // + if(mSslCtx != NULL) + SSL_CTX_free(mSslCtx); + /* EVP_cleanup(); */ /* ?? */ + mSecu = FALSE; +} + +void arret(int socket, int forceShutdown) +{ + if(mSecu) + libereSecu(); + if(0) + shutdown(socket, 2); + close(socket); +} + +int ssl_verify(int ok, X509_STORE_CTX * ctx) +{ + return 1; +} + +int secuSocket() +{ + int cr; + if((mClientSsl = SSL_new(mSslCtx)) == NULL) + { + printf("Erreur SSL_new\n"); + /* erreur gestion etat SSL */ + libereSecu(); + return FALSE; + } + if(!SSL_set_fd(mClientSsl, mSocket)) + { + printf("Erreur SSL_set_fd\n"); + /* erreur assoc socket */ + libereSecu(); + return FALSE; + } + if((cr = SSL_accept(mClientSsl)) <= 0) /* accept pour la partie "serveur" */ + { + int sslcr, cpt = 0; + /* erreur acceptation requetes SSL */ + sslcr = SSL_get_error(mClientSsl, cr); + while(cr != 1 && sslcr == 2 && cpt < 3) + { + /* */ + cpt++; + cr = SSL_accept(mClientSsl); + sslcr = SSL_get_error(mClientSsl, cr); + } + if(cr != 1) + { + printf("Erreur SSL_accept, code %d error %d\n", sslcr, errno); + libereSecu(); + return FALSE; + } + } + return TRUE; +} + +int securise(char * certificat, char * privateKey, int socket) +{ + mSslCtx = NULL; + mClientSsl = NULL; + if(1) + { + if((mSslCtx = SSL_CTX_new(TLS_server_method())) == NULL) + { + printf("Erreur SSL_CTX_new\n"); + libereSecu(); + return FALSE; + } + SSL_CTX_set_options(mSslCtx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION); + /* pas de controle du client ici par certificat (login/mdp ou sso) */ + SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_NONE, NULL); // NULL a la place de "ssl_verify" ?? + /* pas de reutilisation de session (mode par defaut normalement) */ + SSL_CTX_set_session_cache_mode(mSslCtx, SSL_SESS_CACHE_OFF); + /* */ + SSL_CTX_set_ecdh_auto(mSslCtx, 1); + /* */ + if (SSL_CTX_use_certificate_file(mSslCtx, certificat, SSL_FILETYPE_PEM) <= 0) + { + printf("Erreur SSL_CTX_use_certificate_file\n"); + libereSecu(); + return FALSE; + } + if (SSL_CTX_use_PrivateKey_file(mSslCtx, privateKey, SSL_FILETYPE_PEM) <= 0) + { + printf("Erreur SSL_CTX_use_PrivateKey_file\n"); + libereSecu(); + return FALSE; + } + if (!SSL_CTX_check_private_key(mSslCtx)) + { + printf("Erreur SSL_CTX_check_private_key\n"); + libereSecu(); + return FALSE; + } + mSecu = TRUE; + if(socket) + { + return secuSocket(); + } + else + { + return TRUE; + } + } + else + { + /* client */ + /* option "non bloquant" empeche le bon fonctionnement en securise : remettre bloquant */ + int ret, arg = 0; + ioctl(mSocket, FIONBIO, &arg); /* socket bloquant (arg = 0) */ + if((mSslCtx = SSL_CTX_new(TLS_client_method())) == NULL) + { + libereSecu(); + return FALSE; /* erreur creation contexte SSL */ + } + if((mClientSsl = SSL_new(mSslCtx)) == NULL) + { + /* erreur gestion etat SSL */ + libereSecu(); + return FALSE; + } + SSL_set_fd(mClientSsl, mSocket); + if((ret = SSL_connect(mClientSsl)) != 1) /* connect pour partie "client" */ + { + /* erreur connexion a un serveur TLS/SSL */ + libereSecu(); + return FALSE; + } + return TRUE; + } +} + +int creerServeur(long port) +{ + struct sockaddr_in addr; + struct linger l_s; /* Structure pour setsockopt */ + int sockopt, sock, buf = 64000; /* taille buffer send/rec = 64 ko environ */ + int arg = 1; /* pour ioctl */ + // cree une socket serveur prete a ecouter + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + /* mise en place de la socket serveur d'ecoute */ + if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("Erreur creation socket\n"); + return FALSE; // erreur + } + ioctl(sock, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */ + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */ + { + printf("Erreur setsockopt SO_REUSEADDR\n"); + /* erreur */ + close(sock); + return FALSE; + } + if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) + { + printf("Erreur setsockopt SO_RCVBUF\n"); + /* erreur */ + close(sock); + return FALSE; + } + if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) + { + printf("Erreur setsockopt SO_SNDBUF\n"); + /* erreur */ + close(sock); + return FALSE; + } + // linger n'impacte QUE le close de la socket + l_s.l_onoff = 1; + l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP + if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s))) + { + printf("Erreur setsockopt SO_LINGER\n"); + /* erreur */ + close(sock); + return FALSE; + } + if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + printf("Erreur bind, errno %d\n", errno); + close(sock); + return FALSE; + } + else + if(listen(sock, 10) < 0) + { + printf("Erreur listen\n"); + close(sock); + return FALSE; + } + else + { + mSocket = sock; + sigemptyset(&mOldBlockSig); + sigfillset(&mBlockSig); + return TRUE; // ok + } +} + +long attente(long timeOut) +{ + fd_set masque; /* struct sur aix */ + struct timeval delai; + long cr; + // attend une activite sur la socket, timeOut en 1/10 de sec. + delai.tv_sec = timeOut / 10; /* x sec */ + delai.tv_usec = (timeOut % 10) * 100000; /* y µsec */ + FD_ZERO(&masque); + FD_SET(mSocket, &masque); + // + if(mSockServeur) + { + /* pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour */ + /* les variables "delai" et "masque fd" ; il faut aussi imperativement */ + /* bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante) */ + //sigprocmask(SIG_SETMASK, &mBlockSig, &mOldBlockSig); + cr = select(mSocket + 1, &masque, NULL, NULL, &delai); + //sigprocmask(SIG_SETMASK, &mOldBlockSig, NULL); + } + else + { + while((cr=select(mSocket + 1, &masque, NULL, NULL, &delai)) < 0 && errno == EINTR) errno = 0; + if(cr > 0) + cr = FD_ISSET(mSocket, &masque); + } + return cr; // si > 0 : ok pour continuer et lire la socket +} + +int lireConnexion(char * data) +{ + int nblu = 0, arg = 1; + int flagInProgress = FALSE; + int pas = 2000; + // lire par paquets de longueur fixe et s'arrêter dès que plus rien à lire + // lecture par paquets de octets + ioctl(mSocket, FIONBIO, &arg); // socket non bloquant (sys/ioctl.h) necessaire quand la longueur n'est pas connue (sinon lire sur la longueur et laisser(?) la socket bloquante) + do + { + //if(!data.ctrl(data.getLen() + pas, TRUE)) + // return FALSE; // erreur mem + int lg = strlen(data); + if(lg + pas >= 64000) + ; // TODO : taille maxi du buffer atteinte : quid ?? + while((nblu = SSL_read(mClientSsl, data + lg, pas)) < 0 && errno == EWOULDBLOCK && (strlen(data) == 0 || flagInProgress)) ; + if(errno == EINPROGRESS) // 115 + flagInProgress = TRUE; // indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! + else if(nblu > 0) + data[lg + nblu] = 0; //data.setLen(data.getLen() + nblu); + else + { + int err = SSL_get_error(mClientSsl, nblu); + if(err == SSL_ERROR_ZERO_RETURN || err == SSL_ERROR_SYSCALL) + { + printf("Fermeture de la connexion par le client\n"); + return FALSE; + } + + } + // + } while(nblu > 0); + return TRUE; +} + +int ecrireConnexion(char * data) +{ + int nbecrit = 0; + int retSsl; + do + { + nbecrit = SSL_write(mClientSsl, data, strlen(data)); + retSsl = SSL_get_error(mClientSsl, nbecrit); + // pour gerer les envois partiels de SSLwrite + } while(retSsl == SSL_ERROR_WANT_WRITE || retSsl == SSL_ERROR_WANT_READ); + return (nbecrit == strlen(data)); +} + +void setFin(int fin, int depuisSignal) +{ + mFin = fin; + mSignal = depuisSignal; +} + +void attenteFinFils() +{ + if(mNbFils) + { + while(waitpid(-1, NULL, WNOHANG) > 0) + mNbFils--; /* compte tous les fils terminés "en meme temps" (si un fils se termine quand le pere est dans ce handler) */ + } +} + +void demandeArretFilsEtAttente() +{ + /* demander aux fils de s'arrêter */ + kill(0, SIGUSR1); // 0 = tous les process du groupe : tous les fils + // attente fin fils + while(mNbFils) + { + while(waitpid(-1, NULL, WNOHANG) > 0) + mNbFils--; + } +} + +void verifierFinFils() +{ + waitpid(-1, NULL, WNOHANG); +} + +void trt_exit() +{ + // comment sortir ? + demandeArretFilsEtAttente(); + arret(mSocket, TRUE); + exit(-2); +} + +void trt_sig(int sig) +{ + switch(sig) + { + case SIGCHLD: + if(mServeur) + { + //un process fils se termine (forcement recu par le pere/le serveur) + attenteFinFils(); + } + else + { + // fin depuis un fils (session client) d'un module/batch : waitpid ? + } + break; + // + case SIGINT: + case SIGHUP: + case SIGQUIT: + case SIGTERM: // (kill pid) + mFin = TRUE; + mSignal = TRUE; + break; + // + case SIGSEGV: + trt_exit(); + // + case SIGTTOU: + break; // ignorer si sortie terminal depuis arriere plan + // + case SIGUSR1: + if(! mServeur) + { + mFin = TRUE; + mSignal = TRUE; + } // arret des fils a reception de ce signal + break; + // pour lister les numeros de signaux, taper "kill -l" + } +} + +// ----------------------------------------------------------- +char data[64000]; // buffer de lecture/ecriture sur la socket securisee +void trt_connexion() +{ + //Dynamic req, methode, uri, rep, tmp, fld; + //long meth, cr, nb; + int keepAlive; + printf("trt demande\n"); + // + *data = 0; + keepAlive = TRUE; + while(keepAlive) + { + //tmp.let("GET;HEAD;POST"); + //// lire les donnees entrantes sur la socket // pbm ici bloquant : sans doute pbm de longueur attendue !? a tester + //printf("debut boucle\n"); + if ( ! lireConnexion(data)) + break; // fin du client + printf("lu:\n%s\n", data); + //if(strstr(data,"keep-alive") == NULL) + // keepAlive = FALSE; + // + strcpy(data, "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); + printf("Reponse:\n%s\n", data); + ecrireConnexion(data); + *data = 0; + //// faire une attente passive ici (sinon consomme trop de CPU) + //printf("Attente fin boucle\n"); + //while(attente(10) <= 0 && ! mFin) ; + //if ( ! lireConnexion(data)) + // break; + //if(mFin) + break; // sortie sur signal + } + printf("fin cnx client\n"); +} + +// ---------------------------------------------------------- +int main(int argc, char *argv[]) +{ + if(argc != 4) + { + printf("Usage : %s \n", argv[0]); + exit(1); + } + int demon = (argv[0][strlen(argv[0]) - 1] == 'd'); + /* */ + int port = atoi(argv[1]); + certificat = argv[2]; + cleprivee = argv[3]; + /* */ + mServeur = TRUE; + mFin = FALSE; + mSignal = FALSE; + mPid = getpid(); + mNbFils = 0; + signal(SIGHUP, trt_sig); + signal(SIGSEGV, trt_sig); + signal(SIGINT, trt_sig); /* ctrl-C */ + signal(SIGQUIT, trt_sig); + signal(SIGTERM, trt_sig); + signal(SIGTTOU, trt_sig); /* ecriture terminal arriere plan */ + signal(SIGCHLD, trt_sig); /* prevenu quand un process fils se termine */ + signal(SIGUSR1, trt_sig); /* sert a demander au fils de s'arrêter suite arrêt du pere */ + signal(SIGUSR2, trt_sig); /* sert a avertir un fils qu'une requête asynchrone est terminee */ + signal(SIGPIPE, SIG_IGN); /* ignorer ce signal pour eviter une erreur lors du sock.write */ + // + mSocket = 0; + mSockServeur = 1; + mSslCtx = NULL; + mClientSsl = NULL; + // + if(demon) + { + if((mPid = fork()) != 0) + { + printf("Lancement en tache de fond du process pid %ld\n", mPid); + exit(0); /* sortie du pere */ + } + mPid = getpid(); + chdir("/"); // permet de ne pas bloquer un filesystem avec ce process + setsid(); + for(int i=0;i < FOPEN_MAX; i++) /* OPEN_MAX sous AIX */ + close(i); + } + // + printf("Demarrage serveur, port %d pid %d mode %d bits\n", port, getpid(), sizeof(long)==4?32:64); + /* initialisations internes openssl */ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + // verification du contexte securise avant de continuer + if( ! securise(certificat, cleprivee, FALSE)) + { + printf("Erreur lors de la mise en place du contexte securise SSL/TLS\n"); + exit(4); + } + else + { + libereSecu(); + } + if(creerServeur(port)) + { + while( ! mFin) + { + if(attente(10) > 0 && ! mFin) // 10 = 1 seconde + { + struct sockaddr_in addr_cnx; + unsigned int size_addr_cnx = sizeof(addr_cnx); + int sock_fils; + if((sock_fils = accept(mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) > 0) + { + unsigned int ipClient = htonl(addr_cnx.sin_addr.s_addr); + long pid_fils = fork(); + if(pid_fils > 0) + { + // dans le pere + mNbFils++; + signal(SIGCHLD, trt_sig); /* SIGCHLD : prevenu quand un process fils se termine */ + printf("Connexion depuis ip %d.%d.%d.%d : creation process pid %ld\n", (ipClient >> 24) & 0xFF, (ipClient >> 16) & 0xFF, (ipClient >> 8) & 0xFF, (ipClient & 0xFF), pid_fils); + arret(sock_fils, TRUE); + } + else if(pid_fils == 0) + { + // dans le fils + mServeur = FALSE; + mNbFils = 0; + mPid = getpid(); + printf("Connexion entrante pid %ld socket %d\n", mPid, sock_fils); + close(mSocket); // le fils n'a pas besoin de la socket serveur mere + mSocket = sock_fils; + mSockServeur = 0; + int arg = 0; + ioctl(mSocket, FIONBIO, &arg); // mettre bloquant : ok en secu SSL + // + if( ! securise(certificat, cleprivee, TRUE)) + { + // erreur : handshake securise SSL/TLS ko avec le client + printf("Erreur de handshake securise SSL/TLS\n"); + break; + } + // + trt_connexion(); + // + break; + } + else + printf("Erreur de fork() creation fils - demande non traitee\n"); + } + verifierFinFils(); + } + else + printf("Attente... %d\n", mSocket); + } + // arret socket en cours + arret(mSocket, TRUE); + if(mServeur) + { + demandeArretFilsEtAttente(); + printf("Arret du serveur\n"); + } + else + printf("Arret du client\n"); + } + else + { + printf("Erreur d'initialisation du socket serveur - ARRET\n"); + } + return(0); +} -- 2.56.0.windows.4 From 0dc02cb3e6d890d382e4a575a90512466bfaa0c5 Mon Sep 17 00:00:00 2001 From: Deville Date: Sun, 12 Jul 2026 14:22:04 +0200 Subject: [PATCH 2/7] fix: add log --- api.c | 1211 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 624 insertions(+), 587 deletions(-) diff --git a/api.c b/api.c index beb2705..0519e6a 100644 --- a/api.c +++ b/api.c @@ -1,587 +1,624 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "errno.h" -#include -#include - -/* compilation : gcc -o api api.c -Wall -lssl -lcrypto */ - -#define TRUE 1 -#define FALSE 0 - -char * certificat; -char * cleprivee; - -// comm ssl -long mSockServeur; // 1 socket serveur mere en ecoute, 0 socket serveur fille connectee -int mSocket; // socket creee -int mSecu; // si comm securise (TLS OpenSSL) -unsigned int mIpClient; // ip du client qui se connecte (socket type 1 uniquement) -char mIp[16]; -long mDateExpirationCert; // aaaammjjhhmmss - -sigset_t mOldBlockSig,mBlockSig; // gestion des signaux sur socket serveur en ecoute - -SSL_CTX * mSslCtx; /* contexte SSL */ -SSL * mClientSsl; /* etat SSL du client */ - - -// process -int mServeur; // TRUE si serveur, FALSE si client ou fork fils du serveur -int mFin; // pour arret du process -int mSignal; // indique si fin demandee par un signal (kill ou dmd arret depuis le serveur) -long mNbFils; // > 0 si serveur -long mPid; // pid du process - -// ----------------------------------------------------------- -void libereSecu() -{ - if(!mSecu) - return; - // libere les ressources d'OpenSSL - if(mClientSsl != NULL) - { - SSL_shutdown(mClientSsl); - /* liberation liee a openssl */ - SSL_free(mClientSsl); - } - // - if(mSslCtx != NULL) - SSL_CTX_free(mSslCtx); - /* EVP_cleanup(); */ /* ?? */ - mSecu = FALSE; -} - -void arret(int socket, int forceShutdown) -{ - if(mSecu) - libereSecu(); - if(0) - shutdown(socket, 2); - close(socket); -} - -int ssl_verify(int ok, X509_STORE_CTX * ctx) -{ - return 1; -} - -int secuSocket() -{ - int cr; - if((mClientSsl = SSL_new(mSslCtx)) == NULL) - { - printf("Erreur SSL_new\n"); - /* erreur gestion etat SSL */ - libereSecu(); - return FALSE; - } - if(!SSL_set_fd(mClientSsl, mSocket)) - { - printf("Erreur SSL_set_fd\n"); - /* erreur assoc socket */ - libereSecu(); - return FALSE; - } - if((cr = SSL_accept(mClientSsl)) <= 0) /* accept pour la partie "serveur" */ - { - int sslcr, cpt = 0; - /* erreur acceptation requetes SSL */ - sslcr = SSL_get_error(mClientSsl, cr); - while(cr != 1 && sslcr == 2 && cpt < 3) - { - /* */ - cpt++; - cr = SSL_accept(mClientSsl); - sslcr = SSL_get_error(mClientSsl, cr); - } - if(cr != 1) - { - printf("Erreur SSL_accept, code %d error %d\n", sslcr, errno); - libereSecu(); - return FALSE; - } - } - return TRUE; -} - -int securise(char * certificat, char * privateKey, int socket) -{ - mSslCtx = NULL; - mClientSsl = NULL; - if(1) - { - if((mSslCtx = SSL_CTX_new(TLS_server_method())) == NULL) - { - printf("Erreur SSL_CTX_new\n"); - libereSecu(); - return FALSE; - } - SSL_CTX_set_options(mSslCtx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION); - /* pas de controle du client ici par certificat (login/mdp ou sso) */ - SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_NONE, NULL); // NULL a la place de "ssl_verify" ?? - /* pas de reutilisation de session (mode par defaut normalement) */ - SSL_CTX_set_session_cache_mode(mSslCtx, SSL_SESS_CACHE_OFF); - /* */ - SSL_CTX_set_ecdh_auto(mSslCtx, 1); - /* */ - if (SSL_CTX_use_certificate_file(mSslCtx, certificat, SSL_FILETYPE_PEM) <= 0) - { - printf("Erreur SSL_CTX_use_certificate_file\n"); - libereSecu(); - return FALSE; - } - if (SSL_CTX_use_PrivateKey_file(mSslCtx, privateKey, SSL_FILETYPE_PEM) <= 0) - { - printf("Erreur SSL_CTX_use_PrivateKey_file\n"); - libereSecu(); - return FALSE; - } - if (!SSL_CTX_check_private_key(mSslCtx)) - { - printf("Erreur SSL_CTX_check_private_key\n"); - libereSecu(); - return FALSE; - } - mSecu = TRUE; - if(socket) - { - return secuSocket(); - } - else - { - return TRUE; - } - } - else - { - /* client */ - /* option "non bloquant" empeche le bon fonctionnement en securise : remettre bloquant */ - int ret, arg = 0; - ioctl(mSocket, FIONBIO, &arg); /* socket bloquant (arg = 0) */ - if((mSslCtx = SSL_CTX_new(TLS_client_method())) == NULL) - { - libereSecu(); - return FALSE; /* erreur creation contexte SSL */ - } - if((mClientSsl = SSL_new(mSslCtx)) == NULL) - { - /* erreur gestion etat SSL */ - libereSecu(); - return FALSE; - } - SSL_set_fd(mClientSsl, mSocket); - if((ret = SSL_connect(mClientSsl)) != 1) /* connect pour partie "client" */ - { - /* erreur connexion a un serveur TLS/SSL */ - libereSecu(); - return FALSE; - } - return TRUE; - } -} - -int creerServeur(long port) -{ - struct sockaddr_in addr; - struct linger l_s; /* Structure pour setsockopt */ - int sockopt, sock, buf = 64000; /* taille buffer send/rec = 64 ko environ */ - int arg = 1; /* pour ioctl */ - // cree une socket serveur prete a ecouter - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(port); - /* mise en place de la socket serveur d'ecoute */ - if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - printf("Erreur creation socket\n"); - return FALSE; // erreur - } - ioctl(sock, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */ - if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */ - { - printf("Erreur setsockopt SO_REUSEADDR\n"); - /* erreur */ - close(sock); - return FALSE; - } - if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) - { - printf("Erreur setsockopt SO_RCVBUF\n"); - /* erreur */ - close(sock); - return FALSE; - } - if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) - { - printf("Erreur setsockopt SO_SNDBUF\n"); - /* erreur */ - close(sock); - return FALSE; - } - // linger n'impacte QUE le close de la socket - l_s.l_onoff = 1; - l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP - if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s))) - { - printf("Erreur setsockopt SO_LINGER\n"); - /* erreur */ - close(sock); - return FALSE; - } - if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) - { - printf("Erreur bind, errno %d\n", errno); - close(sock); - return FALSE; - } - else - if(listen(sock, 10) < 0) - { - printf("Erreur listen\n"); - close(sock); - return FALSE; - } - else - { - mSocket = sock; - sigemptyset(&mOldBlockSig); - sigfillset(&mBlockSig); - return TRUE; // ok - } -} - -long attente(long timeOut) -{ - fd_set masque; /* struct sur aix */ - struct timeval delai; - long cr; - // attend une activite sur la socket, timeOut en 1/10 de sec. - delai.tv_sec = timeOut / 10; /* x sec */ - delai.tv_usec = (timeOut % 10) * 100000; /* y µsec */ - FD_ZERO(&masque); - FD_SET(mSocket, &masque); - // - if(mSockServeur) - { - /* pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour */ - /* les variables "delai" et "masque fd" ; il faut aussi imperativement */ - /* bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante) */ - //sigprocmask(SIG_SETMASK, &mBlockSig, &mOldBlockSig); - cr = select(mSocket + 1, &masque, NULL, NULL, &delai); - //sigprocmask(SIG_SETMASK, &mOldBlockSig, NULL); - } - else - { - while((cr=select(mSocket + 1, &masque, NULL, NULL, &delai)) < 0 && errno == EINTR) errno = 0; - if(cr > 0) - cr = FD_ISSET(mSocket, &masque); - } - return cr; // si > 0 : ok pour continuer et lire la socket -} - -int lireConnexion(char * data) -{ - int nblu = 0, arg = 1; - int flagInProgress = FALSE; - int pas = 2000; - // lire par paquets de longueur fixe et s'arrêter dès que plus rien à lire - // lecture par paquets de octets - ioctl(mSocket, FIONBIO, &arg); // socket non bloquant (sys/ioctl.h) necessaire quand la longueur n'est pas connue (sinon lire sur la longueur et laisser(?) la socket bloquante) - do - { - //if(!data.ctrl(data.getLen() + pas, TRUE)) - // return FALSE; // erreur mem - int lg = strlen(data); - if(lg + pas >= 64000) - ; // TODO : taille maxi du buffer atteinte : quid ?? - while((nblu = SSL_read(mClientSsl, data + lg, pas)) < 0 && errno == EWOULDBLOCK && (strlen(data) == 0 || flagInProgress)) ; - if(errno == EINPROGRESS) // 115 - flagInProgress = TRUE; // indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! - else if(nblu > 0) - data[lg + nblu] = 0; //data.setLen(data.getLen() + nblu); - else - { - int err = SSL_get_error(mClientSsl, nblu); - if(err == SSL_ERROR_ZERO_RETURN || err == SSL_ERROR_SYSCALL) - { - printf("Fermeture de la connexion par le client\n"); - return FALSE; - } - - } - // - } while(nblu > 0); - return TRUE; -} - -int ecrireConnexion(char * data) -{ - int nbecrit = 0; - int retSsl; - do - { - nbecrit = SSL_write(mClientSsl, data, strlen(data)); - retSsl = SSL_get_error(mClientSsl, nbecrit); - // pour gerer les envois partiels de SSLwrite - } while(retSsl == SSL_ERROR_WANT_WRITE || retSsl == SSL_ERROR_WANT_READ); - return (nbecrit == strlen(data)); -} - -void setFin(int fin, int depuisSignal) -{ - mFin = fin; - mSignal = depuisSignal; -} - -void attenteFinFils() -{ - if(mNbFils) - { - while(waitpid(-1, NULL, WNOHANG) > 0) - mNbFils--; /* compte tous les fils terminés "en meme temps" (si un fils se termine quand le pere est dans ce handler) */ - } -} - -void demandeArretFilsEtAttente() -{ - /* demander aux fils de s'arrêter */ - kill(0, SIGUSR1); // 0 = tous les process du groupe : tous les fils - // attente fin fils - while(mNbFils) - { - while(waitpid(-1, NULL, WNOHANG) > 0) - mNbFils--; - } -} - -void verifierFinFils() -{ - waitpid(-1, NULL, WNOHANG); -} - -void trt_exit() -{ - // comment sortir ? - demandeArretFilsEtAttente(); - arret(mSocket, TRUE); - exit(-2); -} - -void trt_sig(int sig) -{ - switch(sig) - { - case SIGCHLD: - if(mServeur) - { - //un process fils se termine (forcement recu par le pere/le serveur) - attenteFinFils(); - } - else - { - // fin depuis un fils (session client) d'un module/batch : waitpid ? - } - break; - // - case SIGINT: - case SIGHUP: - case SIGQUIT: - case SIGTERM: // (kill pid) - mFin = TRUE; - mSignal = TRUE; - break; - // - case SIGSEGV: - trt_exit(); - // - case SIGTTOU: - break; // ignorer si sortie terminal depuis arriere plan - // - case SIGUSR1: - if(! mServeur) - { - mFin = TRUE; - mSignal = TRUE; - } // arret des fils a reception de ce signal - break; - // pour lister les numeros de signaux, taper "kill -l" - } -} - -// ----------------------------------------------------------- -char data[64000]; // buffer de lecture/ecriture sur la socket securisee -void trt_connexion() -{ - //Dynamic req, methode, uri, rep, tmp, fld; - //long meth, cr, nb; - int keepAlive; - printf("trt demande\n"); - // - *data = 0; - keepAlive = TRUE; - while(keepAlive) - { - //tmp.let("GET;HEAD;POST"); - //// lire les donnees entrantes sur la socket // pbm ici bloquant : sans doute pbm de longueur attendue !? a tester - //printf("debut boucle\n"); - if ( ! lireConnexion(data)) - break; // fin du client - printf("lu:\n%s\n", data); - //if(strstr(data,"keep-alive") == NULL) - // keepAlive = FALSE; - // - strcpy(data, "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); - printf("Reponse:\n%s\n", data); - ecrireConnexion(data); - *data = 0; - //// faire une attente passive ici (sinon consomme trop de CPU) - //printf("Attente fin boucle\n"); - //while(attente(10) <= 0 && ! mFin) ; - //if ( ! lireConnexion(data)) - // break; - //if(mFin) - break; // sortie sur signal - } - printf("fin cnx client\n"); -} - -// ---------------------------------------------------------- -int main(int argc, char *argv[]) -{ - if(argc != 4) - { - printf("Usage : %s \n", argv[0]); - exit(1); - } - int demon = (argv[0][strlen(argv[0]) - 1] == 'd'); - /* */ - int port = atoi(argv[1]); - certificat = argv[2]; - cleprivee = argv[3]; - /* */ - mServeur = TRUE; - mFin = FALSE; - mSignal = FALSE; - mPid = getpid(); - mNbFils = 0; - signal(SIGHUP, trt_sig); - signal(SIGSEGV, trt_sig); - signal(SIGINT, trt_sig); /* ctrl-C */ - signal(SIGQUIT, trt_sig); - signal(SIGTERM, trt_sig); - signal(SIGTTOU, trt_sig); /* ecriture terminal arriere plan */ - signal(SIGCHLD, trt_sig); /* prevenu quand un process fils se termine */ - signal(SIGUSR1, trt_sig); /* sert a demander au fils de s'arrêter suite arrêt du pere */ - signal(SIGUSR2, trt_sig); /* sert a avertir un fils qu'une requête asynchrone est terminee */ - signal(SIGPIPE, SIG_IGN); /* ignorer ce signal pour eviter une erreur lors du sock.write */ - // - mSocket = 0; - mSockServeur = 1; - mSslCtx = NULL; - mClientSsl = NULL; - // - if(demon) - { - if((mPid = fork()) != 0) - { - printf("Lancement en tache de fond du process pid %ld\n", mPid); - exit(0); /* sortie du pere */ - } - mPid = getpid(); - chdir("/"); // permet de ne pas bloquer un filesystem avec ce process - setsid(); - for(int i=0;i < FOPEN_MAX; i++) /* OPEN_MAX sous AIX */ - close(i); - } - // - printf("Demarrage serveur, port %d pid %d mode %d bits\n", port, getpid(), sizeof(long)==4?32:64); - /* initialisations internes openssl */ - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); - // verification du contexte securise avant de continuer - if( ! securise(certificat, cleprivee, FALSE)) - { - printf("Erreur lors de la mise en place du contexte securise SSL/TLS\n"); - exit(4); - } - else - { - libereSecu(); - } - if(creerServeur(port)) - { - while( ! mFin) - { - if(attente(10) > 0 && ! mFin) // 10 = 1 seconde - { - struct sockaddr_in addr_cnx; - unsigned int size_addr_cnx = sizeof(addr_cnx); - int sock_fils; - if((sock_fils = accept(mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) > 0) - { - unsigned int ipClient = htonl(addr_cnx.sin_addr.s_addr); - long pid_fils = fork(); - if(pid_fils > 0) - { - // dans le pere - mNbFils++; - signal(SIGCHLD, trt_sig); /* SIGCHLD : prevenu quand un process fils se termine */ - printf("Connexion depuis ip %d.%d.%d.%d : creation process pid %ld\n", (ipClient >> 24) & 0xFF, (ipClient >> 16) & 0xFF, (ipClient >> 8) & 0xFF, (ipClient & 0xFF), pid_fils); - arret(sock_fils, TRUE); - } - else if(pid_fils == 0) - { - // dans le fils - mServeur = FALSE; - mNbFils = 0; - mPid = getpid(); - printf("Connexion entrante pid %ld socket %d\n", mPid, sock_fils); - close(mSocket); // le fils n'a pas besoin de la socket serveur mere - mSocket = sock_fils; - mSockServeur = 0; - int arg = 0; - ioctl(mSocket, FIONBIO, &arg); // mettre bloquant : ok en secu SSL - // - if( ! securise(certificat, cleprivee, TRUE)) - { - // erreur : handshake securise SSL/TLS ko avec le client - printf("Erreur de handshake securise SSL/TLS\n"); - break; - } - // - trt_connexion(); - // - break; - } - else - printf("Erreur de fork() creation fils - demande non traitee\n"); - } - verifierFinFils(); - } - else - printf("Attente... %d\n", mSocket); - } - // arret socket en cours - arret(mSocket, TRUE); - if(mServeur) - { - demandeArretFilsEtAttente(); - printf("Arret du serveur\n"); - } - else - printf("Arret du client\n"); - } - else - { - printf("Erreur d'initialisation du socket serveur - ARRET\n"); - } - return(0); -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "errno.h" +#include +#include + +/* compilation : gcc -o api api.c -Wall -lssl -lcrypto */ + +char * flog = NULL; + +#define TRUE 1 +#define FALSE 0 + +char * certificat; +char * cleprivee; + +// comm ssl +long mSockServeur; // 1 socket serveur mere en ecoute, 0 socket serveur fille connectee +int mSocket; // socket creee +int mSecu; // si comm securise (TLS OpenSSL) +unsigned int mIpClient; // ip du client qui se connecte (socket type 1 uniquement) +char mIp[16]; +long mDateExpirationCert; // aaaammjjhhmmss + +sigset_t mOldBlockSig,mBlockSig; // gestion des signaux sur socket serveur en ecoute + +SSL_CTX * mSslCtx; /* contexte SSL */ +SSL * mClientSsl; /* etat SSL du client */ + + +// process +int mServeur; // TRUE si serveur, FALSE si client ou fork fils du serveur +int mFin; // pour arret du process +int mSignal; // indique si fin demandee par un signal (kill ou dmd arret depuis le serveur) +long mNbFils; // > 0 si serveur +long mPid; // pid du process + +// ----------------------------------------------------------- +void trace(const char * fmt, ...) +{ + va_list args; + va_start(args, fmt); + if(flog) + { + FILE * f = fopen(flog, "a+"); + if(f) + { + fprintf(f, "%s%d%s", mServeur ? "Serveur " : "Cnx ", getpid(), ": "); + vfprintf(f, fmt, args); + fclose(f); + } + else + { + printf("%s%d%s", mServeur ? "Serveur " : "Cnx ", getpid(), ": "); + vprintf(fmt, args); + } + } + else + { + printf("%s%d%s", mServeur ? "Serveur " : "Cnx ", getpid(), ": "); + vprintf(fmt, args); + } + va_end(args); +} + +// ----------------------------------------------------------- +void libereSecu() +{ + if(!mSecu) + return; + // libere les ressources d'OpenSSL + if(mClientSsl != NULL) + { + SSL_shutdown(mClientSsl); + /* liberation liee a openssl */ + SSL_free(mClientSsl); + } + // + if(mSslCtx != NULL) + SSL_CTX_free(mSslCtx); + /* EVP_cleanup(); */ /* ?? */ + mSecu = FALSE; +} + +void arret(int socket, int forceShutdown) +{ + if(mSecu) + libereSecu(); + if(0) + shutdown(socket, 2); + close(socket); +} + +int ssl_verify(int ok, X509_STORE_CTX * ctx) +{ + return 1; +} + +int secuSocket() +{ + int cr; + if((mClientSsl = SSL_new(mSslCtx)) == NULL) + { + trace("Erreur SSL_new\n"); + /* erreur gestion etat SSL */ + libereSecu(); + return FALSE; + } + if(!SSL_set_fd(mClientSsl, mSocket)) + { + trace("Erreur SSL_set_fd\n"); + /* erreur assoc socket */ + libereSecu(); + return FALSE; + } + if((cr = SSL_accept(mClientSsl)) <= 0) /* accept pour la partie "serveur" */ + { + int sslcr, cpt = 0; + /* erreur acceptation requetes SSL */ + sslcr = SSL_get_error(mClientSsl, cr); + while(cr != 1 && sslcr == 2 && cpt < 3) + { + /* */ + cpt++; + cr = SSL_accept(mClientSsl); + sslcr = SSL_get_error(mClientSsl, cr); + } + if(cr != 1) + { + trace("Erreur SSL_accept, code %d error %d\n", sslcr, errno); + libereSecu(); + return FALSE; + } + } + return TRUE; +} + +int securise(char * certificat, char * privateKey, int socket) +{ + mSslCtx = NULL; + mClientSsl = NULL; + if(1) + { + if((mSslCtx = SSL_CTX_new(TLS_server_method())) == NULL) + { + trace("Erreur SSL_CTX_new\n"); + libereSecu(); + return FALSE; + } + SSL_CTX_set_options(mSslCtx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION); + /* pas de controle du client ici par certificat (login/mdp ou sso) */ + SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_NONE, NULL); // NULL a la place de "ssl_verify" ?? + /* pas de reutilisation de session (mode par defaut normalement) */ + SSL_CTX_set_session_cache_mode(mSslCtx, SSL_SESS_CACHE_OFF); + /* */ + SSL_CTX_set_ecdh_auto(mSslCtx, 1); + /* */ + if (SSL_CTX_use_certificate_file(mSslCtx, certificat, SSL_FILETYPE_PEM) <= 0) + { + trace("Erreur SSL_CTX_use_certificate_file\n"); + libereSecu(); + return FALSE; + } + if (SSL_CTX_use_PrivateKey_file(mSslCtx, privateKey, SSL_FILETYPE_PEM) <= 0) + { + trace("Erreur SSL_CTX_use_PrivateKey_file\n"); + libereSecu(); + return FALSE; + } + if (!SSL_CTX_check_private_key(mSslCtx)) + { + trace("Erreur SSL_CTX_check_private_key\n"); + libereSecu(); + return FALSE; + } + mSecu = TRUE; + if(socket) + { + return secuSocket(); + } + else + { + return TRUE; + } + } + else + { + /* client */ + /* option "non bloquant" empeche le bon fonctionnement en securise : remettre bloquant */ + int ret, arg = 0; + ioctl(mSocket, FIONBIO, &arg); /* socket bloquant (arg = 0) */ + if((mSslCtx = SSL_CTX_new(TLS_client_method())) == NULL) + { + libereSecu(); + return FALSE; /* erreur creation contexte SSL */ + } + if((mClientSsl = SSL_new(mSslCtx)) == NULL) + { + /* erreur gestion etat SSL */ + libereSecu(); + return FALSE; + } + SSL_set_fd(mClientSsl, mSocket); + if((ret = SSL_connect(mClientSsl)) != 1) /* connect pour partie "client" */ + { + /* erreur connexion a un serveur TLS/SSL */ + libereSecu(); + return FALSE; + } + return TRUE; + } +} + +int creerServeur(long port) +{ + struct sockaddr_in addr; + struct linger l_s; /* Structure pour setsockopt */ + int sockopt, sock, buf = 64000; /* taille buffer send/rec = 64 ko environ */ + int arg = 1; /* pour ioctl */ + // cree une socket serveur prete a ecouter + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + /* mise en place de la socket serveur d'ecoute */ + if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + trace("Erreur creation socket\n"); + return FALSE; // erreur + } + ioctl(sock, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */ + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */ + { + trace("Erreur setsockopt SO_REUSEADDR\n"); + /* erreur */ + close(sock); + return FALSE; + } + if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) + { + trace("Erreur setsockopt SO_RCVBUF\n"); + /* erreur */ + close(sock); + return FALSE; + } + if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) + { + trace("Erreur setsockopt SO_SNDBUF\n"); + /* erreur */ + close(sock); + return FALSE; + } + // linger n'impacte QUE le close de la socket + l_s.l_onoff = 1; + l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP + if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s))) + { + trace("Erreur setsockopt SO_LINGER\n"); + /* erreur */ + close(sock); + return FALSE; + } + if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + trace("Erreur bind, errno %d\n", errno); + close(sock); + return FALSE; + } + else + if(listen(sock, 10) < 0) + { + trace("Erreur listen\n"); + close(sock); + return FALSE; + } + else + { + mSocket = sock; + sigemptyset(&mOldBlockSig); + sigfillset(&mBlockSig); + return TRUE; // ok + } +} + +long attente(long timeOut) +{ + fd_set masque; /* struct sur aix */ + struct timeval delai; + long cr; + // attend une activite sur la socket, timeOut en 1/10 de sec. + delai.tv_sec = timeOut / 10; /* x sec */ + delai.tv_usec = (timeOut % 10) * 100000; /* y µsec */ + FD_ZERO(&masque); + FD_SET(mSocket, &masque); + // + if(mSockServeur) + { + /* pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour */ + /* les variables "delai" et "masque fd" ; il faut aussi imperativement */ + /* bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante) */ + //sigprocmask(SIG_SETMASK, &mBlockSig, &mOldBlockSig); + cr = select(mSocket + 1, &masque, NULL, NULL, &delai); + //sigprocmask(SIG_SETMASK, &mOldBlockSig, NULL); + } + else + { + while((cr=select(mSocket + 1, &masque, NULL, NULL, &delai)) < 0 && errno == EINTR) errno = 0; + if(cr > 0) + cr = FD_ISSET(mSocket, &masque); + } + return cr; // si > 0 : ok pour continuer et lire la socket +} + +int lireConnexion(char * data) +{ + int nblu = 0, arg = 1; + int flagInProgress = FALSE; + int pas = 2000; + // lire par paquets de longueur fixe et s'arrêter dès que plus rien à lire + // lecture par paquets de octets + ioctl(mSocket, FIONBIO, &arg); // socket non bloquant (sys/ioctl.h) necessaire quand la longueur n'est pas connue (sinon lire sur la longueur et laisser(?) la socket bloquante) + do + { + //if(!data.ctrl(data.getLen() + pas, TRUE)) + // return FALSE; // erreur mem + int lg = strlen(data); + if(lg + pas >= 64000) + ; // TODO : taille maxi du buffer atteinte : quid ?? + while((nblu = SSL_read(mClientSsl, data + lg, pas)) < 0 && errno == EWOULDBLOCK && (strlen(data) == 0 || flagInProgress)) ; + if(errno == EINPROGRESS) // 115 + flagInProgress = TRUE; // indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! + else if(nblu > 0) + data[lg + nblu] = 0; //data.setLen(data.getLen() + nblu); + else + { + int err = SSL_get_error(mClientSsl, nblu); + if(err == SSL_ERROR_ZERO_RETURN || err == SSL_ERROR_SYSCALL) + { + trace("Fermeture de la connexion par le client\n"); + return FALSE; + } + + } + // + } while(nblu > 0); + return TRUE; +} + +int ecrireConnexion(char * data) +{ + int nbecrit = 0; + int retSsl; + do + { + nbecrit = SSL_write(mClientSsl, data, strlen(data)); + retSsl = SSL_get_error(mClientSsl, nbecrit); + // pour gerer les envois partiels de SSLwrite + } while(retSsl == SSL_ERROR_WANT_WRITE || retSsl == SSL_ERROR_WANT_READ); + return (nbecrit == strlen(data)); +} + +void setFin(int fin, int depuisSignal) +{ + mFin = fin; + mSignal = depuisSignal; +} + +void attenteFinFils() +{ + if(mNbFils) + { + while(waitpid(-1, NULL, WNOHANG) > 0) + mNbFils--; /* compte tous les fils terminés "en meme temps" (si un fils se termine quand le pere est dans ce handler) */ + } +} + +void demandeArretFilsEtAttente() +{ + /* demander aux fils de s'arrêter */ + kill(0, SIGUSR1); // 0 = tous les process du groupe : tous les fils + // attente fin fils + while(mNbFils) + { + while(waitpid(-1, NULL, WNOHANG) > 0) + mNbFils--; + } +} + +void verifierFinFils() +{ + waitpid(-1, NULL, WNOHANG); +} + +void trt_exit() +{ + // comment sortir ? + demandeArretFilsEtAttente(); + arret(mSocket, TRUE); + exit(-2); +} + +void trt_sig(int sig) +{ + switch(sig) + { + case SIGCHLD: + if(mServeur) + { + //un process fils se termine (forcement recu par le pere/le serveur) + attenteFinFils(); + } + else + { + // fin depuis un fils (session client) d'un module/batch : waitpid ? + } + break; + // + case SIGINT: + case SIGHUP: + case SIGQUIT: + case SIGTERM: // (kill pid) + mFin = TRUE; + mSignal = TRUE; + break; + // + case SIGSEGV: + trt_exit(); + // + case SIGTTOU: + break; // ignorer si sortie terminal depuis arriere plan + // + case SIGUSR1: + if(! mServeur) + { + mFin = TRUE; + mSignal = TRUE; + } // arret des fils a reception de ce signal + break; + // pour lister les numeros de signaux, taper "kill -l" + } +} + +// ----------------------------------------------------------- +char data[64000]; // buffer de lecture/ecriture sur la socket securisee +void trt_connexion() +{ + //Dynamic req, methode, uri, rep, tmp, fld; + //long meth, cr, nb; + int keepAlive; + // + *data = 0; + keepAlive = TRUE; + while(keepAlive) + { + //tmp.let("GET;HEAD;POST"); + //// lire les donnees entrantes sur la socket // pbm ici bloquant : sans doute pbm de longueur attendue !? a tester + //trace("debut boucle\n"); + if ( ! lireConnexion(data)) + break; // fin du client + trace("lu:\n%s\n", data); + if(strstr(data,"keep-alive") == NULL) + keepAlive = FALSE; + // + strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); + trace("Reponse:\n%s\n", data); + ecrireConnexion(data); + *data = 0; + //// faire une attente passive ici (sinon consomme trop de CPU) + //trace("Attente fin boucle\n"); + while(attente(10) <= 0 && ! mFin) ; + //if ( ! lireConnexion(data)) + // break; + if(mFin) + break; // sortie sur signal + } + trace("fin cnx client\n"); +} + +// ---------------------------------------------------------- +int main(int argc, char *argv[]) +{ + if(argc != 4 && argc != 5) + { + trace("Usage : %s []\n", argv[0]); + exit(1); + } + int demon = (argv[0][strlen(argv[0]) - 1] == 'd'); + if(argc == 5) + { + flog = argv[4]; + remove(flog); + } + /* */ + int port = atoi(argv[1]); + certificat = argv[2]; + cleprivee = argv[3]; + /* */ + mServeur = TRUE; + mFin = FALSE; + mSignal = FALSE; + mPid = getpid(); + mNbFils = 0; + signal(SIGHUP, trt_sig); + signal(SIGSEGV, trt_sig); + signal(SIGINT, trt_sig); /* ctrl-C */ + signal(SIGQUIT, trt_sig); + signal(SIGTERM, trt_sig); + signal(SIGTTOU, trt_sig); /* ecriture terminal arriere plan */ + signal(SIGCHLD, trt_sig); /* prevenu quand un process fils se termine */ + signal(SIGUSR1, trt_sig); /* sert a demander au fils de s'arrêter suite arrêt du pere */ + signal(SIGUSR2, trt_sig); /* sert a avertir un fils qu'une requête asynchrone est terminee */ + signal(SIGPIPE, SIG_IGN); /* ignorer ce signal pour eviter une erreur lors du sock.write */ + // + mSocket = 0; + mSockServeur = 1; + mSslCtx = NULL; + mClientSsl = NULL; + // + if(demon) + { + if((mPid = fork()) != 0) + { + trace("Lancement en tache de fond du process pid %ld\n", mPid); + exit(0); /* sortie du pere */ + } + mPid = getpid(); + chdir("/"); // permet de ne pas bloquer un filesystem avec ce process + setsid(); + for(int i=0;i < FOPEN_MAX; i++) /* OPEN_MAX sous AIX */ + close(i); + } + // + trace("Demarrage serveur, port %d pid %d mode %d bits\n", port, getpid(), sizeof(long)==4?32:64); + /* initialisations internes openssl */ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + // verification du contexte securise avant de continuer + if( ! securise(certificat, cleprivee, FALSE)) + { + trace("Erreur lors de la mise en place du contexte securise SSL/TLS\n"); + exit(4); + } + else + { + libereSecu(); + } + if(creerServeur(port)) + { + while( ! mFin) + { + if(attente(10) > 0 && ! mFin) // 10 = 1 seconde + { + struct sockaddr_in addr_cnx; + unsigned int size_addr_cnx = sizeof(addr_cnx); + int sock_fils; + if((sock_fils = accept(mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) > 0) + { + unsigned int ipClient = htonl(addr_cnx.sin_addr.s_addr); + long pid_fils = fork(); + if(pid_fils > 0) + { + // dans le pere + mNbFils++; + signal(SIGCHLD, trt_sig); /* SIGCHLD : prevenu quand un process fils se termine */ + trace("Connexion depuis ip %d.%d.%d.%d : creation process pid %ld\n", (ipClient >> 24) & 0xFF, (ipClient >> 16) & 0xFF, (ipClient >> 8) & 0xFF, (ipClient & 0xFF), pid_fils); + arret(sock_fils, TRUE); + } + else if(pid_fils == 0) + { + // dans le fils + mServeur = FALSE; + mNbFils = 0; + mPid = getpid(); + trace("Connexion entrante pid %ld socket %d\n", mPid, sock_fils); + close(mSocket); // le fils n'a pas besoin de la socket serveur mere + mSocket = sock_fils; + mSockServeur = 0; + int arg = 0; + ioctl(mSocket, FIONBIO, &arg); // mettre bloquant : ok en secu SSL + // + if( ! securise(certificat, cleprivee, TRUE)) + { + // erreur : handshake securise SSL/TLS ko avec le client + trace("Erreur de handshake securise SSL/TLS\n"); + break; + } + // + trt_connexion(); + // + break; + } + else + trace("Erreur de fork() creation fils - demande non traitee\n"); + } + verifierFinFils(); + } + else + trace("Attente... %d\n", mSocket); + } + // arret socket en cours + arret(mSocket, TRUE); + if(mServeur) + { + demandeArretFilsEtAttente(); + trace("Arret du serveur\n"); + } + else + trace("Arret du client\n"); + } + else + { + trace("Erreur d'initialisation du socket serveur - ARRET\n"); + } + return(0); +} -- 2.56.0.windows.4 From 352a4b3df0cc80bc5cecbd0a0e83b205e351aa0c Mon Sep 17 00:00:00 2001 From: Deville Date: Sun, 12 Jul 2026 15:41:55 +0200 Subject: [PATCH 3/7] fix: demon mode --- api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api.c b/api.c index 0519e6a..84f71df 100644 --- a/api.c +++ b/api.c @@ -533,10 +533,10 @@ int main(int argc, char *argv[]) exit(0); /* sortie du pere */ } mPid = getpid(); - chdir("/"); // permet de ne pas bloquer un filesystem avec ce process + //chdir("/"); // permet de ne pas bloquer un filesystem avec ce process setsid(); - for(int i=0;i < FOPEN_MAX; i++) /* OPEN_MAX sous AIX */ - close(i); + //for(int i=0;i < FOPEN_MAX; i++) /* OPEN_MAX sous AIX */ + // close(i); } // trace("Demarrage serveur, port %d pid %d mode %d bits\n", port, getpid(), sizeof(long)==4?32:64); -- 2.56.0.windows.4 From b702f8a5482b3ba8f955baa136e95af78d239222 Mon Sep 17 00:00:00 2001 From: Deville Date: Sun, 12 Jul 2026 17:04:03 +0200 Subject: [PATCH 4/7] fix --- api.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/api.c b/api.c index 84f71df..f97c9d8 100644 --- a/api.c +++ b/api.c @@ -51,6 +51,8 @@ void trace(const char * fmt, ...) va_start(args, fmt); if(flog) { + if(*flog == '0') return; // si fichier log = "0" : ne rien afficher ni logguer + // FILE * f = fopen(flog, "a+"); if(f) { @@ -450,9 +452,10 @@ void trt_sig(int sig) } // ----------------------------------------------------------- -char data[64000]; // buffer de lecture/ecriture sur la socket securisee +char data[64000], rep[64000]; // buffer de lecture/ecriture sur la socket securisee void trt_connexion() { + FILE * fp; //Dynamic req, methode, uri, rep, tmp, fld; //long meth, cr, nb; int keepAlive; @@ -470,7 +473,23 @@ void trt_connexion() if(strstr(data,"keep-alive") == NULL) keepAlive = FALSE; // - strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); + //strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); + if((fp = popen("create_ttyd_session.sh", "r")) == NULL) + strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:97\r\n\r\n

Erreur, console de test non disponible, veuillez contacter l'administrateur

"); + else + { + *data = 0; + *rep = 0; + char ligne[10] = {0}; + while (fgets(ligne, sizeof(ligne) - 1, fp)) { + strcat(rep, ligne); + } + pclose(fp); + sprintf(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:%ld", strlen(rep)); + strcat(data, "\r\n\r\n"); + strcat(data, rep); + } + // trace("Reponse:\n%s\n", data); ecrireConnexion(data); *data = 0; @@ -497,7 +516,8 @@ int main(int argc, char *argv[]) if(argc == 5) { flog = argv[4]; - remove(flog); + if(*flog != '0') + remove(flog); } /* */ int port = atoi(argv[1]); -- 2.56.0.windows.4 From bbe362c65d3dec56f83f3c503c794f358ee57985 Mon Sep 17 00:00:00 2001 From: Deville Date: Sun, 12 Jul 2026 17:07:57 +0200 Subject: [PATCH 5/7] fix --- api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.c b/api.c index f97c9d8..02a75fc 100644 --- a/api.c +++ b/api.c @@ -474,7 +474,7 @@ void trt_connexion() keepAlive = FALSE; // //strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); - if((fp = popen("create_ttyd_session.sh", "r")) == NULL) + if((fp = popen("/root/create_ttyd_session.sh", "r")) == NULL) strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:97\r\n\r\n

Erreur, console de test non disponible, veuillez contacter l'administrateur

"); else { -- 2.56.0.windows.4 From afba9c2200ed8430973fdcbe85a1e801e60f120f Mon Sep 17 00:00:00 2001 From: Deville Date: Sun, 12 Jul 2026 18:05:29 +0200 Subject: [PATCH 6/7] fix --- api.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/api.c b/api.c index 02a75fc..29a5f6a 100644 --- a/api.c +++ b/api.c @@ -15,6 +15,8 @@ /* compilation : gcc -o api api.c -Wall -lssl -lcrypto */ +/* ./apid 50000 cert.pem server.key 0 */ + char * flog = NULL; #define TRUE 1 @@ -474,20 +476,24 @@ void trt_connexion() keepAlive = FALSE; // //strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:35\r\n\r\n

Hello World !

"); - if((fp = popen("/root/create_ttyd_session.sh", "r")) == NULL) + remove("/tmp/ttyd.txt"); + system("/root/create_ttyd_session.sh > /tmp/ttyd.txt"); + if((fp = fopen("/tmp/ttyd.txt", "r")) == NULL) strcpy(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:97\r\n\r\n

Erreur, console de test non disponible, veuillez contacter l'administrateur

"); else { *data = 0; *rep = 0; - char ligne[10] = {0}; - while (fgets(ligne, sizeof(ligne) - 1, fp)) { - strcat(rep, ligne); - } - pclose(fp); - sprintf(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:%ld", strlen(rep)); + fseek(fp, 0, SEEK_END); + long lg = ftell(fp); + fseek(fp, 0, SEEK_SET); + fread(rep, lg, 1, fp); + rep[lg] = 0; + fclose(fp); + // + sprintf(data, "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Type:text/html\r\nContent-Length:%ld", lg); strcat(data, "\r\n\r\n"); - strcat(data, rep); + strncat(data, rep, lg); } // trace("Reponse:\n%s\n", data); -- 2.56.0.windows.4 From 14e4b63f9b49ba915c14fb9b6a5fdcb1b9567c80 Mon Sep 17 00:00:00 2001 From: Deville Date: Sun, 12 Jul 2026 19:06:10 +0200 Subject: [PATCH 7/7] feat: appel ttyd depuis wiki php w --- create_ttyd_session.sh | 63 ++++++++++++++++++++++++++++++++++++++++++ wapi.php | 29 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 create_ttyd_session.sh create mode 100644 wapi.php diff --git a/create_ttyd_session.sh b/create_ttyd_session.sh new file mode 100644 index 0000000..4eb223c --- /dev/null +++ b/create_ttyd_session.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# dans /root du serveur docker (avec apid et certificat/cle privee) + +cat /docker/registry/auth/password | docker login 192.168.10.10:5000/v2 -u nicolas --password-stdin + +# Configuration +IMAGE_NAME="192.168.10.10:5000/ttyd_docker:latest" +BASE_PORT=9101 +MAX_PORT=9105 + +# Générer un nom unique (apt install uuid-runtime) +USER_ID=$(uuidgen | cut -d'-' -f1) +CONTAINER_NAME="ttyd_docker_$USER_ID" + +# Trouver un port disponible +find_free_port() { + for ((port=$BASE_PORT; port<=$MAX_PORT; port++)); do + if ! lsof -i :$port > /dev/null; then + echo $port + return 0 + fi + done + return 1 +} + +PORT=$(find_free_port) + +if [ -z "$PORT" ]; then + echo "Aucun port disponible entre $BASE_PORT et $MAX_PORT." + exit 1 +fi + +user=$(uuidgen | cut -d'-' -f1) +pass=$(uuidgen | cut -d'-' -f1) + +# Lancer le conteneur ttyd +docker run -d \ + --name "$CONTAINER_NAME" \ + -p "$PORT":7681 \ + -e TTYD_USER=$user \ + -e TTYD_PASS=$pass \ + --rm \ + --stop-timeout=30 \ + --memory="2g" \ + --cpus="0.75" \ + "$IMAGE_NAME" + +( sleep 7200 && docker stop "$CONTAINER_NAME" ) & + +if [ $? -ne 0 ]; then + echo "Erreur lors du démarrage du conteneur." + exit 1 +fi + +PORT_URL=$(($PORT - $BASE_PORT + 1)) +# Afficher l'URL d'accès +#echo "Session ttyd créée avec succès !" +#echo "Nom du conteneur : $CONTAINER_NAME" +#echo "Conteneur lancé pour 2 heures : URL" +#echo "User: $user / Password: $pass" +#echo "Termine avec succes" + +echo "https://$user:$pass@w-$PORT_URL.lanisys.fr/" \ No newline at end of file diff --git a/wapi.php b/wapi.php new file mode 100644 index 0000000..59b5d57 --- /dev/null +++ b/wapi.php @@ -0,0 +1,29 @@ + [ + 'timeout' => 4, + ], +]); + +echo file_get_contents( + "https://api.lanisys.fr:50000/", + false, + $ctx +); + +$rep = file_get_contents( + "https://api.lanisys.fr:50000/", + false, + $ctx +); + +$pos = strpos($rep, "https://"); +if ($pos !== false) +{ + header("Location: ".substr($rep, $pos)); + exit; +} +else + echo $rep; \ No newline at end of file -- 2.56.0.windows.4