#include #include #include #include #include "nargv/nargv.h" #include "libpq-fe.h" #include /* for fork */ #include /* for pid_t */ #include /* for wait */ #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_RESET "\x1b[0m" #define AUTHORIZED_SHELL_COMMAND "bash-gitonly" #define AUTHORIZED_SHELL_FLAG "-c" #define AUTHORIZED_COMMANDS "git-receive-pack","git-upload-pack","git-upload-archive" #define AUTHORIZED_COMMANDS_COUNT 3 #define COMMANDS_PATH "/bin/" #define MAX_FULL_EXECFILENAME_LENGTH 24 #define BDD_PASS_FILE "/pipi-system.pass" #define BDD_CONN_LENGTH 255 char* isCmdAuthorized(char* cmd){ const char* authorizedCommands[] = {AUTHORIZED_COMMANDS}; for (int i=0; ierror_code) { fprintf(stderr,ANSI_COLOR_GREEN "Impossible de comprendre la commande, erreur nargv %i: %s: at input column %i" ANSI_COLOR_RESET "\n", subargv->error_code, subargv->error_message, subargv->error_index); return 1; } char* subcmdName = subargv->argv[0]; // Récupération de l'utilisateur char * userID = getenv("GIT_USERID"); if(userID==NULL){ fprintf(stderr,ANSI_COLOR_GREEN "Impossible de récupérer votre identifiant utilisateur ..." ANSI_COLOR_RESET "\n"); return 1; } // Récupération du repo et du droit d'accès demandés // Normalement, la commande n'a que deux éléments: char* repoName = subargv->argv[1]; char connInfo[BDD_CONN_LENGTH] = "dbname='pipi' user=pipisys password='"; char lastAp = '\''; FILE *dbPassFile; char ch; int pos = strlen(connInfo); dbPassFile = fopen(BDD_PASS_FILE,"r"); if (dbPassFile == NULL) { fprintf(stderr,ANSI_COLOR_GREEN "Cannot open file %s, on peut pas se connecter à la base de données" ANSI_COLOR_RESET "\n",BDD_PASS_FILE); return 1; } while (feof(dbPassFile)) { connInfo[pos] = fgetc(dbPassFile); pos++; } fclose(dbPassFile); connInfo[pos] = '\''; PGconn *conn; conn = PQconnectdb(connInfo); PGresult *res; int nFields; /* Vérifier que la connexion au backend a été faite avec succès */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr,ANSI_COLOR_GREEN "Connection to database failed: %s" ANSI_COLOR_RESET "\n",PQerrorMessage(conn)); return 1; } res = PQexec(conn, "SELECT pg_catalog.set_config('search_path', '', false)"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,ANSI_COLOR_GREEN "SET failed: %s" ANSI_COLOR_RESET "\n",PQerrorMessage(conn)); PQclear(res); return 1; } PQclear(res); // Récupération de l'autorisation auprès du serveur Pgsql const char *paramValues[2]; paramValues[0] = userID; paramValues[1] = repoName; res = PQexecParams(conn, "SELECT git.\"AccessType\"($1,$2)",2,NULL,paramValues,NULL,NULL,1); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,ANSI_COLOR_GREEN "Impossible de lancer la requête SQL pour les autorisations: %s" ANSI_COLOR_RESET "\n",PQerrorMessage(conn)); PQclear(res); return 1; } nFields = PQntuples(res); // Il y a toujours une seule valeur retournée, renvoie NULL si il n'y a rien char* niveauAutorisation; niveauAutorisation=PQgetvalue(res, 0, 0); PQclear(res); PQfinish(conn); fprintf(stderr,ANSI_COLOR_GREEN "Autorisation: sur %s pour %s -> %s" ANSI_COLOR_RESET "\n",userID,repoName,niveauAutorisation); if(niveauAutorisation[0]=='\0'){// If the string is empty i.e. NULL authorisations fprintf(stderr,ANSI_COLOR_GREEN "Vous n'avez pas le droit d'accéder à ce repo. Il n'existe peut-être même pas ..." ANSI_COLOR_RESET "\n"); return 1; } // Déjà on a la lecture if(strcmp(subcmdName,"git-receive-pack")==0){ // Il nous faut aussi le droit d'écriture if(strcmp(niveauAutorisation,"WRITE")!=0){ fprintf(stderr,ANSI_COLOR_GREEN "Vous n'avez pas le droit d'écrire dans ce repo." ANSI_COLOR_RESET "\n"); return 1; } } // On effectue la commande. char execFilename[MAX_FULL_EXECFILENAME_LENGTH] = COMMANDS_PATH; strcat(execFilename, subcmdName); pid_t pid=fork(); if (pid==0) { /* child process */ execve(execFilename, subargv->argv, (char *const []){NULL}); // Pas d'environement exit(127); /* only if execv fails */ } else { /* pid!=0; parent process */ waitpid(pid,0,0); /* wait for child to exit */ } nargv_free(subargv); return 0; }