List for cgit developers and users
 help / color / mirror / Atom feed
* Gitolite support  patch
@ 2012-01-31 18:25 ranger
  2012-01-31 18:31 ` ranger
  2012-02-07  3:19 ` mathstuf
  0 siblings, 2 replies; 3+ messages in thread
From: ranger @ 2012-01-31 18:25 UTC (permalink / raw)


Hello,

I'm using gitolite (https://github.com/sitaramc/gitolite) in my git 
server to limit user's access to specific repos only.

Since I'm using cgit as the web frontend I needed the same functionality 
there as well.

I've created a quick patch to add gitolite config file parsing support 
to cgit.

It reads and parses gitolite.conf config file, extracts the information 
from there (users and groups) and creates allowed repo list. The user 
name is retrieved from REMOTE_USER environment variable since I use 
basic authentication. The config file parsing is basic but that 
currently fits to my needs.

I do not know if there is anyone who needs the same functionality but 
nevertheless I'm attaching my patch. Maybe it could be useful to someone 
else as well.



P.S. I tried to use the gl-auth-command perl script that gitolite itself 
uses, but under CGI and suexec it did not work, so I rather took the 
config file parsing approach.


-- 
rgrds,
Ranger




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Gitolite support  patch
  2012-01-31 18:25 Gitolite support patch ranger
@ 2012-01-31 18:31 ` ranger
  2012-02-07  3:19 ` mathstuf
  1 sibling, 0 replies; 3+ messages in thread
From: ranger @ 2012-01-31 18:31 UTC (permalink / raw)


On 31.01.2012 20:25, The Ranger wrote:
> I've created a quick patch to add gitolite config file parsing support
> to cgit.

diff -puNX exclude.pat cgit-0.9.0.2/cgit.c cgit-gitolite/cgit.c
--- cgit-0.9.0.2/cgit.c	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/cgit.c	2012-01-31 13:03:27.974747168 +0200
@@ -15,6 +15,7 @@
  #include "ui-shared.h"
  #include "ui-stats.h"
  #include "scan-tree.h"
+#include "gitolite.h"

  const char *cgit_version = CGIT_VERSION;

@@ -235,6 +236,9 @@ void config_cb(const char *name, const c
  		add_mimetype(name + 9, value);
  	else if (!strcmp(name, "include"))
  		parse_configfile(expand_macros(value), config_cb);
+	else if (!strcmp(name, "gitolite-conf")) {
+		ctx.cfg.gitolite_conf = gitolite_scan_conf(value, ctx.env.remote_user);
+	}
  }

  static void querystring_cb(const char *name, const char *value)
@@ -309,6 +313,7 @@ static void prepare_context(struct cgit_
  	ctx->cfg.cache_scanrc_ttl = 15;
  	ctx->cfg.cache_static_ttl = -1;
  	ctx->cfg.css = "/cgit.css";
+	ctx->cfg.gitolite_conf = NULL;
  	ctx->cfg.logo = "/cgit.png";
  	ctx->cfg.local_time = 0;
  	ctx->cfg.enable_gitweb_owner = 1;
@@ -345,6 +350,7 @@ static void prepare_context(struct cgit_
  	ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
  	ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
  	ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
+	ctx->env.remote_user = xstrdupn(getenv("REMOTE_USER"));
  	ctx->page.mimetype = "text/html";
  	ctx->page.charset = PAGE_ENCODING;
  	ctx->page.filename = NULL;
@@ -794,6 +800,9 @@ int main(int argc, const char **argv)
  		ctx.cfg.cache_size = 0;
  	err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
  			    ctx.qry.raw, ttl, process_request, &ctx);
+
+	gitolite_free_res(ctx.cfg.gitolite_conf);
+
  	if (err)
  		cgit_print_error(fmt("Error processing page: %s (%d)",
  				     strerror(err), err));
diff -puNX exclude.pat cgit-0.9.0.2/cgit.h cgit-gitolite/cgit.h
--- cgit-0.9.0.2/cgit.h	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/cgit.h	2012-01-25 18:15:01.687362057 +0200
@@ -222,6 +222,7 @@ struct cgit_config {
  	struct string_list mimetypes;
  	struct cgit_filter *about_filter;
  	struct cgit_filter *commit_filter;
+	struct gitolite_conf *gitolite_conf;
  	struct cgit_filter *source_filter;
  };

@@ -249,6 +250,7 @@ struct cgit_environment {
  	char *script_name;
  	char *server_name;
  	char *server_port;
+	char *remote_user;
  };

  struct cgit_context {
Common subdirectories: cgit-0.9.0.2/filters and cgit-gitolite/filters
diff -puNX exclude.pat cgit-0.9.0.2/gitolite.c cgit-gitolite/gitolite.c
--- cgit-0.9.0.2/gitolite.c	1970-01-01 03:00:00.000000000 +0300
+++ cgit-gitolite/gitolite.c	2012-01-31 19:52:42.605533772 +0200
@@ -0,0 +1,232 @@
+/*
+ * gitolite.c
+ *
+ *  Created on: 24.01.2012
+ *      Author: ivari
+ */
+
+#include <stdio.h>
+
+#include "cgit.h"
+#include "gitolite.h"
+
+struct gitolite_option {
+	char option[MAX_OPT_LEN];
+	char value[MAX_OPT_LEN];
+};
+
+//Parse configuration options from gitolite.conf
+static int gitolite_read_option(FILE *file, struct gitolite_option 
*option) {
+	int matches;
+	char line[sizeof(option->option) + sizeof(option->value)];
+	memset(option, 0, sizeof(struct gitolite_option));
+
+	if(fgets(line, sizeof(line), file) == NULL) return -1;
+	matches = sscanf(line, "%s%*[ =\t]%[^\n]s\n", option->option, 
option->value);
+	if(matches < 1) return 0;
+
+	//Handle one big string
+	if(matches == 1) {
+		char *p = strchr(option->option, '=');
+		if(p == NULL) return 0;
+		*p = '\0';
+		strncpy(option->value, p+1, sizeof(option->value));
+		option->value[sizeof(option->value)-1] = 0;
+	}
+
+	//Skip comments
+	if(option->option[0] == '#') return 0;
+	return 1;
+}
+
+//Add repo to list
+static struct gitolite_repo * gitolite_add_repo(struct gitolite_conf 
*conf) {
+	struct gitolite_repo *repo;
+	if(conf == NULL) return NULL;
+
+	repo = xmalloc(sizeof(*repo));
+	if(repo == NULL) return NULL;
+	memset(repo, 0, sizeof(struct gitolite_repo));
+
+	// First repo?
+	if(conf->r_first == NULL) conf->r_first = repo;
+
+	// We have more than one repo?
+	if(conf->r_last != NULL) conf->r_last->next = repo;
+
+	conf->r_last = repo;
+
+	return repo;
+}
+
+//Add group to list
+static struct gitolite_group * gitolite_add_group(struct gitolite_conf 
*conf) {
+	struct gitolite_group *group;
+	if(conf == NULL) return NULL;
+
+	group = xmalloc(sizeof(*group));
+	if(group == NULL) return NULL;
+	memset(group, 0, sizeof(struct gitolite_group));
+
+	if(conf->g_first == NULL) conf->g_first = group;
+	if(conf->g_last != NULL) conf->g_last->next = group;
+
+	conf->g_last = group;
+
+	return group;
+}
+
+static int gitolite_check_group(struct gitolite_conf *conf, const char 
*name) {
+	struct gitolite_group *group;
+
+	if(!strcmp(name, "@all")) return 1;
+
+	if(conf == NULL) return 0;
+
+	group = conf->g_first;
+	while(group != NULL) {
+		if(!strcmp(group->name, name)) return 1;
+		group = group->next;
+	}
+
+	return 0;
+}
+
+static void gitolite_parse_user(struct gitolite_conf *conf, struct 
gitolite_option *option, char *path, const char *user) {
+	struct gitolite_repo *repo;
+	char *p;
+
+	while((p = strrchr(option->value, ' ')) != NULL) {
+		*p = '\0';
+		if(*(p+1) == '@' && gitolite_check_group(conf, p+1) > 0) goto ADDREPO;
+		if(!strcmp(p+1, user)) goto ADDREPO;
+	}
+
+	if(option->value[0] == '@' && gitolite_check_group(conf, 
option->value) > 0) goto ADDREPO;
+
+	//If not current user, skip
+	if(strcmp(option->value, user)) return;
+
+ADDREPO:
+	repo = gitolite_add_repo(conf);
+	repo->path = xstrdup(path);
+}
+
+static void gitolite_parse_group(struct gitolite_conf *conf, struct 
gitolite_option *option, const char *user) {
+	struct gitolite_group *group;
+	char *p;
+
+	while((p = strrchr(option->value, ' ')) != NULL) {
+		*p = '\0';
+		if(strcmp(p+1, user)) continue;
+	}
+
+	if(strcmp(option->value, user)) return;
+
+	group = gitolite_add_group(conf);
+	group->name = xstrdup(option->option);
+}
+
+//Add repos from gitolite.conf file
+struct gitolite_conf * gitolite_scan_conf(const char *gitolite_path, 
const char *user) {
+	FILE *file;
+	struct gitolite_option option;
+	struct gitolite_conf *conf = NULL;
+
+	int i;
+	char *p;
+	char path[MAX_OPT_LEN];
+
+	conf = xmalloc(sizeof(*conf));
+	memset(conf, 0, sizeof(*conf));
+
+	//User not found, deny everything by default
+	if(user == NULL) return conf;
+
+	file = fopen(gitolite_path, "r");
+	if(file == NULL) {
+		fprintf(stderr, "Could not open gitolite config file %s\n", 
gitolite_path);
+		return conf;
+	}
+
+	//Remove @suffix from user names (gitolite does not like this)
+	if ((p = strchr(user, '@')) != NULL) *p = '\0';
+
+	while((i = gitolite_read_option(file, &option)) != -1) {
+		if(i == 0 || *(option.value) == 0) continue;
+
+		// Repo definition
+		if(!strcmp(option.option, "repo")) {
+			strncpy(path, option.value, sizeof(path));
+			path[sizeof(path)-1] = 0;
+			continue;
+		}
+
+		// Access definition
+		if(strcmp(option.option, "R") >= 0) {
+			gitolite_parse_user(conf, &option, path, user);
+			continue;
+		}
+
+		// Group definition
+		if(option.option[0] == '@') {
+			gitolite_parse_group(conf, &option, user);
+			continue;
+		}
+	}
+
+	fclose(file);
+	return conf;
+}
+
+
+
+//Check repo before showing it
+int gitolite_check_repo(struct gitolite_conf *conf, const char *base) {
+	char *p;
+	struct gitolite_repo *repo;
+
+	//No conf set up, disable this check
+	if(conf == NULL) return 1;
+
+	//Remove .git suffix
+	if ((p = strrchr(base, '.')) && !strcmp(p, ".git")) *p = '\0';
+
+	repo = conf->r_first;
+	while(repo != NULL) {
+		if(!strcmp(repo->path, base)) return 1;
+		repo = repo->next;
+	}
+
+	//Repo was not found, deny
+	return 0;
+}
+
+//Cleanup
+void gitolite_free_res(struct gitolite_conf *conf) {
+	struct gitolite_repo *repo;
+	struct gitolite_repo *n_repo;
+
+	struct gitolite_group *group;
+	struct gitolite_group *n_group;
+
+	if(conf == NULL) return;
+
+	//Empty struct, no repos?
+	repo = conf->r_first;
+
+	while(repo != NULL) {
+		n_repo = repo->next;
+		free(repo);
+		repo = n_repo;
+	}
+
+	group = conf->g_first;
+	while(group != NULL) {
+		n_group = group->next;
+		free(group);
+		group = n_group;
+	}
+
+	free(conf);
+}
diff -puNX exclude.pat cgit-0.9.0.2/gitolite.h cgit-gitolite/gitolite.h
--- cgit-0.9.0.2/gitolite.h	1970-01-01 03:00:00.000000000 +0300
+++ cgit-gitolite/gitolite.h	2012-01-31 17:44:02.025566452 +0200
@@ -0,0 +1,35 @@
+/*
+ * gitolite.h
+ *
+ *  Created on: 24.01.2012
+ *      Author: ivari
+ */
+
+#ifndef GITOLITE_H_
+#define GITOLITE_H_
+
+#define MAX_OPT_LEN 256
+
+struct gitolite_conf {
+	struct gitolite_repo *r_first;
+	struct gitolite_repo *r_last;
+
+	struct gitolite_group *g_first;
+	struct gitolite_group *g_last;
+};
+
+struct gitolite_repo {
+	char *path;
+	struct gitolite_repo *next;
+};
+
+struct gitolite_group {
+	char *name;
+	struct gitolite_group *next;
+};
+
+struct gitolite_conf * gitolite_scan_conf(const char *gitolite_path, 
const char *user);
+int gitolite_check_repo(struct gitolite_conf *conf, const char *base);
+void gitolite_free_res(struct gitolite_conf *conf);
+
+#endif /* GITOLITE_H_ */
diff -puNX exclude.pat cgit-0.9.0.2/Makefile cgit-gitolite/Makefile
--- cgit-0.9.0.2/Makefile	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/Makefile	2012-01-25 16:28:49.223364486 +0200
@@ -116,6 +116,7 @@ OBJECTS += ui-summary.o
  OBJECTS += ui-tag.o
  OBJECTS += ui-tree.o
  OBJECTS += vector.o
+OBJECTS += gitolite.o

  ifdef NEEDS_LIBICONV
  	EXTLIBS += -liconv
diff -puNX exclude.pat cgit-0.9.0.2/scan-tree.c cgit-gitolite/scan-tree.c
--- cgit-0.9.0.2/scan-tree.c	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/scan-tree.c	2012-01-26 16:29:53.777586126 +0200
@@ -10,6 +10,7 @@
  #include "cgit.h"
  #include "configfile.h"
  #include "html.h"
+#include "gitolite.h"

  #define MAX_PATH 4096

@@ -99,6 +100,11 @@ static void add_repo(const char *base, c
  	if (!strcmp(rel + strlen(rel) - 5, "/.git"))
  		rel[strlen(rel) - 5] = '\0';

+	if (!gitolite_check_repo(ctx.cfg.gitolite_conf, rel)) {
+		free(rel);
+		return;
+	}
+
  	repo = cgit_add_repo(rel);
  	if (ctx.cfg.remove_suffix)
  		if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git"))
Common subdirectories: cgit-0.9.0.2/tests and cgit-gitolite/tests


-- 
rgrds,
Ranger






^ permalink raw reply	[flat|nested] 3+ messages in thread

* Gitolite support  patch
  2012-01-31 18:25 Gitolite support patch ranger
  2012-01-31 18:31 ` ranger
@ 2012-02-07  3:19 ` mathstuf
  1 sibling, 0 replies; 3+ messages in thread
From: mathstuf @ 2012-02-07  3:19 UTC (permalink / raw)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On Tue, Jan 31, 2012 at 18:25:54 GMT, The Ranger wrote:
> I've created a quick patch to add gitolite config file parsing support
> to cgit.

There was a patch a few months ago that allowed cgit to read the repo's
gitconfig file and extract data from it. This way you could set
cgit.username or something from gitolite and have cgit pick up on it
without tying gitolite into cgit directly.

The original use case was to be able to set parameters such as the
README path and other things that are per-repository and gitolite can
manage with configurations.

- --Ben

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iQIcBAEBCgAGBQJPMJfuAAoJEKaxavVX4C1X9TgQAI0fIKUeXJs6gL4ORNwZAfqL
DPrG47dyW7OvA/iIE87PZELOVHHml8d+HAIBW7mHnfIisemGLPCZUIfpZKpwy+59
UdJgFcyzHEvbAw4QTPiqKahgxuytXRA8Kc7MSLqrDAbOL4aYlDYKWVhzCQk4jWLN
ckQX9kuBmAnkCBwFuBj3vHlT/0BncaCS28lYMWMYD/J5geArQAHVQjY0WlhdYwB1
pUkTYrSZVjmhMg/vQIBn/4ZCMNdgXcaeEf9NZBLWfghzMIbfJDsuXi1tZGve6vlt
hO2Q/wA0MTDbERTvygOKOjdUf7ZMs1J/bSkljGxh9Xfw3Qd+JHMszfKbztuzn9hO
H999nImFsfchAyv/OWFSSRxz5Eh5OZGprZYBBtCpvt9KosmQkjepNDJqD1GCczBh
DKoUoQNsEgfFXvt/6rVupWDROJltyrEWvopV4l3YNAVIy3ly1bV/Saf92petDrfw
52sqFA8rmS1mdWji9gxwxaNsTJB9IZb3mI0UmsD7VhVX+hYKqyl9mFnKGXZ/U6kg
1uCxc7P0ac22iGezCAqUwMO/SELl3hAIquHC0TY0gv0yb7mM/oGiy9SkFzx7tgum
iizXoDnGLhDeWL6t+CRBzwqi7iRUYGTkP74msJK5//pzQkQ05YIvev/R+rr1EnwC
L66DfhPS/lhUIlgkSMWz
=K43B
-----END PGP SIGNATURE-----





^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-02-07  3:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-31 18:25 Gitolite support patch ranger
2012-01-31 18:31 ` ranger
2012-02-07  3:19 ` mathstuf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).