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