I don't know if you still want the --allow-root-regexp patch merged into
1.12.x, but I found some discussion in the archives and it sounds like
we were waiting on documentation and test cases for the change.
I think this is a good way to prevent access to repositories outside
or downside the allowed hierarchy, while keeping it maintainable (no
list of repositories to rebuild), e.g.
--allow-root-regexp='^/srv/cvs/sources/[^/]+'
Unless there's a better way, here's an updated patch against HEAD :)
------------------------------------------------------------------------
Index: ChangeLog
===================================================================
RCS file: /cvsroot/cvs/ccvs/ChangeLog,v
retrieving revision 1.1348
diff -u -r1.1348 ChangeLog
--- ChangeLog 8 May 2007 12:35:53 -0000 1.1348
+++ ChangeLog 8 May 2007 21:04:30 -0000
@@ -1,3 +1,22 @@
+2007-05-08 Sylvain Beucler <address@hidden>
+
+ * Adapted 2001/2004 patch from Roland Mas <address@hidden>:
+
+ * main.c (main): Use new root_allow_regexp_add function, declare
+ new --allow-root-regexp option parameter.
+
+ * root.c: Added new functions root_allow_regexp_add and
+ root_allow_compare_regexp, new variables
+ root_allow_regexp. Modified root_allow_ok, root_allow_used and
+ root_allow_free. The code adds the matched repository path to
+ root_allow as if specified using --allow-root. --allow-root is not
+ mandatory anymore if --allow-root-regexp is used instead.
+
+ * NEWS, cvs.texinfo: Documented these changes.
+
+ * sanity.sh: added test cases as pserver-3b and pserver-3c,
+ updated pserver-3
+
2007-05-07 Derek Price <address@hidden>
* NEWS: Note removal of remote `cvs init'.
Index: NEWS
===================================================================
RCS file: /cvsroot/cvs/ccvs/NEWS,v
retrieving revision 1.367
diff -u -r1.367 NEWS
--- NEWS 8 May 2007 12:35:53 -0000 1.367
+++ NEWS 8 May 2007 21:04:31 -0000
@@ -23,6 +23,11 @@
* When UseNewInfoFmtStrings is enabled, the %{vV} formats will now
expose the real version instead of NONE for removed files.
+* A new command line option, --allow-root-regexp, was added. It
+allows to specify a list of regular expressions for the repositories
+locations, in addition to the list of exact paths.
+
+
BUG FIXES
* The CVS server will no longer allow clients to run `cvs init'.
Index: doc/cvs.texinfo
===================================================================
RCS file: /cvsroot/cvs/ccvs/doc/cvs.texinfo,v
retrieving revision 1.698
diff -u -r1.698 cvs.texinfo
--- doc/cvs.texinfo 12 Sep 2006 20:30:25 -0000 1.698
+++ doc/cvs.texinfo 8 May 2007 21:04:38 -0000
@@ -2606,6 +2606,10 @@
different @sc{cvsroot} directory will not be allowed to
connect. If there is more than one @sc{cvsroot}
directory which you want to allow, repeat the option.
+If there is a whole class of @sc{cvsroot}
+directories which you want to allow, you can also specify a
+regular expression with the @samp{--allow-root-regexp}
+option. This option is repeatable, too.
(Unfortunately, many versions of @code{inetd} have very small
limits on the number of arguments and/or the total length
of the command. The usual solution to this problem is
@@ -12336,6 +12340,12 @@
in @sc{cvs} 1.9 and older). See @ref{Password
authentication server}.
address@hidden address@hidden
+Specify a regular expression to be matched by legal
address@hidden directories (server only) (not in @sc{cvs}
+1.12.13 and earlier). See @ref{Password authentication
+server}.
+
@item -a
Authenticate all communication (client only) (not in @sc{cvs}
1.9 and older). See @ref{Global options}.
@@ -15944,6 +15954,7 @@
specific reason for denying authorization. Check that
the username and password specified are correct and
that the @code{CVSROOT} specified is allowed by @samp{--allow-root}
+or @samp{--allow-root-regexp}
in @file{inetd.conf}. See @ref{Password authenticated}.
@item cvs @var{command}: Bad root @var{directory}
Index: src/main.c
===================================================================
RCS file: /cvsroot/cvs/ccvs/src/main.c,v
retrieving revision 1.268
diff -u -r1.268 main.c
--- src/main.c 17 May 2006 15:24:30 -0000 1.268
+++ src/main.c 8 May 2007 21:04:38 -0000
@@ -576,6 +576,7 @@
{"verify-arg", required_argument, NULL, 12},
#ifdef SERVER_SUPPORT
{"allow-root", required_argument, NULL, 3},
+ {"allow-root-regexp", required_argument, NULL, 14},
{"timeout", required_argument, NULL, 13},
#endif /* SERVER_SUPPORT */
{0, 0, 0, 0}
@@ -823,6 +824,10 @@
/* --allow-root */
root_allow_add (optarg, gConfigPath);
break;
+ case 14:
+ /* --allow-root-regexp */
+ root_allow_regexp_add (optarg, gConfigPath);
+ break;
case 13:
/* --timeout */
connection_timeout = strtol (optarg, &end, 10);
Index: src/root.c
===================================================================
RCS file: /cvsroot/cvs/ccvs/src/root.c,v
retrieving revision 1.125
diff -u -r1.125 root.c
--- src/root.c 24 Apr 2006 18:50:27 -0000 1.125
+++ src/root.c 8 May 2007 21:04:38 -0000
@@ -285,6 +285,7 @@
directories. Then we can check against them when a remote user
hands us a CVSROOT directory. */
static List *root_allow;
+static List *root_allow_regexp;
static void
delconfig (Node *n)
@@ -308,21 +309,65 @@
}
void
+root_allow_regexp_add (const char *arg, const char *configPath)
+{
+ Node *n;
+
+ if (!root_allow_regexp) root_allow_regexp = getlist();
+ n = getnode();
+ n->key = xstrdup (arg);
+
+ /* This is a regexp, not the final cvsroot path - we cannot attach
+ it a config. So we attach configPath and we'll root_allow_add()
+ the actual, matching root in root_allow_compare_regexp() */
+ n->data = (void*)configPath;
+
+ addnode (root_allow_regexp, n);
+}
+
+void
root_allow_free (void)
{
dellist (&root_allow);
+ dellist (&root_allow_regexp);
}
bool
root_allow_used (void)
{
- return root_allow != NULL;
+ return (root_allow != NULL) || (root_allow_regexp != NULL);
+}
+
+/* walklist() callback for determining if 'root_to_check' matches
+ n->key (a regexp). If yes, 'root_to_check' will be added as if
+ directly specified through --allow-root.
+ */
+static int
+root_allow_compare_regexp (Node *n, void *root_to_check)
+{
+ int status;
+ regex_t re;
+
+ if (regcomp(&re, n->key,
+ REG_EXTENDED|REG_NOSUB) != 0)
+ {
+ return 0; /* report error? */
+ }
+ status = regexec(&re, root_to_check, (size_t) 0, NULL, 0);
+ regfree(&re);
+ if (status == 0)
+ {
+ /* n->data contains gConfigPath */
+ root_allow_add (root_to_check, n->data);
+ return 1;
+ }
+ return 0;
}
bool
root_allow_ok (const char *arg)
{
- if (!root_allow)
+ if (!root_allow && !root_allow_regexp)
{
/* Probably someone upgraded from CVS before 1.9.10 to 1.9.10
or later without reading the documentation about
@@ -334,12 +379,18 @@
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-regexp in
inetd.conf\n");
exit (EXIT_FAILURE);
}
+ /* Look for 'arg' in the list of full-path allowed roots */
if (findnode (root_allow, arg))
return true;
+
+ /* Match 'arg' against the list of allowed roots regexps */
+ if (walklist (root_allow_regexp, root_allow_compare_regexp, (void*)arg))
+ return true;
+
return false;
}
Index: src/root.h
===================================================================
RCS file: /cvsroot/cvs/ccvs/src/root.h,v
retrieving revision 1.24
diff -u -r1.24 root.h
--- src/root.h 24 Apr 2006 18:50:27 -0000 1.24
+++ src/root.h 8 May 2007 21:04:38 -0000
@@ -89,6 +89,7 @@
__attribute__ ((__malloc__));
void Create_Root (const char *dir, const char *rootdir);
void root_allow_add (const char *, const char *configPath);
+void root_allow_regexp_add (const char *, const char *configPath);
void root_allow_free (void);
bool root_allow_used (void);
bool root_allow_ok (const char *);
Index: src/sanity.sh
===================================================================
RCS file: /cvsroot/cvs/ccvs/src/sanity.sh,v
retrieving revision 1.1175
diff -u -r1.1175 sanity.sh
--- src/sanity.sh 8 May 2007 12:35:53 -0000 1.1175
+++ src/sanity.sh 8 May 2007 21:04:51 -0000
@@ -31622,7 +31622,7 @@
willfail: :whocares
EOF
dotest_fail pserver-3 "$servercvs pserver" \
-"error 0 Server configuration missing --allow-root in inetd.conf" <<EOF
+"error 0 Server configuration missing --allow-root or --allow-root-regexp in
inetd.conf" <<EOF
BEGIN AUTH REQUEST
$CVSROOT_DIRNAME
testme
@@ -31640,6 +31640,27 @@
END AUTH REQUEST
EOF
+ regexp='^'`dirname ${CVSROOT_DIRNAME}`'/[^/]+$'
+ dotest pserver-3b "${testcvs} --allow-root-regexp=$regexp pserver" \
+"I LOVE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}
+testme
+Ay::'d
+END AUTH REQUEST
+EOF
+
+ regexp='^'`dirname ${CVSROOT_DIRNAME}`'/[^/]+$'
+ dotest_fail pserver-3c "${testcvs} --allow-root-regexp=$regexp
pserver" \
+"$CPROG pserver: ${CVSROOT_DIRNAME}/subdir: no such repository
+I HATE YOU" <<EOF
+BEGIN AUTH REQUEST
+${CVSROOT_DIRNAME}/subdir
+testme
+Ay::'d
+END AUTH REQUEST
+EOF
+
# Confirm that not sending a newline during auth cannot constitute
# a denial-of-service attack. This assumes that PATH_MAX is less
# than 65536 bytes. If PATH_MAX is larger than 65535 bytes, this