Compare commits
10 Commits
5cf4877a9d
...
6c8dae4c8b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c8dae4c8b | ||
|
|
3393efd811 | ||
|
|
5c6a77ceb9 | ||
|
|
18b2647b12 | ||
|
|
09af348180 | ||
|
|
5edb145822 | ||
|
|
dbfdab99e6 | ||
|
|
760b2cd08a | ||
|
|
7eb49b267b | ||
|
|
e5c4e6bf13 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
auth-keys-gen
|
||||
cgit-config-gen
|
||||
gen-readable-list
|
||||
bash-gitonly
|
||||
*.so
|
||||
*.o
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "nargv"]
|
||||
path = nargv
|
||||
url = https://github.com/hypersoft/nargv
|
||||
[submodule "cgit"]
|
||||
path = cgit
|
||||
url = https://git.zx2c4.com/cgit
|
||||
|
||||
14
Makefile
14
Makefile
@ -1,6 +1,6 @@
|
||||
.PHONY: all install
|
||||
|
||||
all: bash-gitonly pam_oath_key.so auth-keys-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
|
||||
@ -12,10 +12,22 @@ pam_oath_key.so: pam_oath_key.c
|
||||
|
||||
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/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
|
||||
cp pam_oath_key.so /usr/libraries/lib/security/
|
||||
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
|
||||
|
||||
clean:
|
||||
rm argvt.o auth-keys-gen bash-gitonly cgit-config-gen pam_oath_key.so
|
||||
|
||||
67
authKeysPg.c
67
authKeysPg.c
@ -10,34 +10,21 @@
|
||||
#define BDD_PASS_FILE "/srv/bdd/pipi-system.pass"
|
||||
#define BDD_CONN_LENGTH 255
|
||||
|
||||
static void
|
||||
exit_nicely(PGconn *conn)
|
||||
{
|
||||
PQfinish(conn);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
int nFields;
|
||||
|
||||
int j,i;
|
||||
|
||||
errno=0;
|
||||
|
||||
/* Crée une connexion à la base de données */
|
||||
|
||||
char connInfo[BDD_CONN_LENGTH] = "dbname='pipi' user=pipisys password='";
|
||||
char lastAp = '\'';
|
||||
FILE *dbPassFile;
|
||||
char ch;
|
||||
int pos = strlen(connInfo);
|
||||
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
int i;
|
||||
|
||||
|
||||
// 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);
|
||||
@ -51,53 +38,43 @@ main(int argc, char **argv)
|
||||
fclose(dbPassFile);
|
||||
connInfo[pos] = '\'';
|
||||
|
||||
|
||||
// Connecte à la BDD
|
||||
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);
|
||||
PQfinish(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialise un search path sûr, pour qu'un utilisateur
|
||||
malveillant ne puisse prendre le contrôle. */
|
||||
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);
|
||||
exit_nicely(conn);
|
||||
PQfinish(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Il faut libérer PGresult avec PQclear dès que l'on en a plus besoin pour
|
||||
* éviter les fuites de mémoire.
|
||||
*/
|
||||
PQclear(res);
|
||||
|
||||
//res = PQprepare(conn,"GettingAllLoginGitUsersInfo","SELECT * FROM $1",1,NULL);
|
||||
//const char * tablename = "git-users";
|
||||
//res = PQexecPrepared(conn,"GettingAllLoginGitUsersInfo",1,"git-users",NULL,NULL,0);
|
||||
|
||||
res = PQexec(conn,"SELECT \"userID\",\"sshKeyType\",\"sshPubKey\" FROM git.keys");
|
||||
/* affiche d'abord les noms des attributs */
|
||||
nFields = PQnfields(res);
|
||||
|
||||
fprintf(stderr, PQerrorMessage(conn));
|
||||
/* puis affiche les lignes */
|
||||
|
||||
// Demande les données à la BDD
|
||||
res = PQexec(conn,"SELECT \"sshKeyType\",\"sshPubKey\" FROM git.keys");
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
||||
fprintf(stderr,"Impossible de lancer la requête SQL pour les autorisations: %s",PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Renvoie le résultat à travers stdout
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
printf("%s %s\n",PQgetvalue(res,i,1),PQgetvalue(res,i,2));
|
||||
printf("%s %s\n",PQgetvalue(res,i,0),PQgetvalue(res,i,1));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
fprintf(stderr,"La liste des clés a été envoyée\n");
|
||||
/* ferme la connexion à la base et nettoie */
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
178
bash-gitonly.c
178
bash-gitonly.c
@ -19,72 +19,82 @@
|
||||
|
||||
#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
|
||||
|
||||
#define ERR(...) \
|
||||
fprintf(stderr, ANSI_COLOR_GREEN);\
|
||||
fprintf(stderr, ##__VA_ARGS__);\
|
||||
fprintf(stderr,ANSI_COLOR_RESET "\n");
|
||||
|
||||
|
||||
|
||||
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 strArrMem(char * el, const char * arr[]){
|
||||
int i = 0;
|
||||
while(arr[i]!=NULL){
|
||||
if(strcmp(el,arr[i]) == 0)
|
||||
return 1;
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp){
|
||||
|
||||
/*
|
||||
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.
|
||||
const char const * authorizedCommands[] = {AUTHORIZED_COMMANDS};
|
||||
|
||||
NARGV* gitargv;
|
||||
|
||||
char* repoName;
|
||||
|
||||
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[3];
|
||||
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){
|
||||
fprintf(stderr, ANSI_COLOR_GREEN "Pas de bash ici, il vous faut un «vrai» accès SSH" ANSI_COLOR_RESET "\n");
|
||||
ERR("Pas de bash ici, il vous faut un «vrai» accès SSH");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parsing de la commande git
|
||||
gitargv = nargv_parse(argv[2]);
|
||||
if (gitargv->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);
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
// Parsing de la commande git
|
||||
|
||||
NARGV* subargv = nargv_parse(argv[2]);
|
||||
if (subargv->error_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");
|
||||
userID = getenv("GIT_USERID");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
// 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");
|
||||
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;
|
||||
}
|
||||
while (feof(dbPassFile))
|
||||
@ -113,79 +119,65 @@ int main(int argc, char **argv, char **envp){
|
||||
fclose(dbPassFile);
|
||||
connInfo[pos] = '\'';
|
||||
|
||||
PGconn *conn;
|
||||
conn = PQconnectdb(connInfo);
|
||||
PGresult *res;
|
||||
int nFields;
|
||||
|
||||
|
||||
conn = PQconnectdb(connInfo);
|
||||
|
||||
/* 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));
|
||||
ERR("Connection to database failed: %s",PQerrorMessage(conn));
|
||||
nargv_free(gitargv);
|
||||
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));
|
||||
ERR("SET failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
nargv_free(gitargv);
|
||||
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);
|
||||
accessTypeRequestValues[0] = userID;
|
||||
accessTypeRequestValues[1] = repoName;
|
||||
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) {
|
||||
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);
|
||||
nargv_free(gitargv);
|
||||
PQfinish(conn);
|
||||
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 l'id %s -> %s" ANSI_COLOR_RESET "\n",repoName,userID,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");
|
||||
|
||||
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(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;
|
||||
strcat(execFilename, subcmdName);
|
||||
// Pour l'instant execFilename = COMMANDS_PATH;
|
||||
strcat(execFilename, gitargv->argv[0]);
|
||||
|
||||
|
||||
pid_t pid=fork();
|
||||
if (pid==0) { /* child process */
|
||||
execve(execFilename, subargv->argv, (char *const []){NULL}); // Pas d'environement
|
||||
gitPid=fork();
|
||||
if (gitPid==0) { /* child process */
|
||||
execve(execFilename, gitargv->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 */
|
||||
waitpid(gitPid,0,0); /* wait for child to exit */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
nargv_free(subargv);
|
||||
nargv_free(gitargv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
1
cgit
Submodule
1
cgit
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 79e81e35ca472d6d0767eacce2520efce55fbd9d
|
||||
130
cgit-config-gen.c
Normal file
130
cgit-config-gen.c
Normal file
@ -0,0 +1,130 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "libpq-fe.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#define BDD_PASS_FILE "/srv/bdd/pipi-system.pass"
|
||||
#define BDD_CONN_LENGTH 255
|
||||
|
||||
#define CGITRC_BASE_FILE "/srv/etc/cgitrc.base"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
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;
|
||||
int i;
|
||||
char* lastRgid;
|
||||
// Euhhhhhhhhhh
|
||||
/*
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
|
||||
dp = opendir ("/var/run/postgresql/");
|
||||
if (dp != NULL)
|
||||
{
|
||||
while (ep = readdir (dp))
|
||||
fprintf(stderr,"|->%s\n",ep->d_name);
|
||||
(void) closedir (dp);
|
||||
}
|
||||
else
|
||||
perror ("Couldn't open the directory");
|
||||
*/
|
||||
// Affichage de la première partie du rc
|
||||
FILE* fd = fopen(CGITRC_BASE_FILE, "rb");
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr,"Z'arrive pas à ouvrir le fichier '%s' : %s\n", CGITRC_BASE_FILE, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
char c = fgetc(fd);
|
||||
while (!feof(fd))
|
||||
{
|
||||
printf ("%c", c);
|
||||
c = fgetc(fd);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
printf("## Maintenant les repos ##\n\n");
|
||||
|
||||
// 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 les données à la BDD
|
||||
const char const * sqlParamValues[] = {"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);
|
||||
PQfinish(conn);
|
||||
return 1;
|
||||
}
|
||||
lastRgid = "";
|
||||
// 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));
|
||||
}
|
||||
printf("repo.url=%s\n",PQgetvalue(res,i,0));
|
||||
printf("repo.path=/srv/git/%s\n",PQgetvalue(res,i,0));
|
||||
if(PQgetisnull(res,i,1)!=1)
|
||||
printf("repo.owner=%s\n",PQgetvalue(res,i,1));
|
||||
if(PQgetisnull(res,i,2)!=1)
|
||||
printf("repo.desc=%s\n",PQgetvalue(res,i,2));
|
||||
if(PQgetisnull(res,i,3)!=1)
|
||||
printf("repo.logo=%s\n",PQgetvalue(res,i,3));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
34
clone-all.sh
Executable file
34
clone-all.sh
Executable file
@ -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
|
||||
21
getNewUser.sh
Executable file
21
getNewUser.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -lt 1 ]
|
||||
then
|
||||
read -p "L'utilisateur: " user
|
||||
else
|
||||
user=$1
|
||||
fi
|
||||
if [ $# -lt 2 ]
|
||||
then
|
||||
read -p "Le nom du pc: " pc
|
||||
else
|
||||
pc=$2
|
||||
fi
|
||||
|
||||
otpHex=`openssl rand -hex 32`
|
||||
otpBase32=`oathtool -v $otpHex | grep "Base32" | cut -d " " -f 3`
|
||||
qrUrl="otpauth://totp/$pc:$user@git.bernard.com.de?digits=6&issuer=Bernard&secret=$otpBase32"
|
||||
|
||||
qrencode -t UTF8 $qrUrl
|
||||
echo "Le code hexadecimal secret est $otpHex"
|
||||
44
git-backup.sh
Executable file
44
git-backup.sh
Executable file
@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
REPOS=/srv/git/
|
||||
TSTMP=`date '+%s'`
|
||||
BUNDLESTMP="/tmp/bundles/$TSTMP"
|
||||
OUTPUTDIR=/root/git-backup
|
||||
trt()
|
||||
{
|
||||
for fl in `find * -maxdepth 0 -type d ! -name bundles`
|
||||
do
|
||||
cd $fl
|
||||
echo "Traitons $1$fl"
|
||||
if git rev-parse --is-bare-repository >/dev/null 2>&1
|
||||
then
|
||||
git bundle create "$BUNDLESTMP/$1$fl.bundle" --all
|
||||
else
|
||||
mkdir "$BUNDLESTMP/$1$fl"
|
||||
trt "$1$fl/"
|
||||
fi
|
||||
cd ..
|
||||
done
|
||||
}
|
||||
|
||||
mkdir -p "$BUNDLESTMP/"
|
||||
|
||||
for fld in mysaa bernard
|
||||
do
|
||||
mkdir "$BUNDLESTMP/$fld"
|
||||
cd "$REPOS/$fld/"
|
||||
trt "$fld/"
|
||||
done
|
||||
|
||||
mdate=`date "+%yw%U"`
|
||||
fletter="a"
|
||||
while [ -f "$OUTPUTDIR/git-pipi2-$mdate$fletter.tar.gz" ]
|
||||
do
|
||||
if [ ${fletter: -1} == "z" ]
|
||||
then fletter="${fletter}a"
|
||||
else fletter="${fletter::-1}$(echo ${fletter: -1} | tr '0-9a-z' '1-9a-z_')"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Enregistrement sous git-pipi2-$mdate$fletter.tar.gz"
|
||||
tar -czvf "$OUTPUTDIR/git-pipi2-$mdate$fletter.tar.gz" $BUNDLESTMP
|
||||
rm -r $BUNDLESTMP
|
||||
212
pam_oath_key.c
212
pam_oath_key.c
@ -11,25 +11,22 @@
|
||||
#include <arpa/inet.h> //Pour la conversion bigendian/littleendian
|
||||
|
||||
|
||||
// These #defines must be present according to PAM documentation.
|
||||
// Qu'es-ce qui est défini
|
||||
#define PAM_SM_AUTH
|
||||
//#define PAM_SM_ACCOUNT
|
||||
//#define PAM_SM_SESSION
|
||||
//#define PAM_SM_PASSWORD
|
||||
|
||||
|
||||
#include <syslog.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/pam_modutil.h>
|
||||
#include <security/pam_ext.h>
|
||||
|
||||
|
||||
// Les fonctions de debug
|
||||
#define D(x) do {\
|
||||
printf("[%s:%s(%d)] ", __FILE__, __FUNCTION__, __LINE__);\
|
||||
printf x;\
|
||||
printf("\n");\
|
||||
} while (0)
|
||||
#define DBG(x) if (cfg.debug) {\
|
||||
D(x);\
|
||||
#define D(...) \
|
||||
pam_syslog(pamh, LOG_NOTICE, ##__VA_ARGS__);
|
||||
|
||||
#define DBG(...) if(cfg.debug) {\
|
||||
pam_syslog(pamh, LOG_NOTICE, ##__VA_ARGS__);\
|
||||
}
|
||||
|
||||
#define PAM_EXTERN extern
|
||||
@ -62,10 +59,10 @@ static void copyUntilEndline(const char * src, char dest[]){
|
||||
}
|
||||
|
||||
static void
|
||||
parse_cfg(int flags, int argc,
|
||||
const char ** argv, struct cfg * cfg) {
|
||||
parse_cfg(pam_handle_t * pamh, int flags, int argc, const char ** argv, struct cfg * cfg) {
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
cfg -> debug = 1;
|
||||
cfg -> digits = 6;
|
||||
cfg -> window = 5;
|
||||
@ -80,17 +77,17 @@ parse_cfg(int flags, int argc,
|
||||
}
|
||||
|
||||
if (MIN_OTP_LEN > cfg -> digits || cfg -> digits > MAX_OTP_LEN) {
|
||||
D(("La longueur du code otp doit être entre %i et %i. Valeur invalide: digits=%i",MIN_OTP_LEN,MAX_OTP_LEN, cfg -> digits));
|
||||
D("La longueur du code otp doit être entre %i et %i. Valeur invalide: digits=%i",MIN_OTP_LEN,MAX_OTP_LEN, cfg -> digits);
|
||||
}
|
||||
|
||||
if (cfg -> debug) {
|
||||
D(("called."));
|
||||
D(("flags %d argc %d", flags, argc));
|
||||
D("called.");
|
||||
D("flags %d argc %d", flags, argc);
|
||||
for (i = 0; i < argc; i++)
|
||||
D(("argv[%d]=%s", i, argv[i]));
|
||||
D(("debug=%d", cfg -> debug));
|
||||
D(("digits=%d", cfg -> digits));
|
||||
D(("window=%d", cfg -> window));
|
||||
D("argv[%d]=%s", i, argv[i]);
|
||||
D("debug=%d", cfg -> debug);
|
||||
D("digits=%d", cfg -> digits);
|
||||
D("window=%d", cfg -> window);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +96,7 @@ char * strtokk(char * str,const char cutter) {
|
||||
while((*str != cutter) && (*str != '\0'))
|
||||
str++;
|
||||
|
||||
bool strEnd = (*str == '\0');
|
||||
int strEnd = (*str == '\0');
|
||||
*str = '\0';
|
||||
if(!strEnd)
|
||||
str++;
|
||||
@ -131,7 +128,6 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
|
||||
|
||||
int retval, rc;
|
||||
const char * user = NULL;
|
||||
const char * password = NULL;
|
||||
char otp[MAX_OTP_LEN + 1];
|
||||
int password_len = 0;
|
||||
@ -145,75 +141,78 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
PGconn *conn;
|
||||
PGresult *res;
|
||||
int nFields;
|
||||
|
||||
const char * ssh_auth_info_ret;
|
||||
char ssh_auth_info [SSH_AUTH_INFO_LEN];
|
||||
|
||||
int gitUserID;
|
||||
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 ...\n");
|
||||
|
||||
char * authType;
|
||||
char * sshKeyType;
|
||||
char * sshKeyVal;
|
||||
|
||||
char connInfo[BDD_CONN_LENGTH] = "dbname='pipi' user=pipisys password='";
|
||||
FILE *dbPassFile;
|
||||
int pos = strlen(connInfo);
|
||||
|
||||
const char *paramValues[2];
|
||||
|
||||
char oathSecretBin[OTP_SECRET_LEN];
|
||||
int oathSecretBinLen = OTP_SECRET_LEN+1;
|
||||
|
||||
//GIT_USERID=########
|
||||
char envStr[11+8];
|
||||
|
||||
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(flags, argc, argv, & cfg);
|
||||
parse_cfg(pamh, flags, argc, argv, &cfg);
|
||||
|
||||
/***** Getting User *****/
|
||||
retval = pam_get_user(pamh, &user, NULL);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
DBG(("Could not get PAM user: %s", pam_strerror(pamh, retval)));
|
||||
goto done;
|
||||
}
|
||||
DBG(("We got the user: %s", user));
|
||||
fprintf(stderr2,"Le user est là ! %s\n", user);
|
||||
|
||||
/****** Getting ssh key ******/
|
||||
/****** Retrieve SSH authentication information. ******/
|
||||
ssh_auth_info_ret = pam_getenv(pamh, "SSH_AUTH_INFO_0");
|
||||
|
||||
/* Retrieve SSH authentication information. */
|
||||
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 AAAAC3NzaC1lZDI1NTE5AAAAILNTOkgZXdTFzWOC9R1Aeuq30B3lG+Eq8nL76tZsJ9Qn\n c aca prout caca";
|
||||
|
||||
fprintf(stderr2,"Les infos que j'ai récupéré: %s;;\n", ssh_auth_info_ret);
|
||||
|
||||
if (!ssh_auth_info_ret || !*ssh_auth_info_ret) {
|
||||
DBG(("No SSH auth info, impossible de traiter"));
|
||||
D("Impossible de récupérer les données de connection SSH, impossible de traiter");
|
||||
return PAM_AUTHINFO_UNAVAIL;
|
||||
}
|
||||
copyUntilEndline(ssh_auth_info_ret,ssh_auth_info);
|
||||
|
||||
DBG(("Infos de connection: %s",ssh_auth_info));
|
||||
DBG("Infos de connection: %s",ssh_auth_info);
|
||||
|
||||
|
||||
const char delim = ' ';
|
||||
|
||||
char * authType = ssh_auth_info;
|
||||
char * sshKeyType = strtokk(ssh_auth_info, delim);
|
||||
char * sshKeyVal = strtokk(sshKeyType, delim);
|
||||
|
||||
DBG(("Authentification Type: '%s'", authType));
|
||||
DBG(("Authentification KeyType: '%s'", sshKeyType));
|
||||
DBG(("Authentification KeyVal: '%s'", sshKeyVal));
|
||||
authType = ssh_auth_info;
|
||||
sshKeyType = strtokk(ssh_auth_info, ' ');
|
||||
sshKeyVal = strtokk(sshKeyType, ' ');
|
||||
|
||||
DBG("Authentification Type: '%s'", authType);
|
||||
DBG("Authentification KeyType: '%s'", sshKeyType);
|
||||
DBG("Authentification KeyVal: '%s'", sshKeyVal);
|
||||
|
||||
|
||||
rc = oath_init();
|
||||
if (rc != OATH_OK) {
|
||||
DBG(("oath_init() failed (%d)", rc));
|
||||
DBG("oath_init() failed (%d)", rc);
|
||||
retval = PAM_AUTHINFO_UNAVAIL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/****** Get oath secret from database ******/
|
||||
char connInfo[BDD_CONN_LENGTH] = "dbname='pipi' user=pipisys password='";
|
||||
char lastAp = '\'';
|
||||
FILE *dbPassFile;
|
||||
char ch;
|
||||
int pos = strlen(connInfo);
|
||||
|
||||
/****** Get oath secret from database ******/
|
||||
dbPassFile = fopen(BDD_PASS_FILE,"r");
|
||||
if (dbPassFile == NULL) {
|
||||
DBG(("Cannot open file %s, on peut pas se connecter à la base de données avec l'UID %s\n", BDD_PASS_FILE, getuid()));
|
||||
DBG("Cannot open file %s, on peut pas se connecter à la base de données avec l'UID %s\n", BDD_PASS_FILE, getuid());
|
||||
retval = PAM_AUTHINFO_UNAVAIL;
|
||||
goto done;
|
||||
}
|
||||
@ -225,14 +224,13 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
fclose(dbPassFile);
|
||||
connInfo[pos] = '\'';
|
||||
|
||||
fprintf(stderr2,"On se connecte à la bdd\n");
|
||||
|
||||
|
||||
conn = PQconnectdb(connInfo);
|
||||
|
||||
/* Vérifier que la connexion au backend a été faite avec succès */
|
||||
if (PQstatus(conn) != CONNECTION_OK) {
|
||||
DBG(("Connection to database failed: %s", PQerrorMessage(conn)));
|
||||
DBG("Connection to database failed: %s", PQerrorMessage(conn));
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
}
|
||||
@ -240,23 +238,22 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
res = PQexec(conn,
|
||||
"SELECT pg_catalog.set_config('search_path', '', false)");
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
||||
DBG(("SET failed: %s", PQerrorMessage(conn)));
|
||||
DBG("SET failed: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
DBG(("Initialisation de la base de données efféctuée\n"));
|
||||
fprintf(stderr2,"Initialisation de la connection à la bdd effectuée\n");
|
||||
DBG("Initialisation de la base de données efféctuée\n");
|
||||
PQclear(res);
|
||||
|
||||
const char *paramValues[2];
|
||||
|
||||
paramValues[0] = sshKeyType;
|
||||
paramValues[1] = sshKeyVal;
|
||||
|
||||
res = PQexecParams(conn, "SELECT \"userID\",\"oathPrivate\" FROM git.keys WHERE \"sshKeyType\"=$1 AND \"sshPubKey\"=$2",2,NULL,paramValues,NULL,NULL,1);
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
||||
DBG(("Impossible de faire la requete à la BDD: %s", PQerrorMessage(conn)));
|
||||
DBG("Impossible de faire la requete à la BDD: %s", PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
@ -264,7 +261,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
|
||||
nFields = PQntuples(res);
|
||||
if(nFields!=1){
|
||||
DBG(("Aucun code secret oath trouvé pour la clé '%s'", sshKeyVal));
|
||||
DBG("Aucun code secret oath trouvé pour la clé '%s'", sshKeyVal);
|
||||
PQclear(res);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
@ -273,11 +270,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
gitUserID = ntohl(*((int*)PQgetvalue(res, 0, 0)));
|
||||
oathSecret = PQgetvalue(res, 0, 1);
|
||||
|
||||
DBG(("On a récupéré le code secret : %s",oathSecret));
|
||||
|
||||
if(PQgetisnull(res, 0, 0)==1){
|
||||
printf("Le champ est bien nul !\n");
|
||||
}
|
||||
DBG("On a récupéré le code secret : %s",oathSecret);
|
||||
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
@ -285,8 +278,6 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
|
||||
/*** Parsing hex to byte array ***/
|
||||
|
||||
char oathSecretBin[OTP_SECRET_LEN];
|
||||
int oathSecretBinLen = OTP_SECRET_LEN+1;
|
||||
oath_hex2bin(oathSecret,oathSecretBin,&oathSecretBinLen);
|
||||
|
||||
|
||||
@ -300,26 +291,8 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
}
|
||||
|
||||
pmsg[0] = & msg[0];
|
||||
{
|
||||
const char * query_template = "One-time password (OATH) for `%s': ";
|
||||
size_t len = strlen(query_template) + strlen(user);
|
||||
size_t wrote;
|
||||
|
||||
query_prompt = malloc(len);
|
||||
if (!query_prompt) {
|
||||
retval = PAM_BUF_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
wrote = snprintf(query_prompt, len, query_template, user);
|
||||
if (wrote < 0 || wrote >= len) {
|
||||
retval = PAM_BUF_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
msg[0].msg = query_prompt;
|
||||
}
|
||||
|
||||
|
||||
msg[0].msg = "Votre mot de passe OTP: ";
|
||||
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
|
||||
resp = NULL;
|
||||
|
||||
@ -330,32 +303,32 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
query_prompt = NULL;
|
||||
|
||||
if (retval != PAM_SUCCESS) {
|
||||
DBG(("conv returned error: %s", pam_strerror(pamh, retval)));
|
||||
DBG("conv returned error: %s", pam_strerror(pamh, retval));
|
||||
goto done;
|
||||
}
|
||||
|
||||
DBG(("conv returned: %s", resp -> resp));
|
||||
DBG("conv returned: %s", resp -> resp);
|
||||
|
||||
password = resp -> resp;
|
||||
|
||||
if (password)
|
||||
password_len = strlen(password);
|
||||
else {
|
||||
DBG(("Could not read password"));
|
||||
DBG("Could not read password");
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (password_len < MIN_OTP_LEN) {
|
||||
DBG(("OTP too short: %s", password));
|
||||
DBG("OTP trop court: %s", password);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
} else if (password_len < cfg.digits) {
|
||||
DBG(("OTP shorter than digits=%d: %s", cfg.digits, password));
|
||||
DBG("OTP trop court, on a demandé plus de chiffres: %s", cfg.digits, password);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
} else if (password_len > MAX_OTP_LEN) {
|
||||
DBG(("OTP too long (and no digits=): %s", password));
|
||||
DBG("OTP trop long: %s", password);
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
} else {
|
||||
@ -363,7 +336,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
password = NULL;
|
||||
}
|
||||
|
||||
DBG(("Pouf ! OTP: %s", otp ? otp : "(null)"));
|
||||
DBG("Pouf ! OTP: %s", otp ? otp : "(null)");
|
||||
|
||||
|
||||
|
||||
@ -371,40 +344,43 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv
|
||||
/****** Validation du mot de passe oath ******/
|
||||
{
|
||||
time_t last_otp;
|
||||
time_t jetzt = 0;
|
||||
time(&jetzt);
|
||||
time_t jetzt;
|
||||
int timeStep = 30;
|
||||
DBG(("Validating oath secret %s of length %i at time %ld",oathSecret,oathSecretBinLen, jetzt));
|
||||
char cdex[32];
|
||||
|
||||
time(&jetzt);
|
||||
|
||||
DBG("Validation du code secret %s, longueur %i, temps %ld",oathSecret,oathSecretBinLen,jetzt);
|
||||
|
||||
rc = oath_totp_validate(oathSecretBin, oathSecretBinLen, jetzt, timeStep, 0, cfg.window, otp);
|
||||
}
|
||||
|
||||
if (rc == OATH_INVALID_OTP) {
|
||||
DBG(("One-time password not authorized to login as user '%s'", user));
|
||||
DBG("Mot de passe OTP invalide.");
|
||||
retval = PAM_AUTH_ERR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
retval = PAM_SUCCESS;
|
||||
|
||||
// On met l'id de l'utisateur pour les autorisations
|
||||
char envStr[11+8];
|
||||
/****** On met l'id de l'utisateur pour les autorisations ******/
|
||||
sprintf(envStr, "GIT_USERID=%d",gitUserID);
|
||||
pam_putenv(pamh,envStr);
|
||||
|
||||
|
||||
/****** Terminé ! ******/
|
||||
done:
|
||||
fclose(stderr2);
|
||||
|
||||
oath_done();
|
||||
free(query_prompt);
|
||||
free(onlypasswd);
|
||||
|
||||
DBG(("Terminé ! [%s]", pam_strerror(pamh, retval)));
|
||||
DBG("Terminé ! [%s]", pam_strerror(pamh, retval));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
|
||||
,const char **argv)
|
||||
{
|
||||
|
||||
62
sql/AccessType.sql
Normal file
62
sql/AccessType.sql
Normal file
@ -0,0 +1,62 @@
|
||||
CREATE OR REPLACE FUNCTION git."AccessType" (
|
||||
gituserid integer,
|
||||
gitrepo character varying
|
||||
)
|
||||
RETURNS git.gitrepoaccesstype
|
||||
LANGUAGE plpgsql
|
||||
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
|
||||
FROM git.perms
|
||||
JOIN git.repos ON "repoID"=repos."ID"
|
||||
WHERE repos.path=gitrepo AND "userID"=gituserid;
|
||||
|
||||
IF selectedrepo != NULL
|
||||
THEN RETURN selectedrepo;
|
||||
END IF;
|
||||
RAISE WARNING 'Le repo na pas marche 2';
|
||||
/* groupe.repo */
|
||||
SELECT MAX(perms."accessType")
|
||||
INTO selectedrepo
|
||||
FROM git.perms
|
||||
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")
|
||||
INTO selectedrepo
|
||||
FROM git.perms
|
||||
JOIN git.repos ON "repoID"=-repos."groupeID"
|
||||
WHERE repos.path=gitrepo AND "userID"=gituserid;
|
||||
|
||||
IF selectedrepo != NULL
|
||||
THEN RETURN selectedrepo;
|
||||
END IF;
|
||||
RAISE WARNING 'Le repo na pas marche 4';
|
||||
/* groupe.repoGroupe */
|
||||
SELECT MAX("accessType")
|
||||
INTO selectedrepo
|
||||
FROM git.perms
|
||||
JOIN git.appartenances ON appartenances."groupeID"=-perms."userID"
|
||||
JOIN git.repos ON "repoID"=-repos."groupeID"
|
||||
WHERE repos.path=gitrepo AND "userID"=gituserid;
|
||||
|
||||
RETURN selectedRepo;
|
||||
|
||||
END
|
||||
$code$
|
||||
44
sql/AccessibleRepos.sql
Normal file
44
sql/AccessibleRepos.sql
Normal file
@ -0,0 +1,44 @@
|
||||
CREATE OR REPLACE FUNCTION git."AccessibleRepos" (
|
||||
gituserid integer,
|
||||
accesst git.gitrepoaccesstype
|
||||
)
|
||||
RETURNS table(
|
||||
ID integer,
|
||||
path character varying(255),
|
||||
name character varying(255),
|
||||
owner character varying(255),
|
||||
description character varying,
|
||||
groupeID integer,
|
||||
logoUrl character varying(255)
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $code$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
/* user.repo */
|
||||
SELECT repos.*
|
||||
FROM git.perms
|
||||
JOIN git.repos ON "repoID"=repos."ID"
|
||||
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">=accesst AND appartenances."utilisateurID"=gituserid
|
||||
UNION
|
||||
/* user.repoGroup */
|
||||
SELECT repos.*
|
||||
FROM git.perms
|
||||
JOIN git.repos ON "repoID"=-repos."groupeID"
|
||||
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">=accesst AND "userID"=gituserid;
|
||||
END
|
||||
$code$
|
||||
144
webterface.c
Normal file
144
webterface.c
Normal file
@ -0,0 +1,144 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "libpq-fe.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
BIN
webterface.cgi
Executable file
BIN
webterface.cgi
Executable file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user