git4pipi/bash-gitonly.c
Mysaa Java 04d63fd09f Premier commit.
Trois programmes:
	- authKeysPg génère un fichier .authorized_keys à partir de la BDD
	- pam_oath_key est un module PAM demandant un mot de passe otp selon la clé de connection SSH utilisée
	- bash-gitonly est un «shell» qui execute les commandes transmises par SSH, uniquement reliées à git et en vérifiant les permissions
2021-05-03 22:29:20 +02:00

107 lines
3.2 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "nargv/nargv.h"
#include <unistd.h> /* for fork */
#include <sys/types.h> /* for pid_t */
#include <sys/wait.h> /* for wait */
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_RESET "\x1b[0m"
#define AUTHORIZED_SHELL_COMMAND "bash-gitonly"
#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
char* isCmdAuthorized(char* cmd){
const char* authorizedCommands[] = {AUTHORIZED_COMMANDS};
for (int i=0; i<AUTHORIZED_COMMANDS_COUNT-1;i++){
char * curseur = cmd;
const char * reader = authorizedCommands[i];
while(*curseur!=' ' && *curseur != '\0' && *curseur==*reader){
curseur++;
reader++;
}
if(*curseur == ' ' || *curseur == '\0')
return curseur;
}
return NULL;
}
int main(int argc, char **argv, char **envp)
{
fprintf(stderr,"Printing environnement: \n");
for (char **env = envp; *env != 0; env++)
{
char *thisEnv = *env;
fprintf(stderr,"%s\n", thisEnv);
}
int counter;
for(counter=0; counter<argc; counter++)
printf("argv[%2d]: %s\n",counter,argv[counter]);
const char* sshcmdname = "/bin/bash-gitonly";
const char* sshcmdflags = "-c";
// 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],sshcmdflags)!=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
char* sshCommandEnd = isCmdAuthorized(argv[2]);
if(sshCommandEnd == NULL){
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;
}
// Récupération de l'utilisateur
// Récupération du repo et du droit d'accès demandés
// Récupération de l'autorisation auprès du serveur Pgsql
// On effectue la commande.
char execFilename[MAX_FULL_EXECFILENAME_LENGTH] = COMMANDS_PATH;
*sshCommandEnd = '\0';
strcat(execFilename, argv[2]);
*sshCommandEnd = ' ';
const char* sshArgs = sshCommandEnd+1;
NARGV* subargv = nargv_parse(argv[2]);
fprintf(stderr,"Trying to parse '%s': %i args\n",sshArgs,subargv->argc);
fprintf(stderr,"Error code: %i\n",subargv->error_code);
for(int i = 0;i<subargv->argc;i++){
fprintf(stderr,"%02d -> %s\n",i,subargv->argv[i]);
}
if (subargv->error_code) {
fprintf(stderr,"nargv parse error: %i: %s: at input column %i\n",
subargv->error_code, subargv->error_message, subargv->error_index);
return 2;
}
pid_t pid=fork();
if (pid==0) { /* child process */
//static char *argv[]={"echo","Foo is my name.",NULL};
execve(execFilename, subargv->argv, (char *const []){NULL});
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;
}