xref: /plan9/sys/src/cmd/rx.c (revision 588d0145e19f8596f2f4442d05dd8a9eda147983)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 
5 int	eof;		/* send an eof if true */
6 int	crtonl;		/* convert all received \r to \n */
7 int	returns;	/* strip \r on reception */
8 char	*note = "die: yankee dog";
9 char	*ruser;		/* for BSD authentication */
10 char *key;
11 
12 void	rex(int, char*, char*);
13 void	tcpexec(int, char*, char*);
14 int	call(char *, char*, char*, char**);
15 char	*buildargs(char*[]);
16 int	send(int);
17 void	error(char*, char*);
18 void	sshexec(char*, char*);
19 
20 void
usage(void)21 usage(void)
22 {
23 	fprint(2, "usage: %s [-e] [-T] [-r] [-k keypattern] [-l user] net!host command...\n", argv0);
24 	exits("usage");
25 }
26 
27 static int
catch(void *,char * s)28 catch(void *, char *s)
29 {
30 	return strstr(s, "alarm") != nil;
31 }
32 
33 void
main(int argc,char * argv[])34 main(int argc, char *argv[])
35 {
36 	char *host, *addr, *args;
37 	int fd;
38 
39 	key = "";
40 	eof = 1;
41 	crtonl = 0;
42 	returns = 1;
43 	ARGBEGIN{
44 	case 'T':
45 		crtonl = 1;
46 		break;
47 	case 'r':
48 		returns = 0;
49 		break;
50 	case 'e':
51 		eof = 0;
52 		break;
53 	case 'k':
54 		key = EARGF(usage());
55 		break;
56 	case 'l':
57 		ruser = EARGF(usage());
58 		break;
59 	default:
60 		usage();
61 	}ARGEND
62 
63 	if(argc < 2)
64 		usage();
65 	host = argv[0];
66 	args = buildargs(&argv[1]);
67 	atnotify(catch, 1);
68 
69 	/* try rexexec p9any then dial again with p9sk2 */
70 	fd = call(0, host, "rexexec", &addr);
71 	if(fd >= 0)
72 		rex(fd, args, "p9any");
73 	close(fd);
74 	fd = call(0, host, "rexexec", &addr);
75 	if(fd >= 0)
76 		rex(fd, args, "p9sk2");
77 	close(fd);
78 
79 	/* if there's an ssh port, try that */
80 	fd = call("tcp", host, "ssh", &addr);
81 	if(fd >= 0){
82 		close(fd);
83 		sshexec(host, args);
84 		/* falls through if no ssh */
85 	}
86 
87 	/* specific attempts */
88 	fd = call("tcp", host, "shell", &addr);
89 	if(fd >= 0)
90 		tcpexec(fd, addr, args);
91 
92 	error("can't dial", host);
93 	exits(0);
94 }
95 
96 int
call(char * net,char * host,char * service,char ** na)97 call(char *net, char *host, char *service, char **na)
98 {
99 	*na = netmkaddr(host, net, service);
100 	return dial(*na, 0, 0, 0);
101 }
102 
103 void
rex(int fd,char * cmd,char * proto)104 rex(int fd, char *cmd, char *proto)
105 {
106 	char buf[4096];
107 	int kid, n, oalarm;
108 	AuthInfo *ai;
109 
110 	oalarm = alarm(2 * 60 * 1000);		/* don't hang forever */
111 	ai = auth_proxy(fd, auth_getkey, "proto=%s role=client %s", proto, key);
112 	alarm(oalarm);
113 	if(ai == nil){
114 		if(strcmp(proto, "p9any") == 0)
115 			return;
116 		error("auth_proxy", nil);
117 	}
118 	write(fd, cmd, strlen(cmd)+1);
119 
120 	kid = send(fd);
121 	while((n=read(fd, buf, sizeof buf))>0)
122 		if(write(1, buf, n)!=n)
123 			error("write error", 0);
124 	sleep(250);
125 	postnote(PNPROC, kid, note);/**/
126 	exits(0);
127 }
128 
129 void
tcpexec(int fd,char * addr,char * cmd)130 tcpexec(int fd, char *addr, char *cmd)
131 {
132 	char *cp, *ep, *u, *ru, buf[4096];
133 	int kid, n;
134 
135 	/*
136 	 *  do the ucb authentication and send command
137 	 */
138 	u = getuser();
139 	ru = ruser;
140 	if(ru == nil)
141 		ru = u;
142 	if(write(fd, "", 1)<0 || write(fd, u, strlen(u)+1)<0
143 	|| write(fd, ru, strlen(ru)+1)<0 || write(fd, cmd, strlen(cmd)+1)<0){
144 		close(fd);
145 		error("can't authenticate to", addr);
146 	}
147 
148 	/*
149 	 *  get authentication reply
150 	 */
151 	if(read(fd, buf, 1) != 1){
152 		close(fd);
153 		error("can't authenticate to", addr);
154 	}
155 	if(buf[0] != 0){
156 		while(read(fd, buf, 1) == 1){
157 			write(2, buf, 1);
158 			if(buf[0] == '\n')
159 				break;
160 		}
161 		close(fd);
162 		error("rejected by", addr);
163 	}
164 
165 	kid = send(fd);
166 	while((n=read(fd, buf, sizeof buf))>0){
167 		if(crtonl) {
168 			/* convert cr's to nl's */
169 			for (cp = buf; cp < buf + n; cp++)
170 				if (*cp == '\r')
171 					*cp = '\n';
172 		}
173 		else if(!returns){
174 			/* convert cr's to null's */
175 			cp = buf;
176 			ep = buf + n;
177 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
178 				memmove(cp, cp+1, ep-cp-1);
179 				ep--;
180 				n--;
181 			}
182 		}
183 		if(write(1, buf, n)!=n)
184 			error("write error", 0);
185 	}
186 	sleep(250);
187 	postnote(PNPROC, kid, note);/**/
188 	exits(0);
189 }
190 
191 void
sshexec(char * host,char * cmd)192 sshexec(char *host, char *cmd)
193 {
194 	char *argv[10];
195 	int n;
196 
197 	n = 0;
198 	argv[n++] = "ssh";
199 	argv[n++] = "-iCm";
200 	if(!returns)
201 		argv[n++] = "-r";
202 	if(ruser){
203 		argv[n++] = "-l";
204 		argv[n++] = ruser;
205 	}
206 	argv[n++] = host;
207 	argv[n++] = cmd;
208 	argv[n] = 0;
209 	exec("/bin/ssh", argv);
210 }
211 
212 int
send(int fd)213 send(int fd)
214 {
215 	char buf[4096];
216 	int n;
217 	int kid;
218 	switch(kid = fork()){
219 	case -1:
220 		error("fork error", 0);
221 	case 0:
222 		break;
223 	default:
224 		return kid;
225 	}
226 	while((n=read(0, buf, sizeof buf))>0)
227 		if(write(fd, buf, n)!=n)
228 			exits("write error");
229 	if(eof)
230 		write(fd, buf, 0);
231 
232 	exits(0);
233 	return 0;			/* to keep compiler happy */
234 }
235 
236 void
error(char * s,char * z)237 error(char *s, char *z)
238 {
239 	if(z == 0)
240 		fprint(2, "%s: %s: %r\n", argv0, s);
241 	else
242 		fprint(2, "%s: %s %s: %r\n", argv0, s, z);
243 	exits(s);
244 }
245 
246 char *
buildargs(char * argv[])247 buildargs(char *argv[])
248 {
249 	char *args;
250 	int m, n;
251 
252 	args = malloc(1);
253 	args[0] = '\0';
254 	n = 0;
255 	while(*argv){
256 		m = strlen(*argv) + 1;
257 		args = realloc(args, n+m +1);
258 		if(args == 0)
259 			error("malloc fail", 0);
260 		args[n] = ' ';	/* smashes old null */
261 		strcpy(args+n+1, *argv);
262 		n += m;
263 		argv++;
264 	}
265 	return args;
266 }
267