1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <libsec.h> 5 6 enum { 7 Encnone, 8 Encssl, 9 Enctls, 10 }; 11 12 static char *encprotos[] = { 13 [Encnone] = "clear", 14 [Encssl] = "ssl", 15 [Enctls] = "tls", 16 nil, 17 }; 18 19 char *keyspec = ""; 20 char *filterp; 21 char *ealgs = "rc4_256 sha1"; 22 int encproto = Encnone; 23 char *aan = "/bin/aan"; 24 AuthInfo *ai; 25 int debug; 26 int doauth = 1; 27 28 int connect(char*, char*, int); 29 int passive(void); 30 int old9p(int); 31 void catcher(void*, char*); 32 void sysfatal(char*, ...); 33 void usage(void); 34 int filter(int, char *, char *); 35 36 static void mksecret(char *, uchar *); 37 38 void 39 post(char *name, char *envname, int srvfd) 40 { 41 int fd; 42 char buf[32]; 43 44 fd = create(name, OWRITE, 0600); 45 if(fd < 0) 46 return; 47 sprint(buf, "%d",srvfd); 48 if(write(fd, buf, strlen(buf)) != strlen(buf)) 49 sysfatal("srv write: %r"); 50 close(fd); 51 putenv(envname, name); 52 } 53 54 static int 55 lookup(char *s, char *l[]) 56 { 57 int i; 58 59 for (i = 0; l[i] != 0; i++) 60 if (strcmp(l[i], s) == 0) 61 return i; 62 return -1; 63 } 64 65 void 66 main(int argc, char **argv) 67 { 68 char *mntpt; 69 int fd, mntflags; 70 int oldserver; 71 char *srvpost, srvfile[64]; 72 int backwards = 0; 73 74 srvpost = nil; 75 oldserver = 0; 76 mntflags = MREPL; 77 ARGBEGIN{ 78 case 'A': 79 doauth = 0; 80 break; 81 case 'a': 82 mntflags = MAFTER; 83 break; 84 case 'b': 85 mntflags = MBEFORE; 86 break; 87 case 'c': 88 mntflags |= MCREATE; 89 break; 90 case 'C': 91 mntflags |= MCACHE; 92 break; 93 case 'd': 94 debug++; 95 break; 96 case 'f': 97 /* ignored but allowed for compatibility */ 98 break; 99 case 'O': 100 case 'o': 101 oldserver = 1; 102 break; 103 case 'E': 104 if ((encproto = lookup(EARGF(usage()), encprotos)) < 0) 105 usage(); 106 break; 107 case 'e': 108 ealgs = EARGF(usage()); 109 if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) 110 ealgs = nil; 111 break; 112 case 'k': 113 keyspec = EARGF(usage()); 114 break; 115 case 'p': 116 filterp = aan; 117 break; 118 case 's': 119 srvpost = EARGF(usage()); 120 break; 121 case 'B': 122 backwards = 1; 123 break; 124 default: 125 usage(); 126 }ARGEND; 127 128 mntpt = 0; /* to shut up compiler */ 129 if(backwards){ 130 switch(argc) { 131 default: 132 mntpt = argv[0]; 133 break; 134 case 0: 135 usage(); 136 } 137 } else { 138 switch(argc) { 139 case 2: 140 mntpt = argv[1]; 141 break; 142 case 3: 143 mntpt = argv[2]; 144 break; 145 default: 146 usage(); 147 } 148 } 149 150 if (encproto == Enctls) 151 sysfatal("%s: tls has not yet been implemented\n", argv[0]); 152 153 notify(catcher); 154 alarm(60*1000); 155 156 if(backwards) 157 fd = passive(); 158 else 159 fd = connect(argv[0], argv[1], oldserver); 160 161 if (!oldserver) 162 fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter", encprotos[encproto]); 163 164 if (encproto != Encnone && ealgs && ai) { 165 uchar key[16]; 166 uchar digest[SHA1dlen]; 167 char fromclientsecret[21]; 168 char fromserversecret[21]; 169 int i; 170 171 memmove(key+4, ai->secret, ai->nsecret); 172 173 /* exchange random numbers */ 174 srand(truerand()); 175 for(i = 0; i < 4; i++) 176 key[i] = rand(); 177 if(write(fd, key, 4) != 4) 178 sysfatal("can't write key part: %r"); 179 if(readn(fd, key+12, 4) != 4) 180 sysfatal("can't read key part: %r"); 181 182 /* scramble into two secrets */ 183 sha1(key, sizeof(key), digest, nil); 184 mksecret(fromclientsecret, digest); 185 mksecret(fromserversecret, digest+10); 186 187 if (filterp) 188 fd = filter(fd, filterp, argv[0]); 189 190 /* set up encryption */ 191 fd = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); 192 if(fd < 0) 193 sysfatal("can't establish ssl connection: %r"); 194 } 195 else if (filterp) 196 fd = filter(fd, filterp, argv[0]); 197 198 if(srvpost){ 199 sprint(srvfile, "/srv/%s", srvpost); 200 remove(srvfile); 201 post(srvfile, srvpost, fd); 202 } 203 if(mount(fd, -1, mntpt, mntflags, "") < 0) 204 sysfatal("can't mount %s: %r", argv[1]); 205 alarm(0); 206 207 if(backwards && argc > 1){ 208 exec(argv[1], &argv[1]); 209 sysfatal("exec: %r"); 210 } 211 exits(0); 212 } 213 214 void 215 catcher(void*, char *msg) 216 { 217 if(strcmp(msg, "alarm") == 0) 218 noted(NCONT); 219 noted(NDFLT); 220 } 221 222 int 223 old9p(int fd) 224 { 225 int p[2]; 226 227 if(pipe(p) < 0) 228 sysfatal("pipe: %r"); 229 230 switch(rfork(RFPROC|RFFDG|RFNAMEG)) { 231 case -1: 232 sysfatal("rfork srvold9p: %r"); 233 case 0: 234 if(fd != 1){ 235 dup(fd, 1); 236 close(fd); 237 } 238 if(p[0] != 0){ 239 dup(p[0], 0); 240 close(p[0]); 241 } 242 close(p[1]); 243 if(0){ 244 fd = open("/sys/log/cpu", OWRITE); 245 if(fd != 2){ 246 dup(fd, 2); 247 close(fd); 248 } 249 execl("/bin/srvold9p", "srvold9p", "-ds", nil); 250 } else 251 execl("/bin/srvold9p", "srvold9p", "-s", nil); 252 sysfatal("exec srvold9p: %r"); 253 default: 254 close(fd); 255 close(p[0]); 256 } 257 return p[1]; 258 } 259 260 int 261 connect(char *system, char *tree, int oldserver) 262 { 263 char buf[ERRMAX], dir[128], *na; 264 int fd, n; 265 char *authp; 266 267 na = netmkaddr(system, 0, "exportfs"); 268 if((fd = dial(na, 0, dir, 0)) < 0) 269 sysfatal("can't dial %s: %r", system); 270 271 if(doauth){ 272 if(oldserver) 273 authp = "p9sk2"; 274 else 275 authp = "p9any"; 276 277 ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", authp, keyspec); 278 if(ai == nil) 279 sysfatal("%r: %s", system); 280 } 281 282 n = write(fd, tree, strlen(tree)); 283 if(n < 0) 284 sysfatal("can't write tree: %r"); 285 286 strcpy(buf, "can't read tree"); 287 288 n = read(fd, buf, sizeof buf - 1); 289 if(n!=2 || buf[0]!='O' || buf[1]!='K'){ 290 buf[sizeof buf - 1] = '\0'; 291 sysfatal("bad remote tree: %s", buf); 292 } 293 294 if(oldserver) 295 return old9p(fd); 296 return fd; 297 } 298 299 int 300 passive(void) 301 { 302 int fd; 303 304 /* 305 * Ignore doauth==0 on purpose. Is it useful here? 306 */ 307 308 ai = auth_proxy(0, auth_getkey, "proto=p9any role=server"); 309 if(ai == nil) 310 sysfatal("auth_proxy: %r"); 311 if(auth_chuid(ai, nil) < 0) 312 sysfatal("auth_chuid: %r"); 313 putenv("service", "import"); 314 315 fd = dup(0, -1); 316 close(0); 317 open("/dev/null", ORDWR); 318 close(1); 319 open("/dev/null", ORDWR); 320 321 return fd; 322 } 323 324 void 325 usage(void) 326 { 327 fprint(2, "usage: import [-abcC] [-A] [-E clear|ssl|tls] [-e 'crypt auth'|clear] [-k keypattern] [-p] host remotefs [mountpoint]\n"); 328 exits("usage"); 329 } 330 331 /* Network on fd1, mount driver on fd0 */ 332 int 333 filter(int fd, char *cmd, char *host) 334 { 335 int p[2], len, argc; 336 char newport[256], buf[256], *s; 337 char *argv[16], *file, *pbuf; 338 339 if ((len = read(fd, newport, sizeof newport - 1)) < 0) 340 sysfatal("filter: cannot write port; %r\n"); 341 newport[len] = '\0'; 342 343 if ((s = strchr(newport, '!')) == nil) 344 sysfatal("filter: illegally formatted port %s\n", newport); 345 346 strecpy(buf, buf+sizeof buf, netmkaddr(host, "tcp", "0")); 347 pbuf = strrchr(buf, '!'); 348 strecpy(pbuf, buf+sizeof buf, s); 349 350 if(debug) 351 fprint(2, "filter: remote port %s\n", newport); 352 353 argc = tokenize(cmd, argv, nelem(argv)-2); 354 if (argc == 0) 355 sysfatal("filter: empty command"); 356 argv[argc++] = "-c"; 357 argv[argc++] = buf; 358 argv[argc] = nil; 359 file = argv[0]; 360 if (s = strrchr(argv[0], '/')) 361 argv[0] = s+1; 362 363 if(pipe(p) < 0) 364 sysfatal("pipe: %r"); 365 366 switch(rfork(RFNOWAIT|RFPROC|RFFDG)) { 367 case -1: 368 sysfatal("rfork record module: %r"); 369 case 0: 370 dup(p[0], 1); 371 dup(p[0], 0); 372 close(p[0]); 373 close(p[1]); 374 exec(file, argv); 375 sysfatal("exec record module: %r"); 376 default: 377 close(fd); 378 close(p[0]); 379 } 380 return p[1]; 381 } 382 383 static void 384 mksecret(char *t, uchar *f) 385 { 386 sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", 387 f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); 388 } 389