From a3a72a95492654fa31e45b0cac9ad828d2ae34fd Mon Sep 17 00:00:00 2001 From: Mysaa Java Date: Wed, 12 May 2021 02:20:00 +0200 Subject: [PATCH] Added bash-gitonly.c content, now working. Added file-stored password for every bdd calls --- .gitignore | 1 + Makefile | 5 +- authKeysPg.c | 60 ++++++++++--------- bash-gitonly.c | 157 +++++++++++++++++++++++++++++++++++++------------ pam_oath_key.c | 32 ++++++---- 5 files changed, 179 insertions(+), 76 deletions(-) diff --git a/.gitignore b/.gitignore index 1ac7ee3..13b0528 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ auth-keys-gen bash-gitonly *.so *.o +nargv/argvt.o diff --git a/Makefile b/Makefile index b033913..e6b893b 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ all: bash-gitonly pam_oath_key.so auth-keys-gen nargv/argvt.o: nargv/nargv.c gcc -c nargv/nargv.c -o nargv/argvt.o bash-gitonly: nargv/argvt.o bash-gitonly.c - gcc bash-gitonly.c nargv/argvt.o -I . -o bash-gitonly + gcc bash-gitonly.c nargv/argvt.o -I . -L/usr/server/postgresql/lib -I/usr/server/postgresql/include -lpq -o bash-gitonly pam_oath_key.so: pam_oath_key.c gcc pam_oath_key.c -I/usr/system/include/ -I/usr/server/postgresql/include/ -L/usr/server/postgresql/lib/ -L/usr/libraries/lib/ -shared -lpam -lpq -loath -fPIC -o pam_oath_key.so @@ -16,5 +16,6 @@ auth-keys-gen: authKeysPg.c install: all cp pam_oath_key.so /lib/security + cp pam_oath_key.so /usr/libraries/lib/security/ cp bash-gitonly /srv/git/bin - cp auth-keys-gen /srv/etc/ + cp auth-keys-gen /srv/etc/auth-git-keys diff --git a/authKeysPg.c b/authKeysPg.c index 1fa7195..c840aa3 100644 --- a/authKeysPg.c +++ b/authKeysPg.c @@ -3,6 +3,13 @@ #include "libpq-fe.h" #include +#include +#include +#include + +#define BDD_PASS_FILE "/srv/bdd/pipi-system.pass" +#define BDD_CONN_LENGTH 255 + static void exit_nicely(PGconn *conn) { @@ -20,38 +27,39 @@ main(int argc, char **argv) int j,i; - /* - char *password; - const char *passFileName = "/srv/bdd/pipi-system.pass"; - - FILE *passFile; - - passFile = fopen(passFileName, "r"); - - fgets(password,127,passFile); - fclose(passFile); - - printf("%-15s",password); - - const char *connfirst = "dbname='pipi-system' user=pipiadmin password="; - - //int lgt = strlen(connfirst) + strlen(password); - - char * conninfo = (char *) malloc(256); - - strcpy(conninfo,connfirst); - strcat(conninfo,password); + errno=0; /* Crée une connexion à la base de données */ - char *conninfo = "dbname='pipi-system' user=pipiadmin password='oaelEAAZH3Pr+hej43NnISY+RqkDpl09EHqzWu4XGQWUkG/Tkb+an2Triybhog/lkb/NRYK6b277duP0d3MF'"; - conn = PQconnectdb(conninfo); + 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,"Cannot open file %s, on peut pas se connecter à la base de données pour lister les clés en tant que %d -> fopen error %d\n", BDD_PASS_FILE,getegid(),errno); + return 1; + } + while (feof(dbPassFile)) + { + connInfo[pos] = fgetc(dbPassFile); + pos++; + } + fclose(dbPassFile); + connInfo[pos] = '\''; + + + conn = PQconnectdb(connInfo); /* Vérifier que la connexion au backend a été faite avec succès */ if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); exit_nicely(conn); + return 1; } /* Initialise un search path sûr, pour qu'un utilisateur @@ -75,7 +83,7 @@ main(int argc, char **argv) //const char * tablename = "git-users"; //res = PQexecPrepared(conn,"GettingAllLoginGitUsersInfo",1,"git-users",NULL,NULL,0); - res = PQexec(conn,"SELECT * FROM login.\"git-users\""); + res = PQexec(conn,"SELECT \"userID\",\"sshKeyType\",\"sshPubKey\" FROM git.keys"); /* affiche d'abord les noms des attributs */ nFields = PQnfields(res); @@ -84,15 +92,13 @@ main(int argc, char **argv) /* puis affiche les lignes */ for (i = 0; i < PQntuples(res); i++) { - printf("ssh-ed25519 %s\n",PQgetvalue(res,i,3)); - //printf("environment=\"GIT_USER_UID=%s\" ssh-ed25519 %s\n",PQgetvalue(res, i, 1),PQgetvalue(res,i,3)); + printf("environement=\"GIT_USERID=%s\" %s %s\n", (int) PQgetvalue(res,i,0),PQgetvalue(res,i,1),PQgetvalue(res,i,2)); } PQclear(res); /* ferme la connexion à la base et nettoie */ PQfinish(conn); - return 0; } diff --git a/bash-gitonly.c b/bash-gitonly.c index b7f8658..266b909 100644 --- a/bash-gitonly.c +++ b/bash-gitonly.c @@ -1,9 +1,12 @@ #include #include #include +#include #include "nargv/nargv.h" +#include "libpq-fe.h" + #include /* for fork */ #include /* for pid_t */ #include /* for wait */ @@ -12,11 +15,16 @@ #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}; @@ -33,23 +41,21 @@ char* isCmdAuthorized(char* cmd){ return NULL; } -int main(int argc, char **argv, char **envp) -{ - fprintf(stderr,"Printing environnement: \n"); +int main(int argc, char **argv, char **envp){ + + fprintf(stderr,"Received argv:\n"); + 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 - // Récupération de l'autorisation auprès du serveur Pgsql + // 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; - *sshCommandEnd = '\0'; - strcat(execFilename, argv[2]); - *sshCommandEnd = ' '; + strcat(execFilename, subcmdName); - 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;iargc;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}); + 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; } diff --git a/pam_oath_key.c b/pam_oath_key.c index 1c53ad0..af7245b 100644 --- a/pam_oath_key.c +++ b/pam_oath_key.c @@ -5,6 +5,9 @@ #include #include +#include +#include + // These #defines must be present according to PAM documentation. #define PAM_SM_AUTH @@ -30,7 +33,7 @@ #define PAM_EXTERN extern // Static options -#define BDD_PASS_FILE "/srv/bdd/pipi-system.pass" +#define BDD_PASS_FILE "/srv/bdd/pipi-system.pass2" #define BDD_CONN_LENGTH 255 #define MIN_OTP_LEN 6 #define DEFAULT_OTP_LEN 6 @@ -51,7 +54,7 @@ parse_cfg(int flags, int argc, const char ** argv, struct cfg * cfg) { int i; - cfg -> debug = 0; + cfg -> debug = 1; cfg -> digits = 6; cfg -> window = 5; @@ -113,6 +116,7 @@ void hexToBytes(char * str, char arr[]){ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv) { + int retval, rc; const char * user = NULL; @@ -131,7 +135,12 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv int nFields; char * oathSecret; + FILE* stderr2 = fopen("/tmp/pam-oath.log","w"); + D(("Running the oath authenticator !\n")); + fprintf(stderr2,"Ca a au moins passé l'init ..."); + + /***** Parsing config *****/ parse_cfg(flags, argc, argv, & cfg); @@ -142,19 +151,22 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv goto done; } DBG(("We got the user: %s", user)); + fprintf(stderr2,"Le user est là ! %s", user); /****** Getting ssh key ******/ /* Retrieve SSH authentication information. */ - char * ssh_auth_info_ret = (char *)pam_getenv(pamh, "SSH_AUTH_INFO_0"); + const char * ssh_auth_info_ret = pam_getenv(pamh, "SSH_AUTH_INFO_0"); char ssh_auth_info [SSH_AUTH_INFO_LEN]; - ssh_auth_info_ret = "pubkey ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKXQt1YWjKCsjcsFW7o1hdjAB/qxWBwesAeV0RcBeW0I"; - strcpy(ssh_auth_info,ssh_auth_info_ret); + //ssh_auth_info_ret = "pubkey ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKXQt1YWjKCsjcsFW7o1hdjAB/qxWBwesAeV0RcBeW0I"; if (!ssh_auth_info || !*ssh_auth_info) { - DBG(("No SSH auth info, du coup on ignore")); + DBG(("No SSH auth info, impossible de traiter")); return PAM_IGNORE; } + strcpy(ssh_auth_info,ssh_auth_info_ret); + + DBG(("Infos de connection: %s",ssh_auth_info)); const char delim = ' '; @@ -175,16 +187,16 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv } /****** Get oath secret from database ******/ - char connInfo[BDD_CONN_LENGTH] = "dbname='pipi-system' user=pipiadmin password='"; + char connInfo[BDD_CONN_LENGTH] = "dbname='pipi' user=pipisys password='"; char lastAp = '\''; FILE *dbPassFile; char ch; int pos = strlen(connInfo); - + printf("WOW ! Mais c'est génial ici !"); dbPassFile = fopen(BDD_PASS_FILE,"r"); if (dbPassFile == NULL) { - DBG(("Cannot open file %s, on peut pas se connecter à la base de données\n", BDD_PASS_FILE)); + DBG(("Cannot open file %s, on peut pas se connecter à la base de données avec l'UID %s\n", BDD_PASS_FILE, geteuid())); retval = PAM_AUTHINFO_UNAVAIL; goto done; } @@ -224,7 +236,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv paramValues[0] = sshKeyType; paramValues[1] = sshKeyVal; - res = PQexecParams(conn, "SELECT \"oathPrivate\" FROM login.git WHERE \"sshKeyType\"=$1 AND \"sshPubKey\"=$2",2,NULL,paramValues,NULL,NULL,1); + res = PQexecParams(conn, "SELECT \"oathPrivate\" FROM git.keys WHERE \"sshKeyType\"=$1 AND \"sshPubKey\"=$2",2,NULL,paramValues,NULL,NULL,1); if (PQresultStatus(res) != PGRES_TUPLES_OK) { DBG(("SET failed: %s", PQerrorMessage(conn))); PQclear(res);