1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray * may be used to endorse or promote products derived from this software
19b528cefcSMark Murray * without specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray * SUCH DAMAGE.
32b528cefcSMark Murray */
33b528cefcSMark Murray
34b528cefcSMark Murray #include "rsh_locl.h"
35*ae771770SStanislav Sedov RCSID("$Id$");
36b528cefcSMark Murray
37b528cefcSMark Murray enum auth_method auth_method;
38*ae771770SStanislav Sedov #if defined(KRB5)
395e9cd1aeSAssar Westerlund int do_encrypt = -1;
408373020dSJacques Vidrine #endif
418373020dSJacques Vidrine #ifdef KRB5
42b528cefcSMark Murray int do_unique_tkfile = 0;
43b528cefcSMark Murray char *unique_tkfile = NULL;
44b528cefcSMark Murray char tkfile[MAXPATHLEN];
458373020dSJacques Vidrine int do_forward = -1;
468373020dSJacques Vidrine int do_forwardable = -1;
47b528cefcSMark Murray krb5_context context;
48b528cefcSMark Murray krb5_keyblock *keyblock;
49b528cefcSMark Murray krb5_crypto crypto;
508373020dSJacques Vidrine #endif
514137ff4cSJacques Vidrine int sock_debug = 0;
52b528cefcSMark Murray
538373020dSJacques Vidrine #ifdef KRB5
544137ff4cSJacques Vidrine static int use_v5 = -1;
558373020dSJacques Vidrine #endif
56*ae771770SStanislav Sedov #if defined(KRB5)
574137ff4cSJacques Vidrine static int use_only_broken = 0;
58c19800e8SDoug Rabson #else
59c19800e8SDoug Rabson static int use_only_broken = 1;
60c19800e8SDoug Rabson #endif
614137ff4cSJacques Vidrine static int use_broken = 1;
624137ff4cSJacques Vidrine static char *port_str;
634137ff4cSJacques Vidrine static const char *user;
644137ff4cSJacques Vidrine static int do_version;
654137ff4cSJacques Vidrine static int do_help;
664137ff4cSJacques Vidrine static int do_errsock = 1;
67c19800e8SDoug Rabson #ifdef KRB5
680cadf2f4SJacques Vidrine static char *protocol_version_str;
690cadf2f4SJacques Vidrine static int protocol_version = 2;
70c19800e8SDoug Rabson #endif
71b528cefcSMark Murray
72b528cefcSMark Murray /*
73b528cefcSMark Murray *
74b528cefcSMark Murray */
75b528cefcSMark Murray
76b528cefcSMark Murray static int input = 1; /* Read from stdin */
77b528cefcSMark Murray
78b528cefcSMark Murray static int
rsh_loop(int s,int errsock)79c19800e8SDoug Rabson rsh_loop (int s, int errsock)
80b528cefcSMark Murray {
81b528cefcSMark Murray fd_set real_readset;
82b528cefcSMark Murray int count = 1;
83b528cefcSMark Murray
840cadf2f4SJacques Vidrine #ifdef KRB5
850cadf2f4SJacques Vidrine if(auth_method == AUTH_KRB5 && protocol_version == 2)
86c19800e8SDoug Rabson init_ivecs(1, errsock != -1);
870cadf2f4SJacques Vidrine #endif
880cadf2f4SJacques Vidrine
89bbd80c28SJacques Vidrine if (s >= FD_SETSIZE || (errsock != -1 && errsock >= FD_SETSIZE))
905e9cd1aeSAssar Westerlund errx (1, "fd too large");
915e9cd1aeSAssar Westerlund
92b528cefcSMark Murray FD_ZERO(&real_readset);
93b528cefcSMark Murray FD_SET(s, &real_readset);
94b528cefcSMark Murray if (errsock != -1) {
95b528cefcSMark Murray FD_SET(errsock, &real_readset);
96b528cefcSMark Murray ++count;
97b528cefcSMark Murray }
98b528cefcSMark Murray if(input)
99b528cefcSMark Murray FD_SET(STDIN_FILENO, &real_readset);
100b528cefcSMark Murray
101b528cefcSMark Murray for (;;) {
102b528cefcSMark Murray int ret;
103b528cefcSMark Murray fd_set readset;
104b528cefcSMark Murray char buf[RSH_BUFSIZ];
105b528cefcSMark Murray
106b528cefcSMark Murray readset = real_readset;
107b528cefcSMark Murray ret = select (max(s, errsock) + 1, &readset, NULL, NULL, NULL);
108b528cefcSMark Murray if (ret < 0) {
109b528cefcSMark Murray if (errno == EINTR)
110b528cefcSMark Murray continue;
111b528cefcSMark Murray else
112b528cefcSMark Murray err (1, "select");
113b528cefcSMark Murray }
114b528cefcSMark Murray if (FD_ISSET(s, &readset)) {
1150cadf2f4SJacques Vidrine ret = do_read (s, buf, sizeof(buf), ivec_in[0]);
116b528cefcSMark Murray if (ret < 0)
117b528cefcSMark Murray err (1, "read");
118b528cefcSMark Murray else if (ret == 0) {
119b528cefcSMark Murray close (s);
120b528cefcSMark Murray FD_CLR(s, &real_readset);
121b528cefcSMark Murray if (--count == 0)
122b528cefcSMark Murray return 0;
123b528cefcSMark Murray } else
124b528cefcSMark Murray net_write (STDOUT_FILENO, buf, ret);
125b528cefcSMark Murray }
126b528cefcSMark Murray if (errsock != -1 && FD_ISSET(errsock, &readset)) {
1270cadf2f4SJacques Vidrine ret = do_read (errsock, buf, sizeof(buf), ivec_in[1]);
128b528cefcSMark Murray if (ret < 0)
129b528cefcSMark Murray err (1, "read");
130b528cefcSMark Murray else if (ret == 0) {
131b528cefcSMark Murray close (errsock);
132b528cefcSMark Murray FD_CLR(errsock, &real_readset);
133b528cefcSMark Murray if (--count == 0)
134b528cefcSMark Murray return 0;
135b528cefcSMark Murray } else
136b528cefcSMark Murray net_write (STDERR_FILENO, buf, ret);
137b528cefcSMark Murray }
138b528cefcSMark Murray if (FD_ISSET(STDIN_FILENO, &readset)) {
139b528cefcSMark Murray ret = read (STDIN_FILENO, buf, sizeof(buf));
140b528cefcSMark Murray if (ret < 0)
141b528cefcSMark Murray err (1, "read");
142b528cefcSMark Murray else if (ret == 0) {
143b528cefcSMark Murray close (STDIN_FILENO);
144b528cefcSMark Murray FD_CLR(STDIN_FILENO, &real_readset);
145b528cefcSMark Murray shutdown (s, SHUT_WR);
146b528cefcSMark Murray } else
1470cadf2f4SJacques Vidrine do_write (s, buf, ret, ivec_out[0]);
148b528cefcSMark Murray }
149b528cefcSMark Murray }
150b528cefcSMark Murray }
151b528cefcSMark Murray
1528373020dSJacques Vidrine #ifdef KRB5
153b528cefcSMark Murray /*
154b528cefcSMark Murray * Send forward information on `s' for host `hostname', them being
155b528cefcSMark Murray * forwardable themselves if `forwardable'
156b528cefcSMark Murray */
157b528cefcSMark Murray
158b528cefcSMark Murray static int
krb5_forward_cred(krb5_auth_context auth_context,int s,const char * hostname,int forwardable)159b528cefcSMark Murray krb5_forward_cred (krb5_auth_context auth_context,
160b528cefcSMark Murray int s,
161b528cefcSMark Murray const char *hostname,
162b528cefcSMark Murray int forwardable)
163b528cefcSMark Murray {
164b528cefcSMark Murray krb5_error_code ret;
165b528cefcSMark Murray krb5_ccache ccache;
166b528cefcSMark Murray krb5_creds creds;
167b528cefcSMark Murray krb5_kdc_flags flags;
168b528cefcSMark Murray krb5_data out_data;
169b528cefcSMark Murray krb5_principal principal;
170b528cefcSMark Murray
171b528cefcSMark Murray memset (&creds, 0, sizeof(creds));
172b528cefcSMark Murray
173b528cefcSMark Murray ret = krb5_cc_default (context, &ccache);
174b528cefcSMark Murray if (ret) {
175b528cefcSMark Murray warnx ("could not forward creds: krb5_cc_default: %s",
176b528cefcSMark Murray krb5_get_err_text (context, ret));
177b528cefcSMark Murray return 1;
178b528cefcSMark Murray }
179b528cefcSMark Murray
180b528cefcSMark Murray ret = krb5_cc_get_principal (context, ccache, &principal);
181b528cefcSMark Murray if (ret) {
182b528cefcSMark Murray warnx ("could not forward creds: krb5_cc_get_principal: %s",
183b528cefcSMark Murray krb5_get_err_text (context, ret));
184b528cefcSMark Murray return 1;
185b528cefcSMark Murray }
186b528cefcSMark Murray
187b528cefcSMark Murray creds.client = principal;
188b528cefcSMark Murray
189*ae771770SStanislav Sedov ret = krb5_make_principal(context,
190b528cefcSMark Murray &creds.server,
191b528cefcSMark Murray principal->realm,
192b528cefcSMark Murray "krbtgt",
193b528cefcSMark Murray principal->realm,
194b528cefcSMark Murray NULL);
195b528cefcSMark Murray
196b528cefcSMark Murray if (ret) {
197*ae771770SStanislav Sedov warnx ("could not forward creds: krb5_make_principal: %s",
198b528cefcSMark Murray krb5_get_err_text (context, ret));
199b528cefcSMark Murray return 1;
200b528cefcSMark Murray }
201b528cefcSMark Murray
202b528cefcSMark Murray creds.times.endtime = 0;
203b528cefcSMark Murray
204b528cefcSMark Murray flags.i = 0;
205b528cefcSMark Murray flags.b.forwarded = 1;
206b528cefcSMark Murray flags.b.forwardable = forwardable;
207b528cefcSMark Murray
208b528cefcSMark Murray ret = krb5_get_forwarded_creds (context,
209b528cefcSMark Murray auth_context,
210b528cefcSMark Murray ccache,
211b528cefcSMark Murray flags.i,
212b528cefcSMark Murray hostname,
213b528cefcSMark Murray &creds,
214b528cefcSMark Murray &out_data);
215b528cefcSMark Murray if (ret) {
216b528cefcSMark Murray warnx ("could not forward creds: krb5_get_forwarded_creds: %s",
217b528cefcSMark Murray krb5_get_err_text (context, ret));
218b528cefcSMark Murray return 1;
219b528cefcSMark Murray }
220b528cefcSMark Murray
221b528cefcSMark Murray ret = krb5_write_message (context,
222b528cefcSMark Murray (void *)&s,
223b528cefcSMark Murray &out_data);
224b528cefcSMark Murray krb5_data_free (&out_data);
225b528cefcSMark Murray
226b528cefcSMark Murray if (ret)
227b528cefcSMark Murray warnx ("could not forward creds: krb5_write_message: %s",
228b528cefcSMark Murray krb5_get_err_text (context, ret));
229b528cefcSMark Murray return 0;
230b528cefcSMark Murray }
231b528cefcSMark Murray
2320cadf2f4SJacques Vidrine static int sendauth_version_error;
2330cadf2f4SJacques Vidrine
234b528cefcSMark Murray static int
send_krb5_auth(int s,struct sockaddr * thisaddr,struct sockaddr * thataddr,const char * hostname,const char * remote_user,const char * local_user,size_t cmd_len,const char * cmd)235b528cefcSMark Murray send_krb5_auth(int s,
236b528cefcSMark Murray struct sockaddr *thisaddr,
237b528cefcSMark Murray struct sockaddr *thataddr,
238b528cefcSMark Murray const char *hostname,
239b528cefcSMark Murray const char *remote_user,
240b528cefcSMark Murray const char *local_user,
241b528cefcSMark Murray size_t cmd_len,
242b528cefcSMark Murray const char *cmd)
243b528cefcSMark Murray {
244b528cefcSMark Murray krb5_principal server;
245b528cefcSMark Murray krb5_data cksum_data;
246b528cefcSMark Murray int status;
247b528cefcSMark Murray size_t len;
248b528cefcSMark Murray krb5_auth_context auth_context = NULL;
2490cadf2f4SJacques Vidrine const char *protocol_string = NULL;
2500cadf2f4SJacques Vidrine krb5_flags ap_opts;
251c19800e8SDoug Rabson char *str;
252b528cefcSMark Murray
253b528cefcSMark Murray status = krb5_sname_to_principal(context,
254b528cefcSMark Murray hostname,
255b528cefcSMark Murray "host",
256b528cefcSMark Murray KRB5_NT_SRV_HST,
257b528cefcSMark Murray &server);
258b528cefcSMark Murray if (status) {
259b528cefcSMark Murray warnx ("%s: %s", hostname, krb5_get_err_text(context, status));
260b528cefcSMark Murray return 1;
261b528cefcSMark Murray }
262b528cefcSMark Murray
263bbd80c28SJacques Vidrine if(do_encrypt == -1) {
264bbd80c28SJacques Vidrine krb5_appdefault_boolean(context, NULL,
265bbd80c28SJacques Vidrine krb5_principal_get_realm(context, server),
266bbd80c28SJacques Vidrine "encrypt",
267bbd80c28SJacques Vidrine FALSE,
268bbd80c28SJacques Vidrine &do_encrypt);
269bbd80c28SJacques Vidrine }
270bbd80c28SJacques Vidrine
271c19800e8SDoug Rabson cksum_data.length = asprintf (&str,
272b528cefcSMark Murray "%u:%s%s%s",
273b528cefcSMark Murray ntohs(socket_get_port(thataddr)),
274b528cefcSMark Murray do_encrypt ? "-x " : "",
275b528cefcSMark Murray cmd,
276b528cefcSMark Murray remote_user);
277c19800e8SDoug Rabson if (str == NULL) {
278c19800e8SDoug Rabson warnx ("%s: failed to allocate command", hostname);
279c19800e8SDoug Rabson return 1;
280c19800e8SDoug Rabson }
281c19800e8SDoug Rabson cksum_data.data = str;
282b528cefcSMark Murray
2830cadf2f4SJacques Vidrine ap_opts = 0;
2840cadf2f4SJacques Vidrine
2850cadf2f4SJacques Vidrine if(do_encrypt)
2860cadf2f4SJacques Vidrine ap_opts |= AP_OPTS_MUTUAL_REQUIRED;
2870cadf2f4SJacques Vidrine
2880cadf2f4SJacques Vidrine switch(protocol_version) {
2890cadf2f4SJacques Vidrine case 2:
2900cadf2f4SJacques Vidrine ap_opts |= AP_OPTS_USE_SUBKEY;
2910cadf2f4SJacques Vidrine protocol_string = KCMD_NEW_VERSION;
2920cadf2f4SJacques Vidrine break;
2930cadf2f4SJacques Vidrine case 1:
2940cadf2f4SJacques Vidrine protocol_string = KCMD_OLD_VERSION;
2950cadf2f4SJacques Vidrine key_usage = KRB5_KU_OTHER_ENCRYPTED;
2960cadf2f4SJacques Vidrine break;
2970cadf2f4SJacques Vidrine default:
2980cadf2f4SJacques Vidrine abort();
2990cadf2f4SJacques Vidrine }
3000cadf2f4SJacques Vidrine
301b528cefcSMark Murray status = krb5_sendauth (context,
302b528cefcSMark Murray &auth_context,
303b528cefcSMark Murray &s,
3040cadf2f4SJacques Vidrine protocol_string,
305b528cefcSMark Murray NULL,
306b528cefcSMark Murray server,
3070cadf2f4SJacques Vidrine ap_opts,
308b528cefcSMark Murray &cksum_data,
309b528cefcSMark Murray NULL,
310b528cefcSMark Murray NULL,
311b528cefcSMark Murray NULL,
312b528cefcSMark Murray NULL,
313b528cefcSMark Murray NULL);
3140cadf2f4SJacques Vidrine
315bbd80c28SJacques Vidrine /* do this while we have a principal */
316bbd80c28SJacques Vidrine if(do_forward == -1 || do_forwardable == -1) {
317bbd80c28SJacques Vidrine krb5_const_realm realm = krb5_principal_get_realm(context, server);
318bbd80c28SJacques Vidrine if (do_forwardable == -1)
319bbd80c28SJacques Vidrine krb5_appdefault_boolean(context, NULL, realm,
320bbd80c28SJacques Vidrine "forwardable", FALSE,
321bbd80c28SJacques Vidrine &do_forwardable);
322bbd80c28SJacques Vidrine if (do_forward == -1)
323bbd80c28SJacques Vidrine krb5_appdefault_boolean(context, NULL, realm,
324bbd80c28SJacques Vidrine "forward", FALSE,
325bbd80c28SJacques Vidrine &do_forward);
326bbd80c28SJacques Vidrine }
327bbd80c28SJacques Vidrine
3280cadf2f4SJacques Vidrine krb5_free_principal(context, server);
3290cadf2f4SJacques Vidrine krb5_data_free(&cksum_data);
3300cadf2f4SJacques Vidrine
331b528cefcSMark Murray if (status) {
3320cadf2f4SJacques Vidrine if(status == KRB5_SENDAUTH_REJECTED &&
3330cadf2f4SJacques Vidrine protocol_version == 2 && protocol_version_str == NULL)
3340cadf2f4SJacques Vidrine sendauth_version_error = 1;
3350cadf2f4SJacques Vidrine else
3360cadf2f4SJacques Vidrine krb5_warn(context, status, "%s", hostname);
337b528cefcSMark Murray return 1;
338b528cefcSMark Murray }
339b528cefcSMark Murray
3400cadf2f4SJacques Vidrine status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock);
3410cadf2f4SJacques Vidrine if(keyblock == NULL)
342b528cefcSMark Murray status = krb5_auth_con_getkey (context, auth_context, &keyblock);
343b528cefcSMark Murray if (status) {
344b528cefcSMark Murray warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status));
345b528cefcSMark Murray return 1;
346b528cefcSMark Murray }
347b528cefcSMark Murray
348b528cefcSMark Murray status = krb5_auth_con_setaddrs_from_fd (context,
349b528cefcSMark Murray auth_context,
350b528cefcSMark Murray &s);
351b528cefcSMark Murray if (status) {
352b528cefcSMark Murray warnx("krb5_auth_con_setaddrs_from_fd: %s",
353b528cefcSMark Murray krb5_get_err_text(context, status));
354b528cefcSMark Murray return(1);
355b528cefcSMark Murray }
356b528cefcSMark Murray
357b528cefcSMark Murray status = krb5_crypto_init(context, keyblock, 0, &crypto);
358b528cefcSMark Murray if(status) {
359b528cefcSMark Murray warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status));
360b528cefcSMark Murray return 1;
361b528cefcSMark Murray }
362b528cefcSMark Murray
363b528cefcSMark Murray len = strlen(remote_user) + 1;
364b528cefcSMark Murray if (net_write (s, remote_user, len) != len) {
365b528cefcSMark Murray warn ("write");
366b528cefcSMark Murray return 1;
367b528cefcSMark Murray }
368b528cefcSMark Murray if (do_encrypt && net_write (s, "-x ", 3) != 3) {
369b528cefcSMark Murray warn ("write");
370b528cefcSMark Murray return 1;
371b528cefcSMark Murray }
372b528cefcSMark Murray if (net_write (s, cmd, cmd_len) != cmd_len) {
373b528cefcSMark Murray warn ("write");
374b528cefcSMark Murray return 1;
375b528cefcSMark Murray }
376b528cefcSMark Murray
377b528cefcSMark Murray if (do_unique_tkfile) {
378b528cefcSMark Murray if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) {
379b528cefcSMark Murray warn ("write");
380b528cefcSMark Murray return 1;
381b528cefcSMark Murray }
382b528cefcSMark Murray }
383b528cefcSMark Murray len = strlen(local_user) + 1;
384b528cefcSMark Murray if (net_write (s, local_user, len) != len) {
385b528cefcSMark Murray warn ("write");
386b528cefcSMark Murray return 1;
387b528cefcSMark Murray }
388b528cefcSMark Murray
389b528cefcSMark Murray if (!do_forward
390b528cefcSMark Murray || krb5_forward_cred (auth_context, s, hostname, do_forwardable)) {
391b528cefcSMark Murray /* Empty forwarding info */
392b528cefcSMark Murray
393b528cefcSMark Murray u_char zero[4] = {0, 0, 0, 0};
394b528cefcSMark Murray write (s, &zero, 4);
395b528cefcSMark Murray }
396b528cefcSMark Murray krb5_auth_con_free (context, auth_context);
397b528cefcSMark Murray return 0;
398b528cefcSMark Murray }
399b528cefcSMark Murray
4008373020dSJacques Vidrine #endif /* KRB5 */
4018373020dSJacques Vidrine
402b528cefcSMark Murray static int
send_broken_auth(int s,struct sockaddr * thisaddr,struct sockaddr * thataddr,const char * hostname,const char * remote_user,const char * local_user,size_t cmd_len,const char * cmd)403b528cefcSMark Murray send_broken_auth(int s,
404b528cefcSMark Murray struct sockaddr *thisaddr,
405b528cefcSMark Murray struct sockaddr *thataddr,
406b528cefcSMark Murray const char *hostname,
407b528cefcSMark Murray const char *remote_user,
408b528cefcSMark Murray const char *local_user,
409b528cefcSMark Murray size_t cmd_len,
410b528cefcSMark Murray const char *cmd)
411b528cefcSMark Murray {
412b528cefcSMark Murray size_t len;
413b528cefcSMark Murray
414b528cefcSMark Murray len = strlen(local_user) + 1;
415b528cefcSMark Murray if (net_write (s, local_user, len) != len) {
416b528cefcSMark Murray warn ("write");
417b528cefcSMark Murray return 1;
418b528cefcSMark Murray }
419b528cefcSMark Murray len = strlen(remote_user) + 1;
420b528cefcSMark Murray if (net_write (s, remote_user, len) != len) {
421b528cefcSMark Murray warn ("write");
422b528cefcSMark Murray return 1;
423b528cefcSMark Murray }
424b528cefcSMark Murray if (net_write (s, cmd, cmd_len) != cmd_len) {
425b528cefcSMark Murray warn ("write");
426b528cefcSMark Murray return 1;
427b528cefcSMark Murray }
428b528cefcSMark Murray return 0;
429b528cefcSMark Murray }
430b528cefcSMark Murray
431b528cefcSMark Murray static int
proto(int s,int errsock,const char * hostname,const char * local_user,const char * remote_user,const char * cmd,size_t cmd_len,int (* auth_func)(int s,struct sockaddr * this,struct sockaddr * that,const char * hostname,const char * remote_user,const char * local_user,size_t cmd_len,const char * cmd))432b528cefcSMark Murray proto (int s, int errsock,
433b528cefcSMark Murray const char *hostname, const char *local_user, const char *remote_user,
434b528cefcSMark Murray const char *cmd, size_t cmd_len,
435b528cefcSMark Murray int (*auth_func)(int s,
436b528cefcSMark Murray struct sockaddr *this, struct sockaddr *that,
437b528cefcSMark Murray const char *hostname, const char *remote_user,
438b528cefcSMark Murray const char *local_user, size_t cmd_len,
439b528cefcSMark Murray const char *cmd))
440b528cefcSMark Murray {
441b528cefcSMark Murray int errsock2;
442b528cefcSMark Murray char buf[BUFSIZ];
443b528cefcSMark Murray char *p;
444b528cefcSMark Murray size_t len;
445b528cefcSMark Murray char reply;
446b528cefcSMark Murray struct sockaddr_storage thisaddr_ss;
447b528cefcSMark Murray struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
448b528cefcSMark Murray struct sockaddr_storage thataddr_ss;
449b528cefcSMark Murray struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
450b528cefcSMark Murray struct sockaddr_storage erraddr_ss;
451b528cefcSMark Murray struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
4525e9cd1aeSAssar Westerlund socklen_t addrlen;
453b528cefcSMark Murray int ret;
454b528cefcSMark Murray
455b528cefcSMark Murray addrlen = sizeof(thisaddr_ss);
456b528cefcSMark Murray if (getsockname (s, thisaddr, &addrlen) < 0) {
457b528cefcSMark Murray warn ("getsockname(%s)", hostname);
458b528cefcSMark Murray return 1;
459b528cefcSMark Murray }
460b528cefcSMark Murray addrlen = sizeof(thataddr_ss);
461b528cefcSMark Murray if (getpeername (s, thataddr, &addrlen) < 0) {
462b528cefcSMark Murray warn ("getpeername(%s)", hostname);
463b528cefcSMark Murray return 1;
464b528cefcSMark Murray }
465b528cefcSMark Murray
466b528cefcSMark Murray if (errsock != -1) {
467b528cefcSMark Murray
468b528cefcSMark Murray addrlen = sizeof(erraddr_ss);
469b528cefcSMark Murray if (getsockname (errsock, erraddr, &addrlen) < 0) {
470b528cefcSMark Murray warn ("getsockname");
471b528cefcSMark Murray return 1;
472b528cefcSMark Murray }
473b528cefcSMark Murray
474b528cefcSMark Murray if (listen (errsock, 1) < 0) {
475b528cefcSMark Murray warn ("listen");
476b528cefcSMark Murray return 1;
477b528cefcSMark Murray }
478b528cefcSMark Murray
479b528cefcSMark Murray p = buf;
480b528cefcSMark Murray snprintf (p, sizeof(buf), "%u",
481b528cefcSMark Murray ntohs(socket_get_port(erraddr)));
482b528cefcSMark Murray len = strlen(buf) + 1;
483b528cefcSMark Murray if(net_write (s, buf, len) != len) {
484b528cefcSMark Murray warn ("write");
485b528cefcSMark Murray close (errsock);
486b528cefcSMark Murray return 1;
487b528cefcSMark Murray }
488b528cefcSMark Murray
4895e9cd1aeSAssar Westerlund
4905e9cd1aeSAssar Westerlund for (;;) {
4915e9cd1aeSAssar Westerlund fd_set fdset;
4925e9cd1aeSAssar Westerlund
4935e9cd1aeSAssar Westerlund if (errsock >= FD_SETSIZE || s >= FD_SETSIZE)
4945e9cd1aeSAssar Westerlund errx (1, "fd too large");
4955e9cd1aeSAssar Westerlund
4965e9cd1aeSAssar Westerlund FD_ZERO(&fdset);
4975e9cd1aeSAssar Westerlund FD_SET(errsock, &fdset);
4985e9cd1aeSAssar Westerlund FD_SET(s, &fdset);
4995e9cd1aeSAssar Westerlund
5005e9cd1aeSAssar Westerlund ret = select (max(errsock, s) + 1, &fdset, NULL, NULL, NULL);
5015e9cd1aeSAssar Westerlund if (ret < 0) {
5025e9cd1aeSAssar Westerlund if (errno == EINTR)
5035e9cd1aeSAssar Westerlund continue;
5045e9cd1aeSAssar Westerlund warn ("select");
505b528cefcSMark Murray close (errsock);
506b528cefcSMark Murray return 1;
507b528cefcSMark Murray }
5085e9cd1aeSAssar Westerlund if (FD_ISSET(errsock, &fdset)) {
5095e9cd1aeSAssar Westerlund errsock2 = accept (errsock, NULL, NULL);
510b528cefcSMark Murray close (errsock);
5115e9cd1aeSAssar Westerlund if (errsock2 < 0) {
5125e9cd1aeSAssar Westerlund warn ("accept");
5135e9cd1aeSAssar Westerlund return 1;
5145e9cd1aeSAssar Westerlund }
5155e9cd1aeSAssar Westerlund break;
5165e9cd1aeSAssar Westerlund }
517b528cefcSMark Murray
5185e9cd1aeSAssar Westerlund /*
5195e9cd1aeSAssar Westerlund * there should not arrive any data on this fd so if it's
5205e9cd1aeSAssar Westerlund * readable it probably indicates that the other side when
5215e9cd1aeSAssar Westerlund * away.
5225e9cd1aeSAssar Westerlund */
5235e9cd1aeSAssar Westerlund
5245e9cd1aeSAssar Westerlund if (FD_ISSET(s, &fdset)) {
5255e9cd1aeSAssar Westerlund warnx ("socket closed");
5265e9cd1aeSAssar Westerlund close (errsock);
5275e9cd1aeSAssar Westerlund errsock2 = -1;
5285e9cd1aeSAssar Westerlund break;
5295e9cd1aeSAssar Westerlund }
5305e9cd1aeSAssar Westerlund }
531b528cefcSMark Murray } else {
532b528cefcSMark Murray if (net_write (s, "0", 2) != 2) {
533b528cefcSMark Murray warn ("write");
534b528cefcSMark Murray return 1;
535b528cefcSMark Murray }
536b528cefcSMark Murray errsock2 = -1;
537b528cefcSMark Murray }
538b528cefcSMark Murray
539b528cefcSMark Murray if ((*auth_func)(s, thisaddr, thataddr, hostname,
540b528cefcSMark Murray remote_user, local_user,
541b528cefcSMark Murray cmd_len, cmd)) {
542b528cefcSMark Murray close (errsock2);
543b528cefcSMark Murray return 1;
544b528cefcSMark Murray }
545b528cefcSMark Murray
546b528cefcSMark Murray ret = net_read (s, &reply, 1);
547b528cefcSMark Murray if (ret < 0) {
548b528cefcSMark Murray warn ("read");
549b528cefcSMark Murray close (errsock2);
550b528cefcSMark Murray return 1;
551b528cefcSMark Murray } else if (ret == 0) {
552b528cefcSMark Murray warnx ("unexpected EOF from %s", hostname);
553b528cefcSMark Murray close (errsock2);
554b528cefcSMark Murray return 1;
555b528cefcSMark Murray }
556b528cefcSMark Murray if (reply != 0) {
557b528cefcSMark Murray
558b528cefcSMark Murray warnx ("Error from rshd at %s:", hostname);
559b528cefcSMark Murray
560b528cefcSMark Murray while ((ret = read (s, buf, sizeof(buf))) > 0)
561b528cefcSMark Murray write (STDOUT_FILENO, buf, ret);
562b528cefcSMark Murray write (STDOUT_FILENO,"\n",1);
563b528cefcSMark Murray close (errsock2);
564b528cefcSMark Murray return 1;
565b528cefcSMark Murray }
566b528cefcSMark Murray
5674137ff4cSJacques Vidrine if (sock_debug) {
5684137ff4cSJacques Vidrine int one = 1;
5694137ff4cSJacques Vidrine if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(one)) < 0)
5704137ff4cSJacques Vidrine warn("setsockopt remote");
5714137ff4cSJacques Vidrine if (errsock2 != -1 &&
5724137ff4cSJacques Vidrine setsockopt(errsock2, SOL_SOCKET, SO_DEBUG,
5734137ff4cSJacques Vidrine (void *)&one, sizeof(one)) < 0)
5744137ff4cSJacques Vidrine warn("setsockopt stderr");
5754137ff4cSJacques Vidrine }
5764137ff4cSJacques Vidrine
577c19800e8SDoug Rabson return rsh_loop (s, errsock2);
578b528cefcSMark Murray }
579b528cefcSMark Murray
580b528cefcSMark Murray /*
581b528cefcSMark Murray * Return in `res' a copy of the concatenation of `argc, argv' into
5825e9cd1aeSAssar Westerlund * malloced space. */
583b528cefcSMark Murray
584b528cefcSMark Murray static size_t
construct_command(char ** res,int argc,char ** argv)585b528cefcSMark Murray construct_command (char **res, int argc, char **argv)
586b528cefcSMark Murray {
587b528cefcSMark Murray int i;
588b528cefcSMark Murray size_t len = 0;
589b528cefcSMark Murray char *tmp;
590b528cefcSMark Murray
591b528cefcSMark Murray for (i = 0; i < argc; ++i)
592b528cefcSMark Murray len += strlen(argv[i]) + 1;
593b528cefcSMark Murray len = max (1, len);
594b528cefcSMark Murray tmp = malloc (len);
595b528cefcSMark Murray if (tmp == NULL)
596c19800e8SDoug Rabson errx (1, "malloc %lu failed", (unsigned long)len);
597b528cefcSMark Murray
598b528cefcSMark Murray *tmp = '\0';
599b528cefcSMark Murray for (i = 0; i < argc - 1; ++i) {
600c19800e8SDoug Rabson strlcat (tmp, argv[i], len);
601c19800e8SDoug Rabson strlcat (tmp, " ", len);
602b528cefcSMark Murray }
603b528cefcSMark Murray if (argc > 0)
604c19800e8SDoug Rabson strlcat (tmp, argv[argc-1], len);
605b528cefcSMark Murray *res = tmp;
606b528cefcSMark Murray return len;
607b528cefcSMark Murray }
608b528cefcSMark Murray
609b528cefcSMark Murray static char *
print_addr(const struct sockaddr * sa)610bbd80c28SJacques Vidrine print_addr (const struct sockaddr *sa)
611b528cefcSMark Murray {
612b528cefcSMark Murray char addr_str[256];
613b528cefcSMark Murray char *res;
614bbd80c28SJacques Vidrine const char *as = NULL;
615b528cefcSMark Murray
616bbd80c28SJacques Vidrine if(sa->sa_family == AF_INET)
617bbd80c28SJacques Vidrine as = inet_ntop (sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr,
618bbd80c28SJacques Vidrine addr_str, sizeof(addr_str));
619bbd80c28SJacques Vidrine #ifdef HAVE_INET6
620bbd80c28SJacques Vidrine else if(sa->sa_family == AF_INET6)
621bbd80c28SJacques Vidrine as = inet_ntop (sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr,
622bbd80c28SJacques Vidrine addr_str, sizeof(addr_str));
623bbd80c28SJacques Vidrine #endif
624bbd80c28SJacques Vidrine if(as == NULL)
625bbd80c28SJacques Vidrine return NULL;
626bbd80c28SJacques Vidrine res = strdup(as);
627b528cefcSMark Murray if (res == NULL)
628b528cefcSMark Murray errx (1, "malloc: out of memory");
629b528cefcSMark Murray return res;
630b528cefcSMark Murray }
631b528cefcSMark Murray
632b528cefcSMark Murray static int
doit_broken(int argc,char ** argv,int hostindex,struct addrinfo * ai,const char * remote_user,const char * local_user,int priv_socket1,int priv_socket2,const char * cmd,size_t cmd_len)633b528cefcSMark Murray doit_broken (int argc,
634b528cefcSMark Murray char **argv,
635bbd80c28SJacques Vidrine int hostindex,
6368373020dSJacques Vidrine struct addrinfo *ai,
637b528cefcSMark Murray const char *remote_user,
638b528cefcSMark Murray const char *local_user,
639b528cefcSMark Murray int priv_socket1,
640b528cefcSMark Murray int priv_socket2,
641b528cefcSMark Murray const char *cmd,
642b528cefcSMark Murray size_t cmd_len)
643b528cefcSMark Murray {
6448373020dSJacques Vidrine struct addrinfo *a;
645b528cefcSMark Murray
646b528cefcSMark Murray if (connect (priv_socket1, ai->ai_addr, ai->ai_addrlen) < 0) {
647bbd80c28SJacques Vidrine int save_errno = errno;
648b528cefcSMark Murray
649b528cefcSMark Murray close(priv_socket1);
650b528cefcSMark Murray close(priv_socket2);
651b528cefcSMark Murray
652b528cefcSMark Murray for (a = ai->ai_next; a != NULL; a = a->ai_next) {
653b528cefcSMark Murray pid_t pid;
654bbd80c28SJacques Vidrine char *adr = print_addr(a->ai_addr);
655bbd80c28SJacques Vidrine if(adr == NULL)
656bbd80c28SJacques Vidrine continue;
657b528cefcSMark Murray
658b528cefcSMark Murray pid = fork();
659b528cefcSMark Murray if (pid < 0)
660b528cefcSMark Murray err (1, "fork");
661b528cefcSMark Murray else if(pid == 0) {
662b528cefcSMark Murray char **new_argv;
663b528cefcSMark Murray int i = 0;
664b528cefcSMark Murray
665b528cefcSMark Murray new_argv = malloc((argc + 2) * sizeof(*new_argv));
666b528cefcSMark Murray if (new_argv == NULL)
667b528cefcSMark Murray errx (1, "malloc: out of memory");
668b528cefcSMark Murray new_argv[i] = argv[i];
669b528cefcSMark Murray ++i;
670bbd80c28SJacques Vidrine if (hostindex == i)
671bbd80c28SJacques Vidrine new_argv[i++] = adr;
672b528cefcSMark Murray new_argv[i++] = "-K";
673b528cefcSMark Murray for(; i <= argc; ++i)
674b528cefcSMark Murray new_argv[i] = argv[i - 1];
675bbd80c28SJacques Vidrine if (hostindex > 1)
676bbd80c28SJacques Vidrine new_argv[hostindex + 1] = adr;
677b528cefcSMark Murray new_argv[argc + 1] = NULL;
678b528cefcSMark Murray execv(PATH_RSH, new_argv);
679b528cefcSMark Murray err(1, "execv(%s)", PATH_RSH);
680b528cefcSMark Murray } else {
681b528cefcSMark Murray int status;
682bbd80c28SJacques Vidrine free(adr);
683b528cefcSMark Murray
684b528cefcSMark Murray while(waitpid(pid, &status, 0) < 0)
685b528cefcSMark Murray ;
686b528cefcSMark Murray if(WIFEXITED(status) && WEXITSTATUS(status) == 0)
687b528cefcSMark Murray return 0;
688b528cefcSMark Murray }
689b528cefcSMark Murray }
690bbd80c28SJacques Vidrine errno = save_errno;
691bbd80c28SJacques Vidrine warn("%s", argv[hostindex]);
692b528cefcSMark Murray return 1;
693b528cefcSMark Murray } else {
694b528cefcSMark Murray int ret;
695b528cefcSMark Murray
696b528cefcSMark Murray ret = proto (priv_socket1, priv_socket2,
697bbd80c28SJacques Vidrine argv[hostindex],
698b528cefcSMark Murray local_user, remote_user,
699b528cefcSMark Murray cmd, cmd_len,
700b528cefcSMark Murray send_broken_auth);
701b528cefcSMark Murray return ret;
702b528cefcSMark Murray }
703b528cefcSMark Murray }
704b528cefcSMark Murray
705*ae771770SStanislav Sedov #if defined(KRB5)
706b528cefcSMark Murray static int
doit(const char * hostname,struct addrinfo * ai,const char * remote_user,const char * local_user,const char * cmd,size_t cmd_len,int (* auth_func)(int s,struct sockaddr * this,struct sockaddr * that,const char * hostname,const char * remote_user,const char * local_user,size_t cmd_len,const char * cmd))707b528cefcSMark Murray doit (const char *hostname,
7088373020dSJacques Vidrine struct addrinfo *ai,
709b528cefcSMark Murray const char *remote_user,
710b528cefcSMark Murray const char *local_user,
711b528cefcSMark Murray const char *cmd,
712b528cefcSMark Murray size_t cmd_len,
713b528cefcSMark Murray int (*auth_func)(int s,
714b528cefcSMark Murray struct sockaddr *this, struct sockaddr *that,
715b528cefcSMark Murray const char *hostname, const char *remote_user,
716b528cefcSMark Murray const char *local_user, size_t cmd_len,
717b528cefcSMark Murray const char *cmd))
718b528cefcSMark Murray {
719b528cefcSMark Murray int error;
7208373020dSJacques Vidrine struct addrinfo *a;
7214137ff4cSJacques Vidrine int socketfailed = 1;
722b528cefcSMark Murray int ret;
723b528cefcSMark Murray
724b528cefcSMark Murray for (a = ai; a != NULL; a = a->ai_next) {
725b528cefcSMark Murray int s;
726b528cefcSMark Murray int errsock;
727b528cefcSMark Murray
728b528cefcSMark Murray s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
729b528cefcSMark Murray if (s < 0)
730b528cefcSMark Murray continue;
7314137ff4cSJacques Vidrine socketfailed = 0;
732b528cefcSMark Murray if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
7334137ff4cSJacques Vidrine char addr[128];
7344137ff4cSJacques Vidrine if(getnameinfo(a->ai_addr, a->ai_addrlen,
7354137ff4cSJacques Vidrine addr, sizeof(addr), NULL, 0, NI_NUMERICHOST) == 0)
7364137ff4cSJacques Vidrine warn ("connect(%s [%s])", hostname, addr);
7374137ff4cSJacques Vidrine else
738b528cefcSMark Murray warn ("connect(%s)", hostname);
739b528cefcSMark Murray close (s);
740b528cefcSMark Murray continue;
741b528cefcSMark Murray }
742b528cefcSMark Murray if (do_errsock) {
7435e9cd1aeSAssar Westerlund struct addrinfo *ea, *eai;
744b528cefcSMark Murray struct addrinfo hints;
745b528cefcSMark Murray
746b528cefcSMark Murray memset (&hints, 0, sizeof(hints));
747b528cefcSMark Murray hints.ai_socktype = a->ai_socktype;
748b528cefcSMark Murray hints.ai_protocol = a->ai_protocol;
749b528cefcSMark Murray hints.ai_family = a->ai_family;
750b528cefcSMark Murray hints.ai_flags = AI_PASSIVE;
751b528cefcSMark Murray
7525e9cd1aeSAssar Westerlund errsock = -1;
7535e9cd1aeSAssar Westerlund
7545e9cd1aeSAssar Westerlund error = getaddrinfo (NULL, "0", &hints, &eai);
755b528cefcSMark Murray if (error)
756b528cefcSMark Murray errx (1, "getaddrinfo: %s", gai_strerror(error));
7575e9cd1aeSAssar Westerlund for (ea = eai; ea != NULL; ea = ea->ai_next) {
7585e9cd1aeSAssar Westerlund errsock = socket (ea->ai_family, ea->ai_socktype,
7595e9cd1aeSAssar Westerlund ea->ai_protocol);
760b528cefcSMark Murray if (errsock < 0)
7615e9cd1aeSAssar Westerlund continue;
762b528cefcSMark Murray if (bind (errsock, ea->ai_addr, ea->ai_addrlen) < 0)
763b528cefcSMark Murray err (1, "bind");
7645e9cd1aeSAssar Westerlund break;
7655e9cd1aeSAssar Westerlund }
7665e9cd1aeSAssar Westerlund if (errsock < 0)
7675e9cd1aeSAssar Westerlund err (1, "socket");
7685e9cd1aeSAssar Westerlund freeaddrinfo (eai);
769b528cefcSMark Murray } else
770b528cefcSMark Murray errsock = -1;
771b528cefcSMark Murray
772b528cefcSMark Murray ret = proto (s, errsock,
773b528cefcSMark Murray hostname,
774b528cefcSMark Murray local_user, remote_user,
775b528cefcSMark Murray cmd, cmd_len, auth_func);
776b528cefcSMark Murray close (s);
777b528cefcSMark Murray return ret;
778b528cefcSMark Murray }
7794137ff4cSJacques Vidrine if(socketfailed)
780b528cefcSMark Murray warnx ("failed to contact %s", hostname);
781b528cefcSMark Murray return -1;
782b528cefcSMark Murray }
783*ae771770SStanislav Sedov #endif /* KRB5 */
784b528cefcSMark Murray
785b528cefcSMark Murray struct getargs args[] = {
7868373020dSJacques Vidrine #ifdef KRB5
7874137ff4cSJacques Vidrine { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5" },
788c19800e8SDoug Rabson { "forward", 'f', arg_flag, &do_forward, "Forward credentials [krb5]"},
789b528cefcSMark Murray { "forwardable", 'F', arg_flag, &do_forwardable,
790c19800e8SDoug Rabson "Forward forwardable credentials [krb5]" },
791c19800e8SDoug Rabson { NULL, 'G', arg_negative_flag,&do_forward, "Don't forward credentials" },
792c19800e8SDoug Rabson { "unique", 'u', arg_flag, &do_unique_tkfile,
793c19800e8SDoug Rabson "Use unique remote credentials cache [krb5]" },
794c19800e8SDoug Rabson { "tkfile", 'U', arg_string, &unique_tkfile,
795c19800e8SDoug Rabson "Specifies remote credentials cache [krb5]" },
796c19800e8SDoug Rabson { "protocol", 'P', arg_string, &protocol_version_str,
797c19800e8SDoug Rabson "Protocol version [krb5]", "protocol" },
7988373020dSJacques Vidrine #endif
7998373020dSJacques Vidrine { "broken", 'K', arg_flag, &use_only_broken, "Use only priv port" },
800*ae771770SStanislav Sedov #if defined(KRB5)
8018373020dSJacques Vidrine { "encrypt", 'x', arg_flag, &do_encrypt, "Encrypt connection" },
8028373020dSJacques Vidrine { NULL, 'z', arg_negative_flag, &do_encrypt,
8038373020dSJacques Vidrine "Don't encrypt connection", NULL },
8048373020dSJacques Vidrine #endif
8058373020dSJacques Vidrine { NULL, 'd', arg_flag, &sock_debug, "Enable socket debugging" },
8068373020dSJacques Vidrine { "input", 'n', arg_negative_flag, &input, "Close stdin" },
807b528cefcSMark Murray { "port", 'p', arg_string, &port_str, "Use this port",
8088373020dSJacques Vidrine "port" },
8098373020dSJacques Vidrine { "user", 'l', arg_string, &user, "Run as this user", "login" },
8104137ff4cSJacques Vidrine { "stderr", 'e', arg_negative_flag, &do_errsock, "Don't open stderr"},
811c19800e8SDoug Rabson #ifdef KRB5
812c19800e8SDoug Rabson #endif
8134137ff4cSJacques Vidrine { "version", 0, arg_flag, &do_version, NULL },
8144137ff4cSJacques Vidrine { "help", 0, arg_flag, &do_help, NULL }
815b528cefcSMark Murray };
816b528cefcSMark Murray
817b528cefcSMark Murray static void
usage(int ret)818b528cefcSMark Murray usage (int ret)
819b528cefcSMark Murray {
820b528cefcSMark Murray arg_printusage (args,
821b528cefcSMark Murray sizeof(args) / sizeof(args[0]),
822b528cefcSMark Murray NULL,
8238373020dSJacques Vidrine "[login@]host [command]");
824b528cefcSMark Murray exit (ret);
825b528cefcSMark Murray }
826b528cefcSMark Murray
827b528cefcSMark Murray /*
828b528cefcSMark Murray *
829b528cefcSMark Murray */
830b528cefcSMark Murray
831b528cefcSMark Murray int
main(int argc,char ** argv)832b528cefcSMark Murray main(int argc, char **argv)
833b528cefcSMark Murray {
834b528cefcSMark Murray int priv_port1, priv_port2;
835b528cefcSMark Murray int priv_socket1, priv_socket2;
836bbd80c28SJacques Vidrine int argindex = 0;
8378373020dSJacques Vidrine int error;
8388373020dSJacques Vidrine struct addrinfo hints, *ai;
839b528cefcSMark Murray int ret = 1;
840b528cefcSMark Murray char *cmd;
8414137ff4cSJacques Vidrine char *tmp;
842b528cefcSMark Murray size_t cmd_len;
843b528cefcSMark Murray const char *local_user;
844b528cefcSMark Murray char *host = NULL;
845b528cefcSMark Murray int host_index = -1;
8468373020dSJacques Vidrine #ifdef KRB5
847b528cefcSMark Murray int status;
8488373020dSJacques Vidrine #endif
8495e9cd1aeSAssar Westerlund uid_t uid;
850b528cefcSMark Murray
851b528cefcSMark Murray priv_port1 = priv_port2 = IPPORT_RESERVED-1;
852b528cefcSMark Murray priv_socket1 = rresvport(&priv_port1);
853b528cefcSMark Murray priv_socket2 = rresvport(&priv_port2);
8545e9cd1aeSAssar Westerlund uid = getuid ();
8555e9cd1aeSAssar Westerlund if (setuid (uid) || (uid != 0 && setuid(0) == 0))
8565e9cd1aeSAssar Westerlund err (1, "setuid");
857b528cefcSMark Murray
858adb0ddaeSAssar Westerlund setprogname (argv[0]);
859b528cefcSMark Murray
860b528cefcSMark Murray if (argc >= 2 && argv[1][0] != '-') {
861b528cefcSMark Murray host = argv[host_index = 1];
862bbd80c28SJacques Vidrine argindex = 1;
863b528cefcSMark Murray }
864b528cefcSMark Murray
8655e9cd1aeSAssar Westerlund if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
866bbd80c28SJacques Vidrine &argindex))
8675e9cd1aeSAssar Westerlund usage (1);
8685e9cd1aeSAssar Westerlund
8694137ff4cSJacques Vidrine if (do_help)
8704137ff4cSJacques Vidrine usage (0);
8714137ff4cSJacques Vidrine
8724137ff4cSJacques Vidrine if (do_version) {
8734137ff4cSJacques Vidrine print_version (NULL);
8744137ff4cSJacques Vidrine return 0;
8754137ff4cSJacques Vidrine }
8764137ff4cSJacques Vidrine
877c19800e8SDoug Rabson #ifdef KRB5
8780cadf2f4SJacques Vidrine if(protocol_version_str != NULL) {
8790cadf2f4SJacques Vidrine if(strcasecmp(protocol_version_str, "N") == 0)
8800cadf2f4SJacques Vidrine protocol_version = 2;
8810cadf2f4SJacques Vidrine else if(strcasecmp(protocol_version_str, "O") == 0)
8820cadf2f4SJacques Vidrine protocol_version = 1;
8830cadf2f4SJacques Vidrine else {
8840cadf2f4SJacques Vidrine char *end;
8850cadf2f4SJacques Vidrine int v;
8860cadf2f4SJacques Vidrine v = strtol(protocol_version_str, &end, 0);
8870cadf2f4SJacques Vidrine if(*end != '\0' || (v != 1 && v != 2)) {
8880cadf2f4SJacques Vidrine errx(1, "unknown protocol version \"%s\"",
8890cadf2f4SJacques Vidrine protocol_version_str);
8900cadf2f4SJacques Vidrine }
8910cadf2f4SJacques Vidrine protocol_version = v;
8920cadf2f4SJacques Vidrine }
8930cadf2f4SJacques Vidrine }
8940cadf2f4SJacques Vidrine
8958373020dSJacques Vidrine status = krb5_init_context (&context);
8968373020dSJacques Vidrine if (status) {
8978373020dSJacques Vidrine if(use_v5 == 1)
8988373020dSJacques Vidrine errx(1, "krb5_init_context failed: %d", status);
8998373020dSJacques Vidrine else
9008373020dSJacques Vidrine use_v5 = 0;
9018373020dSJacques Vidrine }
9028373020dSJacques Vidrine
903bbd80c28SJacques Vidrine /* request for forwardable on the command line means we should
904bbd80c28SJacques Vidrine also forward */
905bbd80c28SJacques Vidrine if (do_forwardable == 1)
9068373020dSJacques Vidrine do_forward = 1;
907bbd80c28SJacques Vidrine
9088373020dSJacques Vidrine #endif
909b528cefcSMark Murray
910b528cefcSMark Murray if (use_only_broken) {
9118373020dSJacques Vidrine #ifdef KRB5
912b528cefcSMark Murray use_v5 = 0;
9138373020dSJacques Vidrine #endif
914b528cefcSMark Murray }
915b528cefcSMark Murray
9164137ff4cSJacques Vidrine if(priv_socket1 < 0) {
9174137ff4cSJacques Vidrine if (use_only_broken)
9184137ff4cSJacques Vidrine errx (1, "unable to bind reserved port: is rsh setuid root?");
9194137ff4cSJacques Vidrine use_broken = 0;
920b528cefcSMark Murray }
921b528cefcSMark Murray
922*ae771770SStanislav Sedov #if defined(KRB5)
9234137ff4cSJacques Vidrine if (do_encrypt == 1 && use_only_broken)
9244137ff4cSJacques Vidrine errx (1, "encryption not supported with old style authentication");
9258373020dSJacques Vidrine #endif
9264137ff4cSJacques Vidrine
9274137ff4cSJacques Vidrine
9288373020dSJacques Vidrine
9298373020dSJacques Vidrine #ifdef KRB5
930b528cefcSMark Murray if (do_unique_tkfile && unique_tkfile != NULL)
931b528cefcSMark Murray errx (1, "Only one of -u and -U allowed.");
932b528cefcSMark Murray
933b528cefcSMark Murray if (do_unique_tkfile)
934c19800e8SDoug Rabson strlcpy(tkfile,"-u ", sizeof(tkfile));
935b528cefcSMark Murray else if (unique_tkfile != NULL) {
936b528cefcSMark Murray if (strchr(unique_tkfile,' ') != NULL) {
937b528cefcSMark Murray warnx("Space is not allowed in tkfilename");
938b528cefcSMark Murray usage(1);
939b528cefcSMark Murray }
940b528cefcSMark Murray do_unique_tkfile = 1;
941b528cefcSMark Murray snprintf (tkfile, sizeof(tkfile), "-U %s ", unique_tkfile);
942b528cefcSMark Murray }
9438373020dSJacques Vidrine #endif
944b528cefcSMark Murray
945b528cefcSMark Murray if (host == NULL) {
946bbd80c28SJacques Vidrine if (argc - argindex < 1)
947b528cefcSMark Murray usage (1);
948b528cefcSMark Murray else
949bbd80c28SJacques Vidrine host = argv[host_index = argindex++];
950b528cefcSMark Murray }
951b528cefcSMark Murray
9524137ff4cSJacques Vidrine if((tmp = strchr(host, '@')) != NULL) {
9534137ff4cSJacques Vidrine *tmp++ = '\0';
9544137ff4cSJacques Vidrine user = host;
9554137ff4cSJacques Vidrine host = tmp;
9564137ff4cSJacques Vidrine }
9574137ff4cSJacques Vidrine
958bbd80c28SJacques Vidrine if (argindex == argc) {
959b528cefcSMark Murray close (priv_socket1);
960b528cefcSMark Murray close (priv_socket2);
961b528cefcSMark Murray argv[0] = "rlogin";
962b528cefcSMark Murray execvp ("rlogin", argv);
963b528cefcSMark Murray err (1, "execvp rlogin");
964b528cefcSMark Murray }
965b528cefcSMark Murray
966b528cefcSMark Murray local_user = get_default_username ();
967b528cefcSMark Murray if (local_user == NULL)
968b528cefcSMark Murray errx (1, "who are you?");
969b528cefcSMark Murray
970b528cefcSMark Murray if (user == NULL)
971b528cefcSMark Murray user = local_user;
972b528cefcSMark Murray
973bbd80c28SJacques Vidrine cmd_len = construct_command(&cmd, argc - argindex, argv + argindex);
974b528cefcSMark Murray
975b528cefcSMark Murray /*
976b528cefcSMark Murray * Try all different authentication methods
977b528cefcSMark Murray */
978b528cefcSMark Murray
9798373020dSJacques Vidrine #ifdef KRB5
980b528cefcSMark Murray if (ret && use_v5) {
9818373020dSJacques Vidrine memset (&hints, 0, sizeof(hints));
9828373020dSJacques Vidrine hints.ai_socktype = SOCK_STREAM;
9838373020dSJacques Vidrine hints.ai_protocol = IPPROTO_TCP;
984b528cefcSMark Murray
9858373020dSJacques Vidrine if(port_str == NULL) {
9868373020dSJacques Vidrine error = getaddrinfo(host, "kshell", &hints, &ai);
9878373020dSJacques Vidrine if(error == EAI_NONAME)
9888373020dSJacques Vidrine error = getaddrinfo(host, "544", &hints, &ai);
9898373020dSJacques Vidrine } else
9908373020dSJacques Vidrine error = getaddrinfo(host, port_str, &hints, &ai);
9918373020dSJacques Vidrine
9928373020dSJacques Vidrine if(error)
9938373020dSJacques Vidrine errx (1, "getaddrinfo: %s", gai_strerror(error));
994b528cefcSMark Murray
995b528cefcSMark Murray auth_method = AUTH_KRB5;
9960cadf2f4SJacques Vidrine again:
9978373020dSJacques Vidrine ret = doit (host, ai, user, local_user, cmd, cmd_len,
998b528cefcSMark Murray send_krb5_auth);
9990cadf2f4SJacques Vidrine if(ret != 0 && sendauth_version_error &&
10000cadf2f4SJacques Vidrine protocol_version == 2) {
10010cadf2f4SJacques Vidrine protocol_version = 1;
10020cadf2f4SJacques Vidrine goto again;
10030cadf2f4SJacques Vidrine }
10048373020dSJacques Vidrine freeaddrinfo(ai);
1005b528cefcSMark Murray }
10068373020dSJacques Vidrine #endif
1007b528cefcSMark Murray if (ret && use_broken) {
10088373020dSJacques Vidrine memset (&hints, 0, sizeof(hints));
10098373020dSJacques Vidrine hints.ai_socktype = SOCK_STREAM;
10108373020dSJacques Vidrine hints.ai_protocol = IPPROTO_TCP;
1011b528cefcSMark Murray
10128373020dSJacques Vidrine if(port_str == NULL) {
10138373020dSJacques Vidrine error = getaddrinfo(host, "shell", &hints, &ai);
10148373020dSJacques Vidrine if(error == EAI_NONAME)
10158373020dSJacques Vidrine error = getaddrinfo(host, "514", &hints, &ai);
10168373020dSJacques Vidrine } else
10178373020dSJacques Vidrine error = getaddrinfo(host, port_str, &hints, &ai);
10188373020dSJacques Vidrine
10198373020dSJacques Vidrine if(error)
10208373020dSJacques Vidrine errx (1, "getaddrinfo: %s", gai_strerror(error));
10218373020dSJacques Vidrine
1022b528cefcSMark Murray auth_method = AUTH_BROKEN;
10238373020dSJacques Vidrine ret = doit_broken (argc, argv, host_index, ai,
1024b528cefcSMark Murray user, local_user,
1025b528cefcSMark Murray priv_socket1,
1026b528cefcSMark Murray do_errsock ? priv_socket2 : -1,
1027b528cefcSMark Murray cmd, cmd_len);
10288373020dSJacques Vidrine freeaddrinfo(ai);
1029b528cefcSMark Murray }
10300cadf2f4SJacques Vidrine free(cmd);
1031b528cefcSMark Murray return ret;
1032b528cefcSMark Murray }
1033