summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cvs
diff options
context:
space:
mode:
authorTodd T. Fries <todd@cvs.openbsd.org>2000-12-12 07:49:19 +0000
committerTodd T. Fries <todd@cvs.openbsd.org>2000-12-12 07:49:19 +0000
commitd67f0883f7751e4bea39659d6262f0b6fd039c50 (patch)
treeb3a9426bc6e6575add67f34cf5e7db47e8501dad /gnu/usr.bin/cvs
parent381613a2c4d15b41f83bce4ff709289b9ff540a7 (diff)
rsh was changed to ssh. reflect this in error messages. ok deraadt@
Diffstat (limited to 'gnu/usr.bin/cvs')
-rw-r--r--gnu/usr.bin/cvs/src/client.c6
-rw-r--r--gnu/usr.bin/cvs/src/root.c533
2 files changed, 467 insertions, 72 deletions
diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c
index fb98fc04e67..8bc44b2bd38 100644
--- a/gnu/usr.bin/cvs/src/client.c
+++ b/gnu/usr.bin/cvs/src/client.c
@@ -3983,7 +3983,7 @@ start_tcp_server (tofdp, fromfdp)
if (port <= 0)
{
error (0, 0, "CVS_CLIENT_PORT must be a positive number! If you");
- error (0, 0, "are trying to force a connection via rsh, please");
+ error (0, 0, "are trying to force a connection via ssh, please");
error (0, 0, "put \":server:\" at the beginning of your CVSROOT");
error (1, 0, "variable.");
}
@@ -4700,7 +4700,7 @@ start_rsh_server (tofdp, fromfdp)
/* Do the deed. */
rsh_pid = popenRW (rsh_argv, pipes);
if (rsh_pid < 0)
- error (1, errno, "cannot start server via rsh");
+ error (1, errno, "cannot start server via ssh");
/* Give caller the file descriptors. */
*tofdp = pipes[0];
@@ -4771,7 +4771,7 @@ start_rsh_server (tofdp, fromfdp)
rsh_pid = piped_child (argv, tofdp, fromfdp);
if (rsh_pid < 0)
- error (1, errno, "cannot start server via rsh");
+ error (1, errno, "cannot start server via ssh");
}
free (command);
}
diff --git a/gnu/usr.bin/cvs/src/root.c b/gnu/usr.bin/cvs/src/root.c
index 8b7c83807cb..99e9396699b 100644
--- a/gnu/usr.bin/cvs/src/root.c
+++ b/gnu/usr.bin/cvs/src/root.c
@@ -2,32 +2,36 @@
* Copyright (c) 1992, Mark D. Baushke
*
* You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.4 kit.
+ * specified in the README file that comes with the CVS source distribution.
*
* Name of Root
*
* Determine the path to the CVSROOT and set "Root" accordingly.
- * If this looks like of modified clone of Name_Repository() in
- * repos.c, it is...
*/
#include "cvs.h"
+#include "getline.h"
-#ifndef lint
-static const char rcsid[] = "$CVSid: @(#)root.c,v 1.2 1994/09/15 05:32:17 zoo Exp";
-USE(rcsid);
-#endif
+/* Printable names for things in the CVSroot_method enum variable.
+ Watch out if the enum is changed in cvs.h! */
+
+char *method_names[] = {
+ "local", "server (ssh)", "pserver", "kserver", "gserver", "ext", "fork"
+};
+
+#ifndef DEBUG
char *
-Name_Root(dir, update_dir)
- char *dir;
- char *update_dir;
+Name_Root (dir, update_dir)
+ char *dir;
+ char *update_dir;
{
FILE *fpin;
char *ret, *xupdate_dir;
- char root[PATH_MAX];
- char tmp[PATH_MAX];
- char cvsadm[PATH_MAX];
+ char *root = NULL;
+ size_t root_allocated = 0;
+ char *tmp;
+ char *cvsadm;
char *cp;
if (update_dir && *update_dir)
@@ -37,33 +41,29 @@ Name_Root(dir, update_dir)
if (dir != NULL)
{
+ cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
+ tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ROOT) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
}
else
{
- (void) strcpy (cvsadm, CVSADM);
- (void) strcpy (tmp, CVSADM_ROOT);
+ cvsadm = xstrdup (CVSADM);
+ tmp = xstrdup (CVSADM_ROOT);
}
/*
* Do not bother looking for a readable file if there is no cvsadm
* directory present.
*
- * It is possiible that not all repositories will have a CVS/Root
+ * It is possible that not all repositories will have a CVS/Root
* file. This is ok, but the user will need to specify -d
* /path/name or have the environment variable CVSROOT set in
- * order to continue.
- */
+ * order to continue. */
if ((!isdir (cvsadm)) || (!isreadable (tmp)))
{
- if (CVSroot == NULL)
- {
- error (0, 0, "in directory %s:", xupdate_dir);
- error (0, 0, "must set the CVSROOT environment variable");
- error (0, 0, "or specify the '-d' option to %s.", program_name);
- }
- return (NULL);
+ ret = NULL;
+ goto out;
}
/*
@@ -72,12 +72,15 @@ Name_Root(dir, update_dir)
*/
fpin = open_file (tmp, "r");
- if (fgets (root, PATH_MAX, fpin) == NULL)
+ if (getline (&root, &root_allocated, fpin) < 0)
{
+ /* FIXME: should be checking for end of file separately; errno
+ is not set in that case. */
error (0, 0, "in directory %s:", xupdate_dir);
error (0, errno, "cannot read %s", CVSADM_ROOT);
error (0, 0, "please correct this problem");
- return (NULL);
+ ret = NULL;
+ goto out;
}
(void) fclose (fpin);
if ((cp = strrchr (root, '\n')) != NULL)
@@ -85,95 +88,487 @@ Name_Root(dir, update_dir)
/*
* root now contains a candidate for CVSroot. It must be an
- * absolute pathname
+ * absolute pathname or specify a remote server.
*/
+ if (
#ifdef CLIENT_SUPPORT
- /* It must specify a server via remote CVS or be an absolute pathname. */
- if ((strchr (root, ':') == NULL)
- && ! isabsolute (root))
-#else
- if (root[0] != '/')
+ (strchr (root, ':') == NULL) &&
#endif
+ ! isabsolute (root))
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0,
"ignoring %s because it does not contain an absolute pathname.",
CVSADM_ROOT);
- return (NULL);
+ ret = NULL;
+ goto out;
}
#ifdef CLIENT_SUPPORT
if ((strchr (root, ':') == NULL) && !isdir (root))
-#else
+#else /* ! CLIENT_SUPPORT */
if (!isdir (root))
-#endif
+#endif /* CLIENT_SUPPORT */
{
error (0, 0, "in directory %s:", xupdate_dir);
error (0, 0,
"ignoring %s because it specifies a non-existent repository %s",
CVSADM_ROOT, root);
- return (NULL);
+ ret = NULL;
+ goto out;
}
/* allocate space to return and fill it in */
- strip_path (root);
+ strip_trailing_slashes (root);
ret = xstrdup (root);
+ out:
+ free (cvsadm);
+ free (tmp);
+ if (root != NULL)
+ free (root);
return (ret);
}
/*
- * Returns non-zero if the two directories have the same stat values
- * which indicates that they are really the same directories.
- */
-int
-same_directories (dir1, dir2)
- char *dir1;
- char *dir2;
-{
- struct stat sb1;
- struct stat sb2;
- int ret;
-
- if (stat (dir1, &sb1) < 0)
- return (0);
- if (stat (dir2, &sb2) < 0)
- return (0);
-
- ret = 0;
- if ( (memcmp( &sb1.st_dev, &sb2.st_dev, sizeof(dev_t) ) == 0) &&
- (memcmp( &sb1.st_ino, &sb2.st_ino, sizeof(ino_t) ) == 0))
- ret = 1;
-
- return (ret);
-}
-
-
-/*
* Write the CVS/Root file so that the environment variable CVSROOT
* and/or the -d option to cvs will be validated or not necessary for
* future work.
*/
void
Create_Root (dir, rootdir)
- char *dir;
- char *rootdir;
+ char *dir;
+ char *rootdir;
{
FILE *fout;
- char tmp[PATH_MAX];
+ char *tmp;
+
+ if (noexec)
+ return;
/* record the current cvs root */
if (rootdir != NULL)
{
if (dir != NULL)
+ {
+ tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ROOT) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
+ }
else
- (void) strcpy (tmp, CVSADM_ROOT);
+ tmp = xstrdup (CVSADM_ROOT);
+
fout = open_file (tmp, "w+");
if (fprintf (fout, "%s\n", rootdir) < 0)
error (1, errno, "write to %s failed", tmp);
if (fclose (fout) == EOF)
error (1, errno, "cannot close %s", tmp);
+ free (tmp);
+ }
+}
+
+#endif /* ! DEBUG */
+
+
+/* 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. */
+
+static unsigned int root_allow_count;
+static char **root_allow_vector;
+static unsigned int root_allow_size;
+
+void
+root_allow_add (arg)
+ char *arg;
+{
+ char *p;
+
+ if (root_allow_size <= root_allow_count)
+ {
+ if (root_allow_size == 0)
+ {
+ root_allow_size = 1;
+ root_allow_vector =
+ (char **) malloc (root_allow_size * sizeof (char *));
+ }
+ else
+ {
+ root_allow_size *= 2;
+ root_allow_vector =
+ (char **) realloc (root_allow_vector,
+ root_allow_size * sizeof (char *));
+ }
+
+ if (root_allow_vector == NULL)
+ {
+ no_memory:
+ /* Strictly speaking, we're not supposed to output anything
+ now. But we're about to exit(), give it a try. */
+ printf ("E Fatal server error, aborting.\n\
+error ENOMEM Virtual memory exhausted.\n");
+
+ /* I'm doing this manually rather than via error_exit ()
+ because I'm not sure whether we want to call server_cleanup.
+ Needs more investigation.... */
+
+#ifdef SYSTEM_CLEANUP
+ /* Hook for OS-specific behavior, for example socket
+ subsystems on NT and OS2 or dealing with windows
+ and arguments on Mac. */
+ SYSTEM_CLEANUP ();
+#endif
+
+ exit (EXIT_FAILURE);
+ }
+ }
+ p = malloc (strlen (arg) + 1);
+ if (p == NULL)
+ goto no_memory;
+ strcpy (p, arg);
+ root_allow_vector[root_allow_count++] = p;
+}
+
+void
+root_allow_free ()
+{
+ if (root_allow_vector != NULL)
+ free (root_allow_vector);
+ root_allow_count = 0;
+ root_allow_size = 0;
+}
+
+int
+root_allow_ok (arg)
+ char *arg;
+{
+ unsigned int i;
+
+ if (root_allow_count == 0)
+ {
+ /* Probably someone upgraded from CVS before 1.9.10 to 1.9.10
+ or later without reading the documentation about
+ --allow-root. Printing an error here doesn't disclose any
+ particularly useful information to an attacker because a
+ CVS server configured in this way won't let *anyone* in. */
+
+ /* Note that we are called from a context where we can spit
+ 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_exit ();
+ }
+
+ for (i = 0; i < root_allow_count; ++i)
+ if (strcmp (root_allow_vector[i], arg) == 0)
+ return 1;
+ return 0;
+}
+
+/* This global variable holds the global -d option. It is NULL if -d
+ was not used, which means that we must get the CVSroot information
+ from the CVSROOT environment variable or from a CVS/Root file. */
+
+char *CVSroot_cmdline;
+
+/* Parse a CVSROOT variable into its constituent parts -- method,
+ * username, hostname, directory. The prototypical CVSROOT variable
+ * looks like:
+ *
+ * :method:user@host:path
+ *
+ * Some methods may omit fields; local, for example, doesn't need user
+ * and host.
+ *
+ * Returns zero on success, non-zero on failure. */
+
+char *CVSroot_original = NULL; /* the CVSroot that was passed in */
+int client_active; /* nonzero if we are doing remote access */
+CVSmethod CVSroot_method; /* one of the enum values defined in cvs.h */
+char *CVSroot_username; /* the username or NULL if method == local */
+char *CVSroot_hostname; /* the hostname or NULL if method == local */
+char *CVSroot_directory; /* the directory name */
+
+int
+parse_cvsroot (CVSroot)
+ char *CVSroot;
+{
+ static int cvsroot_parsed = 0;
+ char *cvsroot_copy, *p;
+ int check_hostname;
+
+ /* Don't go through the trouble twice. */
+ if (cvsroot_parsed)
+ {
+ error (0, 0, "WARNING (parse_cvsroot): someone called me twice!\n");
+ return 0;
+ }
+
+ CVSroot_original = xstrdup (CVSroot);
+ cvsroot_copy = xstrdup (CVSroot);
+
+ if ((*cvsroot_copy == ':'))
+ {
+ char *method = ++cvsroot_copy;
+
+ /* Access method specified, as in
+ * "cvs -d :pserver:user@host:/path",
+ * "cvs -d :local:e:\path",
+ * "cvs -d :kserver:user@host:/path", or
+ * "cvs -d :fork:/path".
+ * We need to get past that part of CVSroot before parsing the
+ * rest of it.
+ */
+
+ if (! (p = strchr (method, ':')))
+ {
+ error (0, 0, "bad CVSroot: %s", CVSroot);
+ return 1;
+ }
+ *p = '\0';
+ cvsroot_copy = ++p;
+
+ /* Now we have an access method -- see if it's valid. */
+
+ if (strcmp (method, "local") == 0)
+ CVSroot_method = local_method;
+ else if (strcmp (method, "pserver") == 0)
+ CVSroot_method = pserver_method;
+ else if (strcmp (method, "kserver") == 0)
+ CVSroot_method = kserver_method;
+ else if (strcmp (method, "gserver") == 0)
+ CVSroot_method = gserver_method;
+ else if (strcmp (method, "server") == 0)
+ CVSroot_method = server_method;
+ else if (strcmp (method, "ext") == 0)
+ CVSroot_method = ext_method;
+ else if (strcmp (method, "fork") == 0)
+ CVSroot_method = fork_method;
+ else
+ {
+ error (0, 0, "unknown method in CVSroot: %s", CVSroot);
+ return 1;
+ }
+ }
+ else
+ {
+ /* If the method isn't specified, assume
+ SERVER_METHOD/EXT_METHOD if the string contains a colon or
+ LOCAL_METHOD otherwise. */
+
+ CVSroot_method = ((strchr (cvsroot_copy, ':'))
+#ifdef RSH_NOT_TRANSPARENT
+ ? server_method
+#else
+ ? ext_method
+#endif
+ : local_method);
+ }
+
+ client_active = (CVSroot_method != local_method);
+
+ /* Check for username/hostname if we're not LOCAL_METHOD. */
+
+ CVSroot_username = NULL;
+ CVSroot_hostname = NULL;
+
+ if ((CVSroot_method != local_method)
+ && (CVSroot_method != fork_method))
+ {
+ /* Check to see if there is a username in the string. */
+
+ if ((p = strchr (cvsroot_copy, '@')))
+ {
+ CVSroot_username = cvsroot_copy;
+ *p = '\0';
+ cvsroot_copy = ++p;
+ if (*CVSroot_username == '\0')
+ CVSroot_username = NULL;
+ }
+
+ if ((p = strchr (cvsroot_copy, ':')))
+ {
+ CVSroot_hostname = cvsroot_copy;
+ *p = '\0';
+ cvsroot_copy = ++p;
+
+ if (*CVSroot_hostname == '\0')
+ CVSroot_hostname = NULL;
+ }
+ }
+
+ CVSroot_directory = cvsroot_copy;
+
+#if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG)
+ if (CVSroot_method != local_method)
+ {
+ error (0, 0, "Your CVSROOT is set for a remote access method");
+ error (0, 0, "but your CVS executable doesn't support it");
+ error (0, 0, "(%s)", CVSroot);
+ return 1;
+ }
+#endif
+
+ /* Do various sanity checks. */
+
+ if (CVSroot_username && ! CVSroot_hostname)
+ {
+ error (0, 0, "missing hostname in CVSROOT: %s", CVSroot);
+ return 1;
+ }
+
+ check_hostname = 0;
+ switch (CVSroot_method)
+ {
+ case local_method:
+ case fork_method:
+ if (CVSroot_username || CVSroot_hostname)
+ {
+ error (0, 0, "can't specify hostname and username in CVSROOT");
+ error (0, 0, "when using %s access method",
+ CVSroot_method == local_method ? "local" : "fork");
+ error (0, 0, "(%s)", CVSroot);
+ return 1;
+ }
+ /* cvs.texinfo has always told people that CVSROOT must be an
+ absolute pathname. Furthermore, attempts to use a relative
+ pathname produced various errors (I couldn't get it to work),
+ so there would seem to be little risk in making this a fatal
+ error. */
+ if (!isabsolute (CVSroot_directory))
+ error (1, 0, "CVSROOT %s must be an absolute pathname",
+ CVSroot_directory);
+ break;
+ case kserver_method:
+#ifndef HAVE_KERBEROS
+ error (0, 0, "Your CVSROOT is set for a kerberos access method");
+ error (0, 0, "but your CVS executable doesn't support it");
+ error (0, 0, "(%s)", CVSroot);
+ return 1;
+#else
+ check_hostname = 1;
+ break;
+#endif
+ case gserver_method:
+#ifndef HAVE_GSSAPI
+ error (0, 0, "Your CVSROOT is set for a GSSAPI access method");
+ error (0, 0, "but your CVS executable doesn't support it");
+ error (0, 0, "(%s)", CVSroot);
+ return 1;
+#else
+ check_hostname = 1;
+ break;
+#endif
+ case server_method:
+ case ext_method:
+ case pserver_method:
+ check_hostname = 1;
+ break;
+ }
+
+ if (check_hostname)
+ {
+ if (! CVSroot_hostname)
+ {
+ error (0, 0, "didn't specify hostname in CVSROOT: %s", CVSroot);
+ return 1;
+ }
+ }
+
+ if (*CVSroot_directory == '\0')
+ {
+ error (0, 0, "missing directory in CVSROOT: %s", CVSroot);
+ return 1;
}
+
+ /* Hooray! We finally parsed it! */
+ return 0;
+}
+
+
+/* Set up the global CVSroot* variables as if we're using the local
+ repository DIR. DIR must point to storage which will last for the
+ rest of the CVS invocation (for example, the caller might malloc it
+ and never free it, or free it just before exiting CVS). */
+
+void
+set_local_cvsroot (dir)
+ char *dir;
+{
+ CVSroot_original = dir;
+ CVSroot_method = local_method;
+ CVSroot_directory = CVSroot_original;
+ CVSroot_username = NULL;
+ CVSroot_hostname = NULL;
+ client_active = 0;
}
+
+
+#ifdef DEBUG
+/* This is for testing the parsing function. Use
+
+ gcc -I. -I.. -I../lib -DDEBUG root.c -o root
+
+ to compile. */
+
+#include <stdio.h>
+
+char *CVSroot;
+char *program_name = "testing";
+char *command_name = "parse_cvsroot"; /* XXX is this used??? */
+
+/* Toy versions of various functions when debugging under unix. Yes,
+ these make various bad assumptions, but they're pretty easy to
+ debug when something goes wrong. */
+
+void
+error_exit PROTO ((void))
+{
+ exit (1);
+}
+
+char *
+xstrdup (str)
+ const char *str;
+{
+ return strdup (str);
+}
+
+int
+isabsolute (dir)
+ const char *dir;
+{
+ return (dir && (*dir == '/'));
+}
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ program_name = argv[0];
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: %s <CVSROOT>\n", program_name);
+ exit (2);
+ }
+
+ if (parse_cvsroot (argv[1]))
+ {
+ fprintf (stderr, "%s: Parsing failed.\n", program_name);
+ exit (1);
+ }
+ printf ("CVSroot: %s\n", argv[1]);
+ printf ("CVSroot_method: %s\n", method_names[CVSroot_method]);
+ printf ("CVSroot_username: %s\n",
+ CVSroot_username ? CVSroot_username : "NULL");
+ printf ("CVSroot_hostname: %s\n",
+ CVSroot_hostname ? CVSroot_hostname : "NULL");
+ printf ("CVSroot_directory: %s\n", CVSroot_directory);
+
+ exit (0);
+ /* NOTREACHED */
+}
+#endif