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
107 lines
3.2 KiB
C
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;
|
|
}
|