xref: /freebsd-src/crypto/heimdal/appl/rsh/rsh.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
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