Nétoyage du code de bash-gitonly
This commit is contained in:
parent
5cf4877a9d
commit
e5c4e6bf13
160
bash-gitonly.c
160
bash-gitonly.c
@ -19,72 +19,82 @@
|
|||||||
|
|
||||||
#define AUTHORIZED_COMMANDS "git-receive-pack","git-upload-pack","git-upload-archive"
|
#define AUTHORIZED_COMMANDS "git-receive-pack","git-upload-pack","git-upload-archive"
|
||||||
#define AUTHORIZED_COMMANDS_COUNT 3
|
#define AUTHORIZED_COMMANDS_COUNT 3
|
||||||
|
|
||||||
#define COMMANDS_PATH "/bin/"
|
#define COMMANDS_PATH "/bin/"
|
||||||
#define MAX_FULL_EXECFILENAME_LENGTH 24
|
#define MAX_FULL_EXECFILENAME_LENGTH 24
|
||||||
#define BDD_PASS_FILE "/pipi-system.pass"
|
#define BDD_PASS_FILE "/pipi-system.pass"
|
||||||
#define BDD_CONN_LENGTH 255
|
#define BDD_CONN_LENGTH 255
|
||||||
|
|
||||||
|
#define ERR(...) \
|
||||||
|
fprintf(stderr, ANSI_COLOR_GREEN);\
|
||||||
|
fprintf(stderr, ##__VA_ARGS__);\
|
||||||
|
fprintf(stderr,ANSI_COLOR_RESET "\n");
|
||||||
|
|
||||||
|
|
||||||
char* isCmdAuthorized(char* cmd){
|
int strArrMem(char * el, const char * arr[]){
|
||||||
const char* authorizedCommands[] = {AUTHORIZED_COMMANDS};
|
int i = 0;
|
||||||
for (int i=0; i<AUTHORIZED_COMMANDS_COUNT-1;i++){
|
while(arr[i]!=NULL){
|
||||||
char * curseur = cmd;
|
if(strcmp(el,arr[i]) == 0)
|
||||||
const char * reader = authorizedCommands[i];
|
return 1;
|
||||||
while(*curseur!=' ' && *curseur != '\0' && *curseur==*reader){
|
i++;
|
||||||
curseur++;
|
}
|
||||||
reader++;
|
return 0;
|
||||||
}
|
|
||||||
if(*curseur == ' ' || *curseur == '\0')
|
|
||||||
return curseur;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp){
|
int main(int argc, char **argv, char **envp){
|
||||||
|
|
||||||
/*
|
const char const * authorizedCommands[] = {AUTHORIZED_COMMANDS};
|
||||||
fprintf(stderr,"Received argv:\n");
|
|
||||||
for(int i=0;i<argc;i++)
|
|
||||||
{
|
|
||||||
fprintf(stderr,"%s\n",argv[i]);
|
|
||||||
}
|
|
||||||
fprintf(stderr,"Received env:\n");
|
|
||||||
for (char **env = envp; *env != 0; env++)
|
|
||||||
{
|
|
||||||
char *thisEnv = *env;
|
|
||||||
fprintf(stderr,"%s\n", thisEnv);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Ce bout de code est ultra-restrictif et risque de planter si SSH change. Le message sera alors reconaissable.
|
|
||||||
if(argc !=3 || (strcmp(argv[0],AUTHORIZED_SHELL_COMMAND)!=0 && strcmp(argv[0],COMMANDS_PATH AUTHORIZED_SHELL_COMMAND)) || strcmp(argv[1],AUTHORIZED_SHELL_FLAG)!=0){
|
|
||||||
fprintf(stderr, ANSI_COLOR_GREEN "Pas de bash ici, il vous faut un «vrai» accès SSH" ANSI_COLOR_RESET "\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verification que la commande envoyée est bien une commande git
|
NARGV* gitargv;
|
||||||
char* sshCommandEnd = isCmdAuthorized(argv[2]);
|
|
||||||
if(sshCommandEnd == NULL){
|
char* repoName;
|
||||||
fprintf(stderr, ANSI_COLOR_GREEN "Wow ! ce canal est réservé aux commandes de données git, pour le reste, utilisez un «vrai» accès SSH" ANSI_COLOR_RESET "\n");
|
|
||||||
return 1;
|
char connInfo[BDD_CONN_LENGTH] = "dbname='pipi' user=pipisys password='";
|
||||||
|
FILE *dbPassFile;
|
||||||
|
int pos = strlen(connInfo);
|
||||||
|
|
||||||
|
char * userID;
|
||||||
|
|
||||||
|
PGconn *conn;
|
||||||
|
PGresult *res;
|
||||||
|
int nFields;
|
||||||
|
|
||||||
|
const char *accessTypeRequestValues[2];
|
||||||
|
char* niveauAutorisation;
|
||||||
|
|
||||||
|
char execFilename[MAX_FULL_EXECFILENAME_LENGTH] = COMMANDS_PATH;
|
||||||
|
|
||||||
|
pid_t gitPid;
|
||||||
|
|
||||||
|
|
||||||
|
// Ce bout de code est ultra-restrictif et risque de planter si SSH change. Le message sera alors reconaissable.
|
||||||
|
if(argc !=3 || (strcmp(argv[0],AUTHORIZED_SHELL_COMMAND)!=0 && strcmp(argv[0],COMMANDS_PATH AUTHORIZED_SHELL_COMMAND)) || strcmp(argv[1],AUTHORIZED_SHELL_FLAG)!=0){
|
||||||
|
ERR("Pas de bash ici, il vous faut un «vrai» accès SSH");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsing de la commande git
|
// Parsing de la commande git
|
||||||
|
gitargv = nargv_parse(argv[2]);
|
||||||
NARGV* subargv = nargv_parse(argv[2]);
|
if (gitargv->error_code) {
|
||||||
if (subargv->error_code) {
|
ERR("Impossible de comprendre la commande, erreur nargv %i: %s: at input column %i", gitargv->error_code, gitargv->error_message, gitargv->error_index);
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
char* subcmdName = subargv->argv[0];
|
|
||||||
|
|
||||||
|
// Verification que la commande envoyée est bien une commande git
|
||||||
|
if(strArrMem(gitargv->argv[0],authorizedCommands)==0){
|
||||||
|
ERR("Wow ! ce canal est réservé aux commandes de données git, pour le reste, utilisez un «vrai» accès SSH");
|
||||||
|
nargv_free(gitargv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Récupération de l'utilisateur
|
// Récupération de l'utilisateur
|
||||||
char * userID = getenv("GIT_USERID");
|
userID = getenv("GIT_USERID");
|
||||||
|
|
||||||
if(userID==NULL){
|
if(userID==NULL){
|
||||||
fprintf(stderr,ANSI_COLOR_GREEN "Impossible de récupérer votre identifiant utilisateur ..." ANSI_COLOR_RESET "\n");
|
ERR("Impossible de récupérer votre identifiant utilisateur ...");
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,17 +102,13 @@ int main(int argc, char **argv, char **envp){
|
|||||||
// Récupération du repo et du droit d'accès demandés
|
// Récupération du repo et du droit d'accès demandés
|
||||||
// Normalement, la commande n'a que deux éléments:
|
// Normalement, la commande n'a que deux éléments:
|
||||||
|
|
||||||
char* repoName = subargv->argv[1];
|
repoName = gitargv->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");
|
dbPassFile = fopen(BDD_PASS_FILE,"r");
|
||||||
if (dbPassFile == NULL) {
|
if (dbPassFile == NULL) {
|
||||||
fprintf(stderr,ANSI_COLOR_GREEN "Cannot open file %s, on peut pas se connecter à la base de données en tant que l'uid %d" ANSI_COLOR_RESET "\n",BDD_PASS_FILE,geteuid());
|
ERR("Cannot open file %s, on peut pas se connecter à la base de données en tant que l'uid %d", BDD_PASS_FILE, geteuid());
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
while (feof(dbPassFile))
|
while (feof(dbPassFile))
|
||||||
@ -113,79 +119,77 @@ int main(int argc, char **argv, char **envp){
|
|||||||
fclose(dbPassFile);
|
fclose(dbPassFile);
|
||||||
connInfo[pos] = '\'';
|
connInfo[pos] = '\'';
|
||||||
|
|
||||||
PGconn *conn;
|
|
||||||
|
|
||||||
conn = PQconnectdb(connInfo);
|
conn = PQconnectdb(connInfo);
|
||||||
PGresult *res;
|
|
||||||
int nFields;
|
|
||||||
|
|
||||||
/* Vérifier que la connexion au backend a été faite avec succès */
|
/* Vérifier que la connexion au backend a été faite avec succès */
|
||||||
if (PQstatus(conn) != CONNECTION_OK) {
|
if (PQstatus(conn) != CONNECTION_OK) {
|
||||||
fprintf(stderr,ANSI_COLOR_GREEN "Connection to database failed: %s" ANSI_COLOR_RESET "\n",PQerrorMessage(conn));
|
ERR("Connection to database failed: %s",PQerrorMessage(conn));
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
res = PQexec(conn,
|
res = PQexec(conn,
|
||||||
"SELECT pg_catalog.set_config('search_path', '', false)");
|
"SELECT pg_catalog.set_config('search_path', '', false)");
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
||||||
fprintf(stderr,ANSI_COLOR_GREEN "SET failed: %s" ANSI_COLOR_RESET "\n",PQerrorMessage(conn));
|
ERR("SET failed: %s", PQerrorMessage(conn));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
// Récupération de l'autorisation auprès du serveur Pgsql
|
// Récupération de l'autorisation auprès du serveur Pgsql
|
||||||
|
accessTypeRequestValues[0] = userID;
|
||||||
|
accessTypeRequestValues[1] = repoName;
|
||||||
|
|
||||||
const char *paramValues[2];
|
res = PQexecParams(conn, "SELECT git.\"AccessType\"($1,$2)",2,NULL,accessTypeRequestValues,NULL,NULL,1);
|
||||||
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) {
|
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));
|
ERR("Impossible de lancer la requête SQL pour les autorisations: %s",PQerrorMessage(conn));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nFields = PQntuples(res);
|
nFields = PQntuples(res);
|
||||||
// Il y a toujours une seule valeur retournée, renvoie NULL si il n'y a rien
|
// Il y a toujours une seule valeur retournée, renvoie NULL si il n'y a rien
|
||||||
char* niveauAutorisation;
|
|
||||||
niveauAutorisation = PQgetvalue(res, 0, 0);
|
niveauAutorisation = PQgetvalue(res, 0, 0);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
fprintf(stderr,ANSI_COLOR_GREEN "Autorisation: sur %s pour l'id %s -> %s" ANSI_COLOR_RESET "\n",repoName,userID,niveauAutorisation);
|
//ERR("Autorisation: sur %s pour l'id %s -> %s",repoName,userID,niveauAutorisation));
|
||||||
if(niveauAutorisation[0]=='\0'){// If the string is empty i.e. NULL authorisations
|
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");
|
ERR("Vous n'avez pas le droit d'accéder à ce repo. Il n'existe peut-être même pas ...");
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Déjà on a la lecture
|
// Déjà on a la lecture
|
||||||
|
|
||||||
if(strcmp(subcmdName,"git-receive-pack")==0){
|
if(strcmp(gitargv->argv[0],"git-receive-pack")==0){
|
||||||
// Il nous faut aussi le droit d'écriture
|
// Il nous faut aussi le droit d'écriture
|
||||||
if(strcmp(niveauAutorisation,"WRITE")!=0){
|
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");
|
ERR("Vous n'avez pas le droit d'écrire dans ce repo.");
|
||||||
|
nargv_free(gitargv);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On effectue la commande.
|
// On effectue la commande.
|
||||||
|
// Pour l'instant execFilename = COMMANDS_PATH;
|
||||||
char execFilename[MAX_FULL_EXECFILENAME_LENGTH] = COMMANDS_PATH;
|
strcat(execFilename, gitargv->argv[0]);
|
||||||
strcat(execFilename, subcmdName);
|
|
||||||
|
|
||||||
|
|
||||||
pid_t pid=fork();
|
gitPid=fork();
|
||||||
if (pid==0) { /* child process */
|
if (gitPid==0) { /* child process */
|
||||||
execve(execFilename, subargv->argv, (char *const []){NULL}); // Pas d'environement
|
execve(execFilename, gitargv->argv, (char *const []){NULL}); // Pas d'environement
|
||||||
exit(127); /* only if execv fails */
|
exit(127); /* only if execv fails */
|
||||||
}
|
}
|
||||||
else { /* pid!=0; parent process */
|
else { /* pid!=0; parent process */
|
||||||
waitpid(pid,0,0); /* wait for child to exit */
|
waitpid(gitPid,0,0); /* wait for child to exit */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
nargv_free(gitargv);
|
||||||
|
return 1;
|
||||||
nargv_free(subargv);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user