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