bug-cvs
[Top][All Lists]
Advanced

[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;
 }
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]