[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
CVS & users managed repositories
From: |
Thomas HERAULT |
Subject: |
CVS & users managed repositories |
Date: |
Tue, 21 Jan 2003 22:11:45 +0100 |
Hi,
On some "large" systems ( ~ 200 users ), I've seen - and worked with -
cvs, where repositories are administred and created by normal users.
This works fine, but raise a security problem, when the system provides
a pserver connection (since the administrators don't want to run one
cvs pserver per repository on a different port, they have to run cvs pserver
as root and trust their users that they won't abuse the 'alias:passwd:real_id'
scheme of CVSROOT/passwd). This is even more critical now, since some
linux distributions - like debian - provide easy ways of configuring inetd
with cvs pserver, and since most administrators like easy ways...
So, I've made a patch (for cvs-1.11 currently), which let an administrator
decide which repositories can be trusted (and cvs pserver run as root)
and which are to be run as another identity. The admin provides a file
like
/usr/CVS/
[bill]/home/bill/.cvs
[norm]/special/nfs/norm/.cvs/apmc
[norm]/special/nfs/norm/.cvs/ddfs
/special/gobal
and cvs pserver runs as bill when dealing with the repository
/home/bill/.cvs, etc... (empty users meaning vanilla behavior).
This does not change the behavior of --allow-root.
Here is the patch attached. Any comment/suggestions/bugs will be
greatly welcome. I will maintain a web page with any new
revision of the patch that I will have to do and more information
at the url http://www.lri.fr/~herault/cvs/
Cheers, /T
PS Since I'm dealing (not commercially - hopefully) with system administrators,
I don't need to say to you that if this patch is interresting and integrated
in the main tree, that would ease my life a lot (it's really hard to convince
this people to compile a new version of an "official linux distribution provided
software" ;-)
============================================
diff -urN cvs-1.11/src/cvs.h cvs-1.11-arfm/src/cvs.h
--- cvs-1.11/src/cvs.h Sat Jul 8 21:57:21 2000
+++ cvs-1.11-arfm/src/cvs.h Tue Jan 21 18:56:07 2003
@@ -454,6 +454,8 @@
void set_local_cvsroot PROTO((char *dir));
void Create_Root PROTO((char *dir, char *rootdir));
void root_allow_add PROTO ((char *));
+void root_allow_add_with_user PROTO ((char *, char *));
+void root_allow_add_from_file PROTO ((char *));
void root_allow_free PROTO ((void));
int root_allow_ok PROTO ((char *));
diff -urN cvs-1.11/src/main.c cvs-1.11-arfm/src/main.c
--- cvs-1.11/src/main.c Thu Sep 7 01:35:04 2000
+++ cvs-1.11-arfm/src/main.c Tue Jan 21 20:37:18 2003
@@ -441,6 +441,7 @@
{"help-synonyms", 0, NULL, 2},
{"help-options", 0, NULL, 4},
{"allow-root", required_argument, NULL, 3},
+ {"allow-root-from-file", required_argument, NULL, 5},
{0, 0, 0, 0}
};
/* `getopt_long' stores the option index here, but right now we
@@ -544,6 +545,10 @@
case 3:
/* --allow-root */
root_allow_add (optarg);
+ break;
+ case 5:
+ /* --allow-root-from-file */
+ root_allow_add_from_file (optarg);
break;
case 'Q':
really_quiet = 1;
diff -urN cvs-1.11/src/root.c cvs-1.11-arfm/src/root.c
--- cvs-1.11/src/root.c Fri Jul 28 00:28:36 2000
+++ cvs-1.11-arfm/src/root.c Tue Jan 21 20:37:25 2003
@@ -172,15 +172,26 @@
/* The root_allow_* stuff maintains a list of legal CVSROOT
directories. Then we can check against them when a remote user
- hands us a CVSROOT directory. */
+ hands us a CVSROOT directory.
+ To each CVSROOT directory may be attached the system name of a user (through
+ the --allow-root-from-file option) such that if one name is attached to a
+ directory, the server will do a setuid(name) when allowing this directory to
+ be a CVSROOT */
+
+struct allowed_root_info {
+ char *path; /* the path of the root to allow */
+ char *user_name; /* the identity under which this root is allowed (if
NULL,
+ the current identity is kept) */
+};
static int root_allow_count;
-static char **root_allow_vector;
+static struct allowed_root_info *root_allow_vector;
static int root_allow_size;
void
-root_allow_add (arg)
- char *arg;
+root_allow_add_with_user (path, name)
+ char *path;
+ char *name;
{
char *p;
@@ -190,14 +201,15 @@
{
root_allow_size = 1;
root_allow_vector =
- (char **) malloc (root_allow_size * sizeof (char *));
+ (struct allowed_root_info *) malloc (
+ root_allow_size * sizeof (struct allowed_root_info));
}
else
{
root_allow_size *= 2;
root_allow_vector =
- (char **) realloc (root_allow_vector,
- root_allow_size * sizeof (char *));
+ (struct allowed_root_info *) realloc (root_allow_vector,
+ root_allow_size * sizeof (struct allowed_root_info));
}
if (root_allow_vector == NULL)
@@ -222,26 +234,110 @@
exit (EXIT_FAILURE);
}
}
- p = malloc (strlen (arg) + 1);
+
+ if (name != NULL)
+ {
+ p = malloc (strlen (name) + 1);
+ if (p == NULL)
+ goto no_memory;
+ strcpy (p, name);
+ root_allow_vector[root_allow_count].user_name = p;
+ }
+ else
+ root_allow_vector[root_allow_count].user_name = NULL;
+
+ p = malloc (strlen (path) + 1);
if (p == NULL)
goto no_memory;
- strcpy (p, arg);
- root_allow_vector[root_allow_count++] = p;
+ strcpy (p, path);
+ root_allow_vector[root_allow_count++].path = p;
+}
+
+void
+root_allow_add (arg)
+ char *arg;
+{
+ root_allow_add_with_user (arg, NULL);
}
void
root_allow_free ()
{
- if (root_allow_vector != NULL)
- free_names (&root_allow_count, root_allow_vector);
+ int i;
+ for(i = 0; i < root_allow_count; i++)
+ {
+ if (root_allow_vector[i].path)
+ free (root_allow_vector[i].path);
+ if (root_allow_vector[i].user_name)
+ free (root_allow_vector[i].user_name);
+ }
+ root_allow_count = 0;
+ if (root_allow_vector)
+ free (root_allow_vector);
root_allow_size = 0;
}
+void
+root_allow_add_from_file (arg)
+ char *arg;
+{
+ FILE *fp;
+ char *path = NULL;
+ size_t path_allocated = 0;
+ char *name = NULL;
+ size_t name_allocated = 0;
+ int c;
+
+ if ((fp=fopen (arg, "r")) == NULL)
+ {
+ error (1, errno, "cannot open %s", arg);
+ return;
+ }
+ while( 1 )
+ {
+ c = getc (fp);
+ if (c == EOF)
+ break;
+ if (c == (int)'[') /* format [username]/path/to/root */
+ {
+ getstr (&name, &name_allocated, fp, ']', 0, PATH_MAX);
+ if (strlen(name) != 0)
+ name[strlen(name)-1] = 0; /* strip trailing ']' */
+ getstr (&path, &path_allocated, fp, '\n', 0, PATH_MAX);
+ }
+ else /* format /path/to/root */
+ {
+ getstr (&path, &path_allocated, fp, '\n', 1, PATH_MAX);
+ if (path_allocated)
+ path[0] = (char)c;
+ }
+ strip_trailing_newlines (path);
+ if ((c == '[') && (path_allocated != 0) && (name_allocated != 0))
+ root_allow_add_with_user (path, name);
+ else if(path_allocated != 0)
+ root_allow_add (path);
+ if (path_allocated != 0)
+ {
+ free(path);
+ path = NULL;
+ path_allocated = 0;
+ }
+ if (name_allocated != 0)
+ {
+ free(name);
+ name = NULL;
+ name_allocated = 0;
+ }
+ }
+ fclose (fp);
+}
+
int
root_allow_ok (arg)
char *arg;
{
int i;
+ struct passwd *pw;
if (root_allow_count == 0)
{
@@ -255,13 +351,40 @@
back "error" rather than waiting for the next request which
expects responses. */
printf ("\
-error 0 Server configuration missing --allow-root in inetd.conf\n");
+error 0 Server configuration missing --allow-root or\
+ --allow-root-from-file in inetd.conf\n");
error_exit ();
}
-
for (i = 0; i < root_allow_count; ++i)
- if (strcmp (root_allow_vector[i], arg) == 0)
- return 1;
+ if (strcmp (root_allow_vector[i].path, arg) == 0)
+ {
+ if (root_allow_vector[i].user_name!=NULL)
+ {
+ pw = getpwnam (root_allow_vector[i].user_name);
+ if (pw!=NULL)
+ {
+ if (setgid (pw->pw_gid) < 0)
+ {
+ /* See comments at setuid call in server.c for more
+ discussion. */
+ printf ("error 0 setgid failed: %s\n",
+ strerror (errno));
+ continue;
+ }
+ if (setuid (pw->pw_uid) < 0)
+ {
+ printf ("error 0 setuid failed : %s\n",
+ strerror (errno));
+ continue;
+ }
+ else
+ return 1;
+ }
+ else
+ continue;
+ }
+ return 1;
+ }
return 0;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- CVS & users managed repositories,
Thomas HERAULT <=