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