diff options
author | Todd T. Fries <todd@cvs.openbsd.org> | 2000-12-12 07:49:19 +0000 |
---|---|---|
committer | Todd T. Fries <todd@cvs.openbsd.org> | 2000-12-12 07:49:19 +0000 |
commit | d67f0883f7751e4bea39659d6262f0b6fd039c50 (patch) | |
tree | b3a9426bc6e6575add67f34cf5e7db47e8501dad /gnu/usr.bin/cvs | |
parent | 381613a2c4d15b41f83bce4ff709289b9ff540a7 (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.c | 6 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/root.c | 533 |
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 |