/* CVS rsh client stuff.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. */
#include <sys/cdefs.h>
__RCSID("$NetBSD: rsh-client.c,v 1.3 2017/08/22 10:06:57 christos Exp $");
#include <config.h>
#include "cvs.h"
#include "buffer.h"
#ifdef CLIENT_SUPPORT
#include "rsh-client.h"
#ifndef NO_EXT_METHOD
/* Contact the server by starting it with rsh. */
/* Right now, we have two different definitions for this function,
depending on whether we start the rsh server using popenRW or not.
This isn't ideal, and the best thing would probably be to change
the OS/2 port to be more like the regular Unix client (i.e., by
implementing piped_child)... but I'm doing something else at the
moment, and wish to make only one change at a time. -Karl */
# ifdef START_RSH_WITH_POPEN_RW
/* This is actually a crock -- it's OS/2-specific, for no one else
uses it. If I get time, I want to make piped_child and all the
other stuff in os2/run.c work right. In the meantime, this gets us
up and running, and that's most important. */
void
start_rsh_server (cvsroot_t *root, struct buffer **to_server_p,
struct buffer **from_server_p)
{
int pipes[2];
int child_pid;
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
invoke another rsh on a proxy machine. */
char *cvs_rsh = (root->cvs_rsh != NULL
? root->cvs_rsh : getenv ("CVS_RSH"));
char *cvs_server = (root->cvs_server != NULL
? root->cvs_server : getenv ("CVS_SERVER"));
int i = 0;
/* This needs to fit "rsh", "-b", "-l", "USER", "--", "host",
"cmd (w/ args)", and NULL. We leave some room to grow. */
char *rsh_argv[16];
if (!cvs_rsh || !*cvs_rsh)
/* People sometimes suggest or assume that this should default
to "remsh" on systems like HPUX in which that is the
system-supplied name for the rsh program. However, that
causes various problems (keep in mind that systems such as
HPUX might have non-system-supplied versions of "rsh", like
a Kerberized one, which one might want to use). If we
based the name on what is found in the PATH of the person
who runs configure, that would make it harder to
consistently produce the same result in the face of
different people producing binary distributions. If we
based it on "remsh" always being the default for HPUX
(e.g. based on uname), that might be slightly better but
would require us to keep track of what the defaults are for
each system type, and probably would cope poorly if the
existence of remsh or rsh varies from OS version to OS
version. Therefore, it seems best to have the default
remain "rsh", and tell HPUX users to specify remsh, for
example in CVS_RSH or other such mechanisms to be devised,
if that is what they want (the manual already tells them
that). */
cvs_rsh = RSH_DFLT;
if (!cvs_server)
cvs_server = "cvs";
/* The command line starts out with rsh. */
rsh_argv[i++] = cvs_rsh;
# ifdef RSH_NEEDS_BINARY_FLAG
/* "-b" for binary, under OS/2. */
rsh_argv[i++] = "-b";
# endif /* RSH_NEEDS_BINARY_FLAG */
/* Then we strcat more things on the end one by one. */
if (root->username != NULL)
{
rsh_argv[i++] = "-l";
rsh_argv[i++] = root->username;
}
/* Only non-option arguments from here. (CVE-2017-12836) */
rsh_argv[i++] = "--";
rsh_argv[i++] = root->hostname;
rsh_argv[i++] = cvs_server;
rsh_argv[i++] = "server";
/* Mark the end of the arg list. */
rsh_argv[i] = NULL;
if (trace)
{
fprintf (stderr, " -> Starting server: ");
for (i = 0; rsh_argv[i]; i++)
fprintf (stderr, "%s ", rsh_argv[i]);
putc ('\n', stderr);
}
/* Do the deed. */
child_pid = popenRW (rsh_argv, pipes);
if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
/* Give caller the file descriptors in a form it can deal with. */
make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server_p,
from_server_p, 0);
}
# else /* ! START_RSH_WITH_POPEN_RW */
void
start_rsh_server (cvsroot_t *root, struct buffer **to_server_p,
struct buffer **from_server_p)
{
/* If you're working through firewalls, you can set the
CVS_RSH environment variable to a script which uses rsh to
invoke another rsh on a proxy machine. */
char *cvs_rsh = (root->cvs_rsh != NULL
? root->cvs_rsh : getenv ("CVS_RSH"));
char *cvs_server = (root->cvs_server != NULL
? root->cvs_server : getenv ("CVS_SERVER"));
char *command;
int tofd, fromfd;
int child_pid;
if (!cvs_rsh)
cvs_rsh = RSH_DFLT;
if (!cvs_server)
cvs_server = "cvs";
/* Pass the command to rsh as a single string. This shouldn't
* affect most rsh servers at all, and will pacify some buggy
* versions of rsh that grab switches out of the middle of the
* command (they're calling the GNU getopt routines incorrectly).
*
* If you are running a very old (Nov 3, 1994, before 1.5)
* version of the server, you need to make sure that your .bashrc
* on the server machine does not set CVSROOT to something
* containing a colon (or better yet, upgrade the server).
*/
command = Xasprintf ("%s server", cvs_server);
{
char *argv[16];
char **p = argv;
*p++ = cvs_rsh;
/* If the login names differ between client and server
* pass it on to rsh.
*/
if (root->username != NULL)
{
*p++ = "-l";
*p++ = root->username;
}
*p++ = "--";
*p++ = root->hostname;
*p++ = command;
*p++ = NULL;
if (trace)
{
int i;
fprintf (stderr, " -> Starting server: ");
for (i = 0; argv[i]; i++)
fprintf (stderr, "%s ", argv[i]);
putc ('\n', stderr);
}
child_pid = piped_child (argv, &tofd, &fromfd, true);
if (child_pid < 0)
error (1, errno, "cannot start server via rsh");
}
free (command);
make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
from_server_p, 0);
}
# endif /* START_RSH_WITH_POPEN_RW */
#endif /* NO_EXT_METHOD */
#endif /* CLIENT_SUPPORT */