update from MirBSD CVS
[alioth/cvs.git] / src / rsh-client.c
1 /* CVS rsh client stuff.
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12
13 #include <config.h>
14
15 #include "cvs.h"
16 #include "buffer.h"
17
18 __RCSID("$MirOS: src/gnu/usr.bin/cvs/src/rsh-client.c,v 1.7 2017/08/11 20:41:40 tg Exp $");
19
20 #ifdef CLIENT_SUPPORT
21
22 #include "rsh-client.h"
23
24 #ifndef NO_EXT_METHOD
25
26 /* Contact the server by starting it with rsh.  */
27
28 /* Right now, we have two different definitions for this function,
29    depending on whether we start the rsh server using popenRW or not.
30    This isn't ideal, and the best thing would probably be to change
31    the OS/2 port to be more like the regular Unix client (i.e., by
32    implementing piped_child)... but I'm doing something else at the
33    moment, and wish to make only one change at a time.  -Karl */
34
35 # ifdef START_RSH_WITH_POPEN_RW
36
37
38
39 /* This is actually a crock -- it's OS/2-specific, for no one else
40    uses it.  If I get time, I want to make piped_child and all the
41    other stuff in os2/run.c work right.  In the meantime, this gets us
42    up and running, and that's most important. */
43 void
44 start_rsh_server (cvsroot_t *root, struct buffer **to_server_p,
45                   struct buffer **from_server_p)
46 {
47     int pipes[2];
48     int child_pid;
49
50     /* If you're working through firewalls, you can set the
51        CVS_RSH environment variable to a script which uses rsh to
52        invoke another rsh on a proxy machine.  */
53     char *cvs_rsh = (root->cvs_rsh != NULL
54                      ? root->cvs_rsh : getenv ("CVS_RSH"));
55     char *cvs_server = (root->cvs_server != NULL
56                         ? root->cvs_server : getenv ("CVS_SERVER"));
57     int i = 0;
58     /* This needs to fit "rsh", "-b", "-l", "USER", "-p", port,
59        "--", "host", "cvs", "-R", "server", and NULL.
60        We leave some room to grow. */
61     char *rsh_argv[16];
62     char argvport[16];
63
64     if (!cvs_rsh || !*cvs_rsh)
65         /* People sometimes suggest or assume that this should default
66            to "remsh" on systems like HPUX in which that is the
67            system-supplied name for the rsh program.  However, that
68            causes various problems (keep in mind that systems such as
69            HPUX might have non-system-supplied versions of "rsh", like
70            a Kerberized one, which one might want to use).  If we
71            based the name on what is found in the PATH of the person
72            who runs configure, that would make it harder to
73            consistently produce the same result in the face of
74            different people producing binary distributions.  If we
75            based it on "remsh" always being the default for HPUX
76            (e.g. based on uname), that might be slightly better but
77            would require us to keep track of what the defaults are for
78            each system type, and probably would cope poorly if the
79            existence of remsh or rsh varies from OS version to OS
80            version.  Therefore, it seems best to have the default
81            remain "rsh", and tell HPUX users to specify remsh, for
82            example in CVS_RSH or other such mechanisms to be devised,
83            if that is what they want (the manual already tells them
84            that).  */
85         cvs_rsh = RSH_DFLT;
86     if (!cvs_server || !*cvs_server)
87         cvs_server = "cvs";
88
89     /* The command line starts out with rsh. */
90     rsh_argv[i++] = cvs_rsh;
91
92 #   ifdef RSH_NEEDS_BINARY_FLAG
93     /* "-b" for binary, under OS/2. */
94     rsh_argv[i++] = "-b";
95 #   endif /* RSH_NEEDS_BINARY_FLAG */
96
97     /* Then we strcat more things on the end one by one. */
98     if (root->username != NULL)
99     {
100         rsh_argv[i++] = "-l";
101         rsh_argv[i++] = root->username;
102     }
103
104     if (root->method == extssh_method && root->port)
105     {
106         snprintf(argvport, sizeof(argvport), "%d", root->port);
107         rsh_argv[i++] = "-p";
108         rsh_argv[i++] = argvport;
109     }
110
111     /* Only non-option arguments from here. (CVE-2017-12836) */
112     rsh_argv[i++] = "--";
113
114     rsh_argv[i++] = root->hostname;
115     rsh_argv[i++] = cvs_server;
116     if (readonlyfs)
117         rsh_argv[i++] = "-R";
118     rsh_argv[i++] = "server";
119
120     /* Mark the end of the arg list. */
121     rsh_argv[i]   = NULL;
122
123     if (trace)
124     {
125         fprintf (stderr, " -> Starting server: ");
126         for (i = 0; rsh_argv[i]; i++)
127             fprintf (stderr, "%s ", rsh_argv[i]);
128         putc ('\n', stderr);
129     }
130
131     /* Do the deed. */
132     child_pid = popenRW (rsh_argv, pipes);
133     if (child_pid < 0)
134         error (1, errno, "cannot start server via rsh");
135
136     /* Give caller the file descriptors in a form it can deal with. */
137     make_bufs_from_fds (pipes[0], pipes[1], child_pid, to_server_p,
138                         from_server_p, 0);
139 }
140
141 # else /* ! START_RSH_WITH_POPEN_RW */
142
143 void
144 start_rsh_server (cvsroot_t *root, struct buffer **to_server_p,
145                   struct buffer **from_server_p)
146 {
147     /* If you're working through firewalls, you can set the
148        CVS_RSH environment variable to a script which uses rsh to
149        invoke another rsh on a proxy machine.  */
150     char *cvs_rsh = (root->cvs_rsh != NULL
151                      ? root->cvs_rsh : getenv ("CVS_RSH"));
152     char *cvs_server = (root->cvs_server != NULL
153                         ? root->cvs_server : getenv ("CVS_SERVER"));
154     char *command;
155     int tofd, fromfd;
156     int child_pid;
157
158     if (!cvs_rsh || !*cvs_rsh)
159         cvs_rsh = RSH_DFLT;
160     if (!cvs_server || !*cvs_server)
161         cvs_server = "cvs";
162
163     /* Pass the command to rsh as a single string.  This shouldn't
164      * affect most rsh servers at all, and will pacify some buggy
165      * versions of rsh that grab switches out of the middle of the
166      * command (they're calling the GNU getopt routines incorrectly).
167      *
168      * If you are running a very old (Nov 3, 1994, before 1.5)
169      * version of the server, you need to make sure that your .bashrc
170      * on the server machine does not set CVSROOT to something
171      * containing a colon (or better yet, upgrade the server).
172      */
173     command = Xasprintf ("%s%s server", cvs_server, readonlyfs ? " -R" : "");
174
175     {
176         char argvport[16];
177         char *argv[16];
178         char **p = argv;
179
180         *p++ = cvs_rsh;
181
182         /* If the login names differ between client and server
183          * pass it on to rsh.
184          */
185         if (root->username != NULL)
186         {
187             *p++ = "-l";
188             *p++ = root->username;
189         }
190
191         if (root->method == extssh_method && root->port)
192         {
193                 snprintf(argvport, sizeof(argvport), "%d", root->port);
194                 *p++ = "-p";
195                 *p++ = argvport;
196         }
197
198         *p++ = "--";
199
200         *p++ = root->hostname;
201         *p++ = command;
202         *p++ = NULL;
203
204         if (trace)
205         {
206             int i;
207
208             fprintf (stderr, " -> Starting server: ");
209             for (i = 0; argv[i]; i++)
210                 fprintf (stderr, "%s ", argv[i]);
211             putc ('\n', stderr);
212         }
213         child_pid = piped_child (argv, &tofd, &fromfd, true);
214
215         if (child_pid < 0)
216             error (1, errno, "cannot start server via rsh");
217     }
218     free (command);
219
220     make_bufs_from_fds (tofd, fromfd, child_pid, root, to_server_p,
221                         from_server_p, 0);
222 }
223
224 # endif /* START_RSH_WITH_POPEN_RW */
225
226 #endif /* NO_EXT_METHOD */
227
228 #endif /* CLIENT_SUPPORT */