diff --git a/.gitignore b/.gitignore index 3b764c7..002744d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ auth-keys-gen cgit-config-gen +gen-readable-list bash-gitonly *.so *.o diff --git a/Makefile b/Makefile index 5bcc619..180ee14 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: all install -all: bash-gitonly pam_oath_key.so auth-keys-gen cgit-config-gen +all: bash-gitonly pam_oath_key.so auth-keys-gen cgit-config-gen webterface.cgi argvt.o: nargv/nargv.c gcc -c nargv/nargv.c -o argvt.o @@ -14,9 +14,11 @@ auth-keys-gen: authKeysPg.c gcc authKeysPg.c -o auth-keys-gen -L/usr/server/postgresql/lib -I/usr/server/postgresql/include -lpq cgit-config-gen: cgit-config-gen.c gcc cgit-config-gen.c -o cgit-config-gen -L/usr/server/postgresql/lib -I/usr/server/postgresql/include -lpq $(CFLAGS) +webterface.cgi: webterface.c + gcc webterface.c -o webterface.cgi -L/usr/server/postgresql/lib -I/usr/server/postgresql/include -lpq $(CFLAGS) -install-sql: sql/AccessType.sql sql/ReadableRepos.sql - /usr/server/postgresql/bin/psql -Upostgres -dpipi -f sql/AccessType.sql -f sql/ReadableRepos.sql +install-sql: sql/AccessType.sql sql/AccessibleRepos.sql + /usr/server/postgresql/bin/psql -Upostgres -dpipi -f sql/AccessType.sql -f sql/AccessibleRepos.sql install: all cp pam_oath_key.so /lib/security @@ -24,3 +26,5 @@ install: all cp bash-gitonly /srv/git/bin cp auth-keys-gen /srv/etc/auth-git-keys cp cgit-config-gen /srv/etc/cgit-config-gen + cp webterface.cgi /srv/admin/webterface/webterface.cgi + cp clone-all.sh /srv/admin/public/clone-all.sh diff --git a/bash-gitonly.c b/bash-gitonly.c index 3088b97..86f74b9 100644 --- a/bash-gitonly.c +++ b/bash-gitonly.c @@ -59,7 +59,7 @@ int main(int argc, char **argv, char **envp){ PGresult *res; int nFields; - const char *accessTypeRequestValues[2]; + const char *accessTypeRequestValues[3]; char* niveauAutorisation; char execFilename[MAX_FULL_EXECFILENAME_LENGTH] = COMMANDS_PATH; @@ -142,8 +142,8 @@ int main(int argc, char **argv, char **envp){ // Récupération de l'autorisation auprès du serveur Pgsql accessTypeRequestValues[0] = userID; accessTypeRequestValues[1] = repoName; - - res = PQexecParams(conn, "SELECT git.\"AccessType\"($1,$2)",2,NULL,accessTypeRequestValues,NULL,NULL,1); + accessTypeRequestValues[2] = (strcmp(gitargv->argv[0],"git-receive-pack")==0)?"WRITE":"READ"; + res = PQexecParams(conn, "SELECT * FROM git.\"AccessibleRepos\"($1,$3) WHERE path=$2;",3,NULL,accessTypeRequestValues,NULL,NULL,1); if (PQresultStatus(res) != PGRES_TUPLES_OK) { ERR("Impossible de lancer la requête SQL pour les autorisations: %s",PQerrorMessage(conn)); PQclear(res); @@ -153,28 +153,15 @@ int main(int argc, char **argv, char **envp){ } nFields = PQntuples(res); - // Il y a toujours une seule valeur retournée, renvoie NULL si il n'y a rien - niveauAutorisation = PQgetvalue(res, 0, 0); PQclear(res); PQfinish(conn); - //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(nFields<1){ 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; } - - // Déjà on a la lecture - - if(strcmp(gitargv->argv[0],"git-receive-pack")==0){ - // Il nous faut aussi le droit d'écriture - if(strcmp(niveauAutorisation,"WRITE")!=0){ - ERR("Vous n'avez pas le droit d'écrire dans ce repo."); - nargv_free(gitargv); - return 1; - } - } - + // On effectue la commande. // Pour l'instant execFilename = COMMANDS_PATH; strcat(execFilename, gitargv->argv[0]); @@ -192,5 +179,5 @@ int main(int argc, char **argv, char **envp){ nargv_free(gitargv); - return 1; + return 0; } diff --git a/cgit-config-gen.c b/cgit-config-gen.c index b4e06ce..28c5d45 100644 --- a/cgit-config-gen.c +++ b/cgit-config-gen.c @@ -92,10 +92,10 @@ main(int argc, char **argv) } PQclear(res); - + // Demande les données à la BDD const char const * sqlParamValues[] = {"0"}; - res = PQexecParams(conn,"SELECT path,owner,description,logoUrl,groupeID,gdr.nom FROM git.\"ReadableRepos\"($1) JOIN git.\"groupesDeRepo\" AS gdr ON gdr.\"ID\"=groupeID ORDER BY groupeID",1,NULL,sqlParamValues,NULL,NULL,0); + res = PQexecParams(conn,"SELECT path,owner,description,logoUrl,groupeID,gdr.nom FROM git.\"AccessibleRepos\"($1,'READ') JOIN git.\"groupesDeRepo\" AS gdr ON gdr.\"ID\"=groupeID ORDER BY groupeID",1,NULL,sqlParamValues,NULL,NULL,0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr,"Impossible de lancer la requête SQL pour la liste des repos: %s",PQerrorMessage(conn)); PQclear(res); @@ -106,7 +106,7 @@ main(int argc, char **argv) // Renvoie le résultat à travers stdout for (i = 0; i < PQntuples(res); i++) { - + if(PQgetisnull(res,i,4)!=1 && (strcmp(PQgetvalue(res, i, 4),lastRgid)!=0)){ lastRgid = PQgetvalue(res, i, 4); printf("\nsection=%s\n\n",PQgetvalue(res,i,5)); diff --git a/clone-all.sh b/clone-all.sh new file mode 100755 index 0000000..4c506ce --- /dev/null +++ b/clone-all.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +token=FgBxePzpabd+9D1EJWrZ4tEbY6UQ5QLFR+7tdrtfCqFbN210trnyAynByxlsb2voDkz1oR1yoZkPR9mMMwPxjw +liste=`curl https://admin.bernard.com.de/wtf/$token/list-readable-repos` + +for path in $liste +do + + if [ -f ./$path ] + then + echo "Vérification du repo $path" + if [[ ! -z $(git -C "./$path" status -s) ]] + then + echo "Le repository $path a des fichiers non enregistrés dans un commit... faudrait y corriger" + git -C "./$path" status + exit 1 + fi + # Bon. on télécharge + if git -C "./$path" pull + then + /bin/true # Ou bien rien à merge, ou bien ca à marché. + else + # Impossible de merge + echo "Le repository $path a suivi un chemin de commits différent, il faut résoudre ça à la main." + exit 1 + fi + # Enfin, on envoie nos changements + git -C "./$path" push --all + + else + git clone git@bernard.com.de:$path ./$path + fi + +done diff --git a/pam_oath_key.c b/pam_oath_key.c index d500d1d..115007c 100644 --- a/pam_oath_key.c +++ b/pam_oath_key.c @@ -166,6 +166,15 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv D("Running the oath authenticator !\n"); + + D("Environement récupéré:\n"); + + char** envp = pam_getenvlist(pamh); + for (char **env = envp; *env != 0; env++) + { + char *thisEnv = *env; + printf("%s\n", thisEnv); + } /***** Parsing config *****/ parse_cfg(pamh, flags, argc, argv, &cfg); diff --git a/sql/AccessType.sql b/sql/AccessType.sql index f6f86c0..4fc3ae6 100644 --- a/sql/AccessType.sql +++ b/sql/AccessType.sql @@ -8,7 +8,10 @@ AS $code$ DECLARE selectedrepo git.gitrepoaccesstype; BEGIN - + + IF gitrepo LIKE '/%' + THEN gitrepo := SUBSTRING(gitrepo,1,LENGTH(gitrepo)-1); + END IF; /* user.repo */ SELECT MAX("accessType") INTO selectedrepo @@ -16,26 +19,26 @@ BEGIN JOIN git.repos ON "repoID"=repos."ID" WHERE repos.path=gitrepo AND "userID"=gituserid; - RETURN selectedrepo; - IF selectedrepo != NULL THEN RETURN selectedrepo; END IF; - + RAISE WARNING 'Le repo na pas marche 2'; /* groupe.repo */ - SELECT MAX('accessType') + SELECT MAX(perms."accessType") INTO selectedrepo FROM git.perms - JOIN git.repos ON repoID=repos."ID" + JOIN git.repos ON "repoID"=repos."ID" JOIN git.appartenances ON appartenances."groupeID"=-perms."userID" WHERE repos.path=gitrepo AND appartenances."utilisateurID"=gituserid; + IF selectedrepo != NULL THEN RETURN selectedrepo; END IF; + RAISE WARNING 'Le repo na pas marche 3'; /* user.repoGroup */ - SELECT MAX('accessType') + SELECT MAX("accessType") INTO selectedrepo FROM git.perms JOIN git.repos ON "repoID"=-repos."groupeID" @@ -44,9 +47,9 @@ BEGIN IF selectedrepo != NULL THEN RETURN selectedrepo; END IF; - + RAISE WARNING 'Le repo na pas marche 4'; /* groupe.repoGroupe */ - SELECT MAX('accessType') + SELECT MAX("accessType") INTO selectedrepo FROM git.perms JOIN git.appartenances ON appartenances."groupeID"=-perms."userID" diff --git a/sql/ReadableRepos.sql b/sql/AccessibleRepos.sql similarity index 71% rename from sql/ReadableRepos.sql rename to sql/AccessibleRepos.sql index f76ab23..75e01ac 100644 --- a/sql/ReadableRepos.sql +++ b/sql/AccessibleRepos.sql @@ -1,5 +1,6 @@ -CREATE OR REPLACE FUNCTION git."ReadableRepos" ( - gituserid integer +CREATE OR REPLACE FUNCTION git."AccessibleRepos" ( + gituserid integer, + accesst git.gitrepoaccesstype ) RETURNS table( ID integer, @@ -18,26 +19,26 @@ BEGIN SELECT repos.* FROM git.perms JOIN git.repos ON "repoID"=repos."ID" - WHERE "accessType">='READ' AND "userID"=gituserid + WHERE "accessType">=accesst AND "userID"=gituserid UNION /* groupe.repo */ SELECT repos.* FROM git.perms JOIN git.repos ON "repoID"=repos."ID" JOIN git.appartenances ON appartenances."groupeID"=-perms."userID" - WHERE "accessType">='READ' AND appartenances."utilisateurID"=gituserid + WHERE "accessType">=accesst AND appartenances."utilisateurID"=gituserid UNION /* user.repoGroup */ SELECT repos.* FROM git.perms JOIN git.repos ON "repoID"=-repos."groupeID" - WHERE "accessType">='READ' AND "userID"=gituserid + WHERE "accessType">=accesst AND "userID"=gituserid UNION /* groupe.repoGroupe */ SELECT repos.* FROM git.perms JOIN git.appartenances ON appartenances."groupeID"=-perms."userID" JOIN git.repos ON "repoID"=-repos."groupeID" - WHERE "accessType">='READ' AND "userID"=gituserid; + WHERE "accessType">=accesst AND "userID"=gituserid; END $code$ diff --git a/webterface.c b/webterface.c new file mode 100644 index 0000000..2ebf001 --- /dev/null +++ b/webterface.c @@ -0,0 +1,144 @@ +#include +#include +#include "libpq-fe.h" +#include + +#include +#include +#include +#include + +#include + +#define BDD_PASS_FILE "/srv/bdd/pipi-system.pass" +#define BDD_CONN_LENGTH 255 + +int +main(int argc, char **argv, char **envp) +{ + + // Print cgi headers + printf("Content-Type: text/plain; charset=UTF-8\n\n"); + + char* pathInfo = getenv("PATH_INFO"); + if(pathInfo==NULL){ + printf("Je n'ai pas accès au PATH_INFO.\n"); + return 2; + } + + const char slash[] = {'/'}; + char* token = strtok(pathInfo,slash); + if(token == NULL){ + printf("Il vous faut un token non nul pour accéder à l'interface\n"); + return 2; + } + char* action = strtok(NULL,slash); + if(action == NULL){ + printf("Que voulez-vous faire avec votre token %s ?\n",token); + return 2; + } + char* reste = strtok(NULL,slash); + + //printf("Données récupérées: %s, puis %s, puis %s",token,action,reste); + int i; + /* + //Dumping args + for(i = 0; i < argc; i++) + printf("argv[%d] -> %s\n",i,argv[i]); + //Dumping env + for (char **env = envp; *env != 0; env++) + { + char *thisEnv = *env; + printf("env: %s\n", thisEnv); + } + + printf("-------------------------------------------\n"); + */ + char connInfo[BDD_CONN_LENGTH] = "host='/var/run/postgresql' dbname='pipi' user=pipisys password='"; + FILE *dbPassFile; + char ch; + int pos = strlen(connInfo); + + PGconn *conn; + PGresult *res; + + char* userId = "0"; + if(argc>1){ + userId=*(argv+1); + } + + // Récupère le mdp à la BDD + 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,geteuid(),errno); + return 1; + } + while (feof(dbPassFile)) + { + connInfo[pos] = fgetc(dbPassFile); + pos++; + } + fclose(dbPassFile); + connInfo[pos] = '\''; + + + // Connecte à la BDD + conn = PQconnectdb(connInfo); + if (PQstatus(conn) != CONNECTION_OK) + { + fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); + PQfinish(conn); + return 1; + } + res = PQexec(conn, + "SELECT pg_catalog.set_config('search_path', '', false)"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "SET failed: %s", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return 1; + } + PQclear(res); + + // Demande de l'autorisation + + char const * sqlParamValues[] = {action,token}; + res = PQexecParams(conn,"SELECT userID FROM git.tokens WHERE type=$1 AND token=$2",2,NULL,sqlParamValues,NULL,NULL,0); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"Impossible de lancer la requête SQL pour authentifier le token: %s",PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return 1; + } + if(PQntuples(res)<1){ + printf("Ce token est invalide !!!"); + PQclear(res); + PQfinish(conn); + return 0; + } + userId=PQgetvalue(res,0,0); + PQclear(res); + + // Demande les données à la BDD + sqlParamValues[0] = userId; + res = PQexecParams(conn,"SELECT path,owner,description,logoUrl,groupeID,gdr.nom FROM git.\"AccessibleRepos\"($1,'WRITE') JOIN git.\"groupesDeRepo\" AS gdr ON gdr.\"ID\"=groupeID ORDER BY groupeID",1,NULL,sqlParamValues,NULL,NULL,0); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"Impossible de lancer la requête SQL pour la liste des repos: %s",PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return 1; + } + + // Renvoie le résultat à travers stdout + for (i = 0; i < PQntuples(res); i++) + { + printf("%s\n",PQgetvalue(res,i,0)); + } + + + PQclear(res); + PQfinish(conn); + return 0; +} + diff --git a/webterface.cgi b/webterface.cgi new file mode 100755 index 0000000..17038ce Binary files /dev/null and b/webterface.cgi differ