xref: /plan9/sys/src/cmd/rx.c (revision 9b943567965ba040fd275927fbe088656eb8ce4f)
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;
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 *host, char *cmd);
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 erexexec 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, buf[4096];
124 	int kid, n;
125 	char *r;
126 
127 	/*
128 	 *  do the ucb authentication and send command
129 	 */
130 	u = getuser();
131 	r = ruser ? ruser : u;
132 	if(write(fd, "", 1)<0 || write(fd, u, strlen(u)+1)<0
133 	|| write(fd, r, strlen(r)+1)<0 || write(fd, cmd, strlen(cmd)+1)<0){
134 		close(fd);
135 		error("can't authenticate to", addr);
136 	}
137 
138 	/*
139 	 *  get authentication reply
140 	 */
141 	if(read(fd, buf, 1) != 1){
142 		close(fd);
143 		error("can't authenticate to", addr);
144 	}
145 	if(buf[0] != 0){
146 		while(read(fd, buf, 1) == 1){
147 			write(2, buf, 1);
148 			if(buf[0] == '\n')
149 				break;
150 		}
151 		close(fd);
152 		error("rejected by", addr);
153 	}
154 
155 	kid = send(fd);
156 	while((n=read(fd, buf, sizeof buf))>0){
157 		if(crtonl) {
158 			/* convert cr's to nl's */
159 			for (cp = buf; cp < buf + n; cp++)
160 				if (*cp == '\r')
161 					*cp = '\n';
162 		}
163 		else if(!returns){
164 			/* convert cr's to null's */
165 			cp = buf;
166 			ep = buf + n;
167 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
168 				memmove(cp, cp+1, ep-cp-1);
169 				ep--;
170 				n--;
171 			}
172 		}
173 		if(write(1, buf, n)!=n)
174 			error("write error", 0);
175 	}
176 	sleep(250);
177 	postnote(PNPROC, kid, note);/**/
178 	exits(0);
179 }
180 
181 void
182 sshexec(char *host, char *cmd)
183 {
184 	execl("/bin/ssh", "ssh", "-iCm", host, cmd, 0);
185 }
186 
187 int
188 send(int fd)
189 {
190 	char buf[4096];
191 	int n;
192 	int kid;
193 	switch(kid = fork()){
194 	case -1:
195 		error("fork error", 0);
196 	case 0:
197 		break;
198 	default:
199 		return kid;
200 	}
201 	while((n=read(0, buf, sizeof buf))>0)
202 		if(write(fd, buf, n)!=n)
203 			exits("write error");
204 	if(eof)
205 		write(fd, buf, 0);
206 
207 	exits(0);
208 	return 0;			/* to keep compiler happy */
209 }
210 
211 void
212 error(char *s, char *z)
213 {
214 	if(z == 0)
215 		fprint(2, "%s: %s: %r\n", argv0, s);
216 	else
217 		fprint(2, "%s: %s %s: %r\n", argv0, s, z);
218 	exits(s);
219 }
220 
221 char *
222 buildargs(char *argv[])
223 {
224 	char *args;
225 	int m, n;
226 
227 	args = malloc(1);
228 	args[0] = '\0';
229 	n = 0;
230 	while(*argv){
231 		m = strlen(*argv) + 1;
232 		args = realloc(args, n+m +1);
233 		if(args == 0)
234 			error("malloc fail", 0);
235 		args[n] = ' ';	/* smashes old null */
236 		strcpy(args+n+1, *argv);
237 		n += m;
238 		argv++;
239 	}
240 	return args;
241 }
242