1162f803dSDavid du Colombier /* 2162f803dSDavid du Colombier * tftpd - tftp service, see /lib/rfc/rfc783 3162f803dSDavid du Colombier */ 43e12c5d1SDavid du Colombier #include <u.h> 53e12c5d1SDavid du Colombier #include <libc.h> 6c0eadb1cSDavid du Colombier #include <auth.h> 73e12c5d1SDavid du Colombier #include <bio.h> 83e12c5d1SDavid du Colombier #include <ip.h> 93e12c5d1SDavid du Colombier #include <ndb.h> 103e12c5d1SDavid du Colombier 119a747e4fSDavid du Colombier enum 129a747e4fSDavid du Colombier { 139a747e4fSDavid du Colombier Maxpath= 128, 149a747e4fSDavid du Colombier Maxerr= 256, 159a747e4fSDavid du Colombier }; 169a747e4fSDavid du Colombier 173e12c5d1SDavid du Colombier int dbg; 18219b2ee8SDavid du Colombier int restricted; 193e12c5d1SDavid du Colombier void sendfile(int, char*, char*); 203e12c5d1SDavid du Colombier void recvfile(int, char*, char*); 213e12c5d1SDavid du Colombier void nak(int, int, char*); 223e12c5d1SDavid du Colombier void ack(int, ushort); 233e12c5d1SDavid du Colombier void clrcon(void); 243e12c5d1SDavid du Colombier void setuser(void); 253e12c5d1SDavid du Colombier char* sunkernel(char*); 267dd7cddfSDavid du Colombier void remoteaddr(char*, char*, int); 277dd7cddfSDavid du Colombier void doserve(int); 283e12c5d1SDavid du Colombier 297dd7cddfSDavid du Colombier char bigbuf[32768]; 307dd7cddfSDavid du Colombier char raddr[64]; 313e12c5d1SDavid du Colombier 323e12c5d1SDavid du Colombier char *dir = "/lib/tftpd"; 33219b2ee8SDavid du Colombier char *dirsl; 34219b2ee8SDavid du Colombier int dirsllen; 353e12c5d1SDavid du Colombier char flog[] = "ipboot"; 369a747e4fSDavid du Colombier char net[Maxpath]; 373e12c5d1SDavid du Colombier 383e12c5d1SDavid du Colombier enum 393e12c5d1SDavid du Colombier { 403e12c5d1SDavid du Colombier Tftp_READ = 1, 413e12c5d1SDavid du Colombier Tftp_WRITE = 2, 423e12c5d1SDavid du Colombier Tftp_DATA = 3, 433e12c5d1SDavid du Colombier Tftp_ACK = 4, 443e12c5d1SDavid du Colombier Tftp_ERROR = 5, 453e12c5d1SDavid du Colombier Segsize = 512, 463e12c5d1SDavid du Colombier }; 473e12c5d1SDavid du Colombier 483e12c5d1SDavid du Colombier void 497dd7cddfSDavid du Colombier usage(void) 507dd7cddfSDavid du Colombier { 51c0eadb1cSDavid du Colombier fprint(2, "usage: %s [-dr] [-h homedir] [-s svc] [-x netmtpt]\n", 52c0eadb1cSDavid du Colombier argv0); 537dd7cddfSDavid du Colombier exits("usage"); 547dd7cddfSDavid du Colombier } 557dd7cddfSDavid du Colombier 567dd7cddfSDavid du Colombier void 573e12c5d1SDavid du Colombier main(int argc, char **argv) 583e12c5d1SDavid du Colombier { 597dd7cddfSDavid du Colombier char buf[64]; 607dd7cddfSDavid du Colombier char adir[64], ldir[64]; 617dd7cddfSDavid du Colombier int cfd, lcfd, dfd; 62162f803dSDavid du Colombier char *svc = "69"; 633e12c5d1SDavid du Colombier 64162f803dSDavid du Colombier setnetmtpt(net, sizeof net, nil); 653e12c5d1SDavid du Colombier ARGBEGIN{ 663e12c5d1SDavid du Colombier case 'd': 673e12c5d1SDavid du Colombier dbg++; 683e12c5d1SDavid du Colombier break; 693e12c5d1SDavid du Colombier case 'h': 70162f803dSDavid du Colombier dir = EARGF(usage()); 713e12c5d1SDavid du Colombier break; 72219b2ee8SDavid du Colombier case 'r': 73219b2ee8SDavid du Colombier restricted = 1; 74219b2ee8SDavid du Colombier break; 75c0eadb1cSDavid du Colombier case 's': 76c0eadb1cSDavid du Colombier svc = EARGF(usage()); 77c0eadb1cSDavid du Colombier break; 787dd7cddfSDavid du Colombier case 'x': 79162f803dSDavid du Colombier setnetmtpt(net, sizeof net, EARGF(usage())); 807dd7cddfSDavid du Colombier break; 813e12c5d1SDavid du Colombier default: 827dd7cddfSDavid du Colombier usage(); 833e12c5d1SDavid du Colombier }ARGEND 843e12c5d1SDavid du Colombier 85219b2ee8SDavid du Colombier snprint(buf, sizeof buf, "%s/", dir); 86219b2ee8SDavid du Colombier dirsl = strdup(buf); 87219b2ee8SDavid du Colombier dirsllen = strlen(dirsl); 88219b2ee8SDavid du Colombier 899a747e4fSDavid du Colombier fmtinstall('E', eipfmt); 909a747e4fSDavid du Colombier fmtinstall('I', eipfmt); 913e12c5d1SDavid du Colombier 92*64eb6bc1SDavid du Colombier /* 93*64eb6bc1SDavid du Colombier * setuser calls newns, and typical /lib/namespace files contain 94*64eb6bc1SDavid du Colombier * "cd /usr/$user", so call setuser before chdir. 95*64eb6bc1SDavid du Colombier */ 96*64eb6bc1SDavid du Colombier setuser(); 973e12c5d1SDavid du Colombier if(chdir(dir) < 0) 987dd7cddfSDavid du Colombier sysfatal("can't get to directory %s: %r", dir); 993e12c5d1SDavid du Colombier 1007dd7cddfSDavid du Colombier if(!dbg) 1013e12c5d1SDavid du Colombier switch(rfork(RFNOTEG|RFPROC|RFFDG)) { 1023e12c5d1SDavid du Colombier case -1: 1037dd7cddfSDavid du Colombier sysfatal("fork: %r"); 1043e12c5d1SDavid du Colombier case 0: 1053e12c5d1SDavid du Colombier break; 1063e12c5d1SDavid du Colombier default: 1073e12c5d1SDavid du Colombier exits(0); 1083e12c5d1SDavid du Colombier } 1093e12c5d1SDavid du Colombier 110c0eadb1cSDavid du Colombier snprint(buf, sizeof buf, "%s/udp!*!%s", net, svc); 1117dd7cddfSDavid du Colombier cfd = announce(buf, adir); 112c0eadb1cSDavid du Colombier if (cfd < 0) 113c0eadb1cSDavid du Colombier sysfatal("announcing on %s: %r", buf); 114c0eadb1cSDavid du Colombier syslog(dbg, flog, "tftpd started on %s dir %s", buf, adir); 115*64eb6bc1SDavid du Colombier // setuser(); 1163e12c5d1SDavid du Colombier for(;;) { 1177dd7cddfSDavid du Colombier lcfd = listen(adir, ldir); 1187dd7cddfSDavid du Colombier if(lcfd < 0) 119c0eadb1cSDavid du Colombier sysfatal("listening on %s: %r", adir); 1207dd7cddfSDavid du Colombier 1217dd7cddfSDavid du Colombier switch(fork()) { 1227dd7cddfSDavid du Colombier case -1: 1237dd7cddfSDavid du Colombier sysfatal("fork: %r"); 1247dd7cddfSDavid du Colombier case 0: 125c0eadb1cSDavid du Colombier dfd = accept(lcfd, ldir); 1267dd7cddfSDavid du Colombier if(dfd < 0) 1277dd7cddfSDavid du Colombier exits(0); 1287dd7cddfSDavid du Colombier remoteaddr(ldir, raddr, sizeof(raddr)); 129c0eadb1cSDavid du Colombier syslog(0, flog, "tftp connection from %s dir %s", 130c0eadb1cSDavid du Colombier raddr, ldir); 1317dd7cddfSDavid du Colombier doserve(dfd); 1327dd7cddfSDavid du Colombier exits("done"); 1337dd7cddfSDavid du Colombier break; 1347dd7cddfSDavid du Colombier default: 1357dd7cddfSDavid du Colombier close(lcfd); 1367dd7cddfSDavid du Colombier continue; 1377dd7cddfSDavid du Colombier } 1387dd7cddfSDavid du Colombier } 1397dd7cddfSDavid du Colombier } 1407dd7cddfSDavid du Colombier 1417dd7cddfSDavid du Colombier void 1427dd7cddfSDavid du Colombier doserve(int fd) 1437dd7cddfSDavid du Colombier { 1447dd7cddfSDavid du Colombier int dlen; 1457dd7cddfSDavid du Colombier char *mode, *p; 1467dd7cddfSDavid du Colombier short op; 1477dd7cddfSDavid du Colombier 1487dd7cddfSDavid du Colombier dlen = read(fd, bigbuf, sizeof(bigbuf)); 1493e12c5d1SDavid du Colombier if(dlen < 0) 1507dd7cddfSDavid du Colombier sysfatal("listen read: %r"); 1513e12c5d1SDavid du Colombier 1527dd7cddfSDavid du Colombier op = (bigbuf[0]<<8) | bigbuf[1]; 1533e12c5d1SDavid du Colombier dlen -= 2; 1547dd7cddfSDavid du Colombier mode = bigbuf+2; 1553e12c5d1SDavid du Colombier while(*mode != '\0' && dlen--) 1563e12c5d1SDavid du Colombier mode++; 1573e12c5d1SDavid du Colombier mode++; 1583e12c5d1SDavid du Colombier p = mode; 1593e12c5d1SDavid du Colombier while(*p && dlen--) 1603e12c5d1SDavid du Colombier p++; 1613e12c5d1SDavid du Colombier if(dlen == 0) { 1627dd7cddfSDavid du Colombier nak(fd, 0, "bad tftpmode"); 1637dd7cddfSDavid du Colombier close(fd); 164c0eadb1cSDavid du Colombier syslog(dbg, flog, "bad mode from %s", raddr); 1657dd7cddfSDavid du Colombier return; 1663e12c5d1SDavid du Colombier } 1673e12c5d1SDavid du Colombier 1683e12c5d1SDavid du Colombier if(op != Tftp_READ && op != Tftp_WRITE) { 1697dd7cddfSDavid du Colombier nak(fd, 4, "Illegal TFTP operation"); 1707dd7cddfSDavid du Colombier close(fd); 1713e12c5d1SDavid du Colombier syslog(dbg, flog, "bad request %d %s", op, raddr); 1727dd7cddfSDavid du Colombier return; 1733e12c5d1SDavid du Colombier } 1747dd7cddfSDavid du Colombier 175219b2ee8SDavid du Colombier if(restricted){ 17667031067SDavid du Colombier if(bigbuf[2] == '#' || 17767031067SDavid du Colombier strncmp(bigbuf+2, "../", 3)==0 || strstr(bigbuf+2, "/../") || 1787dd7cddfSDavid du Colombier (bigbuf[2] == '/' && strncmp(bigbuf+2, dirsl, dirsllen)!=0)){ 1797dd7cddfSDavid du Colombier nak(fd, 4, "Permission denied"); 1807dd7cddfSDavid du Colombier close(fd); 18139734e7eSDavid du Colombier syslog(dbg, flog, "bad request %d from %s file %s", op, raddr, bigbuf+2); 1827dd7cddfSDavid du Colombier return; 183219b2ee8SDavid du Colombier } 184219b2ee8SDavid du Colombier } 1857dd7cddfSDavid du Colombier 1863e12c5d1SDavid du Colombier if(op == Tftp_READ) 1877dd7cddfSDavid du Colombier sendfile(fd, bigbuf+2, mode); 1883e12c5d1SDavid du Colombier else 1897dd7cddfSDavid du Colombier recvfile(fd, bigbuf+2, mode); 1903e12c5d1SDavid du Colombier } 1913e12c5d1SDavid du Colombier 1923e12c5d1SDavid du Colombier void 1933e12c5d1SDavid du Colombier catcher(void *junk, char *msg) 1943e12c5d1SDavid du Colombier { 1953e12c5d1SDavid du Colombier USED(junk); 1963e12c5d1SDavid du Colombier 1973e12c5d1SDavid du Colombier if(strncmp(msg, "exit", 4) == 0) 1983e12c5d1SDavid du Colombier noted(NDFLT); 1993e12c5d1SDavid du Colombier noted(NCONT); 2003e12c5d1SDavid du Colombier } 2013e12c5d1SDavid du Colombier 2023e12c5d1SDavid du Colombier void 2033e12c5d1SDavid du Colombier sendfile(int fd, char *name, char *mode) 2043e12c5d1SDavid du Colombier { 2053e12c5d1SDavid du Colombier int file; 2063e12c5d1SDavid du Colombier uchar buf[Segsize+4]; 2073e12c5d1SDavid du Colombier uchar ack[1024]; 2089a747e4fSDavid du Colombier char errbuf[Maxerr]; 2093e12c5d1SDavid du Colombier int ackblock, block, ret; 2103e12c5d1SDavid du Colombier int rexmit, n, al, txtry, rxl; 2113e12c5d1SDavid du Colombier short op; 2123e12c5d1SDavid du Colombier 2133e12c5d1SDavid du Colombier syslog(dbg, flog, "send file '%s' %s to %s", name, mode, raddr); 2143e12c5d1SDavid du Colombier name = sunkernel(name); 2153e12c5d1SDavid du Colombier if(name == 0){ 2163e12c5d1SDavid du Colombier nak(fd, 0, "not in our database"); 2173e12c5d1SDavid du Colombier return; 2183e12c5d1SDavid du Colombier } 2193e12c5d1SDavid du Colombier 2203e12c5d1SDavid du Colombier notify(catcher); 2213e12c5d1SDavid du Colombier 2223e12c5d1SDavid du Colombier file = open(name, OREAD); 2233e12c5d1SDavid du Colombier if(file < 0) { 2249a747e4fSDavid du Colombier errstr(errbuf, sizeof errbuf); 2253e12c5d1SDavid du Colombier nak(fd, 0, errbuf); 2263e12c5d1SDavid du Colombier return; 2273e12c5d1SDavid du Colombier } 2283e12c5d1SDavid du Colombier block = 0; 2293e12c5d1SDavid du Colombier rexmit = 0; 2303e12c5d1SDavid du Colombier n = 0; 231219b2ee8SDavid du Colombier for(txtry = 0; txtry < 5;) { 2323e12c5d1SDavid du Colombier if(rexmit == 0) { 2333e12c5d1SDavid du Colombier block++; 2343e12c5d1SDavid du Colombier buf[0] = 0; 2353e12c5d1SDavid du Colombier buf[1] = Tftp_DATA; 2363e12c5d1SDavid du Colombier buf[2] = block>>8; 2373e12c5d1SDavid du Colombier buf[3] = block; 2383e12c5d1SDavid du Colombier n = read(file, buf+4, Segsize); 2393e12c5d1SDavid du Colombier if(n < 0) { 2409a747e4fSDavid du Colombier errstr(errbuf, sizeof errbuf); 2413e12c5d1SDavid du Colombier nak(fd, 0, errbuf); 2423e12c5d1SDavid du Colombier return; 2433e12c5d1SDavid du Colombier } 244219b2ee8SDavid du Colombier txtry = 0; 2453e12c5d1SDavid du Colombier } 2467dd7cddfSDavid du Colombier else { 247162f803dSDavid du Colombier syslog(dbg, flog, "rexmit %d %s:%d to %s", 248162f803dSDavid du Colombier 4+n, name, block, raddr); 2493e12c5d1SDavid du Colombier txtry++; 2507dd7cddfSDavid du Colombier } 2517dd7cddfSDavid du Colombier 2523e12c5d1SDavid du Colombier ret = write(fd, buf, 4+n); 2537ec5746aSDavid du Colombier if(ret < 4+n) 2547dd7cddfSDavid du Colombier sysfatal("tftpd: network write error: %r"); 2553e12c5d1SDavid du Colombier 2563e12c5d1SDavid du Colombier for(rxl = 0; rxl < 10; rxl++) { 2573e12c5d1SDavid du Colombier rexmit = 0; 258*64eb6bc1SDavid du Colombier alarm(1000); 2593e12c5d1SDavid du Colombier al = read(fd, ack, sizeof(ack)); 2603e12c5d1SDavid du Colombier alarm(0); 2613e12c5d1SDavid du Colombier if(al < 0) { 2623e12c5d1SDavid du Colombier rexmit = 1; 2633e12c5d1SDavid du Colombier break; 2643e12c5d1SDavid du Colombier } 2653e12c5d1SDavid du Colombier op = ack[0]<<8|ack[1]; 2663e12c5d1SDavid du Colombier if(op == Tftp_ERROR) 2673e12c5d1SDavid du Colombier goto error; 2683e12c5d1SDavid du Colombier ackblock = ack[2]<<8|ack[3]; 2693e12c5d1SDavid du Colombier if(ackblock == block) 2703e12c5d1SDavid du Colombier break; 2713e12c5d1SDavid du Colombier if(ackblock == 0xffff) { 2723e12c5d1SDavid du Colombier rexmit = 1; 2733e12c5d1SDavid du Colombier break; 2743e12c5d1SDavid du Colombier } 2753e12c5d1SDavid du Colombier } 2763e12c5d1SDavid du Colombier if(ret != Segsize+4 && rexmit == 0) 2773e12c5d1SDavid du Colombier break; 2783e12c5d1SDavid du Colombier } 2793e12c5d1SDavid du Colombier error: 2803e12c5d1SDavid du Colombier close(fd); 2813e12c5d1SDavid du Colombier close(file); 2823e12c5d1SDavid du Colombier } 2833e12c5d1SDavid du Colombier 284162f803dSDavid du Colombier enum { Hdrsize = 2 * sizeof(short), }; /* op, block */ 285162f803dSDavid du Colombier 2863e12c5d1SDavid du Colombier void 2873e12c5d1SDavid du Colombier recvfile(int fd, char *name, char *mode) 2883e12c5d1SDavid du Colombier { 2893e12c5d1SDavid du Colombier ushort op, block, inblock; 2903e12c5d1SDavid du Colombier uchar buf[Segsize+8]; 2919a747e4fSDavid du Colombier char errbuf[Maxerr]; 2923e12c5d1SDavid du Colombier int n, ret, file; 2933e12c5d1SDavid du Colombier 2943e12c5d1SDavid du Colombier syslog(dbg, flog, "receive file '%s' %s from %s", name, mode, raddr); 2953e12c5d1SDavid du Colombier 2963e12c5d1SDavid du Colombier file = create(name, OWRITE, 0666); 2973e12c5d1SDavid du Colombier if(file < 0) { 2989a747e4fSDavid du Colombier errstr(errbuf, sizeof errbuf); 2993e12c5d1SDavid du Colombier nak(fd, 0, errbuf); 300162f803dSDavid du Colombier syslog(dbg, flog, "can't create %s: %r", name); 3013e12c5d1SDavid du Colombier return; 3023e12c5d1SDavid du Colombier } 3033e12c5d1SDavid du Colombier 3043e12c5d1SDavid du Colombier block = 0; 3053e12c5d1SDavid du Colombier ack(fd, block); 3063e12c5d1SDavid du Colombier block++; 3073e12c5d1SDavid du Colombier 3083e12c5d1SDavid du Colombier for (;;) { 3093e12c5d1SDavid du Colombier alarm(15000); 3103e12c5d1SDavid du Colombier n = read(fd, buf, sizeof(buf)); 3113e12c5d1SDavid du Colombier alarm(0); 312162f803dSDavid du Colombier if(n < 0) { 313162f803dSDavid du Colombier syslog(dbg, flog, "tftpd: network error reading %s: %r", 314162f803dSDavid du Colombier name); 3153e12c5d1SDavid du Colombier goto error; 316162f803dSDavid du Colombier } 317162f803dSDavid du Colombier if(n <= Hdrsize) { 318162f803dSDavid du Colombier syslog(dbg, flog, 319162f803dSDavid du Colombier "tftpd: short read from network, reading %s", 320162f803dSDavid du Colombier name); 321162f803dSDavid du Colombier goto error; 322162f803dSDavid du Colombier } 3233e12c5d1SDavid du Colombier op = buf[0]<<8|buf[1]; 324162f803dSDavid du Colombier if(op == Tftp_ERROR) { 325162f803dSDavid du Colombier syslog(dbg, flog, "tftpd: tftp error reading %s", name); 3263e12c5d1SDavid du Colombier goto error; 327162f803dSDavid du Colombier } 3283e12c5d1SDavid du Colombier 329162f803dSDavid du Colombier n -= Hdrsize; 3303e12c5d1SDavid du Colombier inblock = buf[2]<<8|buf[3]; 3313e12c5d1SDavid du Colombier if(op == Tftp_DATA) { 3323e12c5d1SDavid du Colombier if(inblock == block) { 333162f803dSDavid du Colombier ret = write(file, buf+Hdrsize, n); 334162f803dSDavid du Colombier if(ret != n) { 3359a747e4fSDavid du Colombier errstr(errbuf, sizeof errbuf); 3363e12c5d1SDavid du Colombier nak(fd, 0, errbuf); 337162f803dSDavid du Colombier syslog(dbg, flog, 338162f803dSDavid du Colombier "tftpd: error writing %s: %s", 339162f803dSDavid du Colombier name, errbuf); 3403e12c5d1SDavid du Colombier goto error; 3413e12c5d1SDavid du Colombier } 3423e12c5d1SDavid du Colombier ack(fd, block); 3433e12c5d1SDavid du Colombier block++; 34478307a5fSDavid du Colombier } else 34578307a5fSDavid du Colombier ack(fd, 0xffff); /* tell him to resend */ 3463e12c5d1SDavid du Colombier } 3473e12c5d1SDavid du Colombier } 3483e12c5d1SDavid du Colombier error: 3493e12c5d1SDavid du Colombier close(file); 3503e12c5d1SDavid du Colombier } 3513e12c5d1SDavid du Colombier 3523e12c5d1SDavid du Colombier void 3533e12c5d1SDavid du Colombier ack(int fd, ushort block) 3543e12c5d1SDavid du Colombier { 3553e12c5d1SDavid du Colombier uchar ack[4]; 3563e12c5d1SDavid du Colombier int n; 3573e12c5d1SDavid du Colombier 3583e12c5d1SDavid du Colombier ack[0] = 0; 3593e12c5d1SDavid du Colombier ack[1] = Tftp_ACK; 3603e12c5d1SDavid du Colombier ack[2] = block>>8; 3613e12c5d1SDavid du Colombier ack[3] = block; 3623e12c5d1SDavid du Colombier 3633e12c5d1SDavid du Colombier n = write(fd, ack, 4); 364162f803dSDavid du Colombier if(n < 4) 3657dd7cddfSDavid du Colombier sysfatal("network write: %r"); 3663e12c5d1SDavid du Colombier } 3673e12c5d1SDavid du Colombier 3683e12c5d1SDavid du Colombier void 3693e12c5d1SDavid du Colombier nak(int fd, int code, char *msg) 3703e12c5d1SDavid du Colombier { 3713e12c5d1SDavid du Colombier char buf[128]; 3723e12c5d1SDavid du Colombier int n; 3733e12c5d1SDavid du Colombier 3743e12c5d1SDavid du Colombier buf[0] = 0; 3753e12c5d1SDavid du Colombier buf[1] = Tftp_ERROR; 3763e12c5d1SDavid du Colombier buf[2] = 0; 3773e12c5d1SDavid du Colombier buf[3] = code; 3783e12c5d1SDavid du Colombier strcpy(buf+4, msg); 3793e12c5d1SDavid du Colombier n = strlen(msg) + 4 + 1; 3803e12c5d1SDavid du Colombier n = write(fd, buf, n); 3813e12c5d1SDavid du Colombier if(n < 0) 3827dd7cddfSDavid du Colombier sysfatal("write nak: %r"); 3833e12c5d1SDavid du Colombier } 3843e12c5d1SDavid du Colombier 3853e12c5d1SDavid du Colombier void 3863e12c5d1SDavid du Colombier setuser(void) 3873e12c5d1SDavid du Colombier { 388c0eadb1cSDavid du Colombier int fd; 3893e12c5d1SDavid du Colombier 390c0eadb1cSDavid du Colombier fd = open("#c/user", OWRITE); 391c0eadb1cSDavid du Colombier if(fd < 0 || write(fd, "none", strlen("none")) < 0) 392c0eadb1cSDavid du Colombier sysfatal("can't become none: %r"); 393c0eadb1cSDavid du Colombier close(fd); 394c0eadb1cSDavid du Colombier if(newns("none", nil) < 0) 395c0eadb1cSDavid du Colombier sysfatal("can't build namespace: %r"); 3963e12c5d1SDavid du Colombier } 3973e12c5d1SDavid du Colombier 3987dd7cddfSDavid du Colombier char* 399da51d93aSDavid du Colombier lookup(char *sattr, char *sval, char *tattr, char *tval, int len) 4007dd7cddfSDavid du Colombier { 4017dd7cddfSDavid du Colombier static Ndb *db; 4027dd7cddfSDavid du Colombier char *attrs[1]; 4037dd7cddfSDavid du Colombier Ndbtuple *t; 4047dd7cddfSDavid du Colombier 4057dd7cddfSDavid du Colombier if(db == nil) 4067dd7cddfSDavid du Colombier db = ndbopen(0); 4077dd7cddfSDavid du Colombier if(db == nil) 4087dd7cddfSDavid du Colombier return nil; 4097dd7cddfSDavid du Colombier 4107dd7cddfSDavid du Colombier if(sattr == nil) 4117dd7cddfSDavid du Colombier sattr = ipattr(sval); 4127dd7cddfSDavid du Colombier 4137dd7cddfSDavid du Colombier attrs[0] = tattr; 4147dd7cddfSDavid du Colombier t = ndbipinfo(db, sattr, sval, attrs, 1); 4157dd7cddfSDavid du Colombier if(t == nil) 4167dd7cddfSDavid du Colombier return nil; 417da51d93aSDavid du Colombier strncpy(tval, t->val, len); 418da51d93aSDavid du Colombier tval[len-1] = 0; 4197dd7cddfSDavid du Colombier ndbfree(t); 4207dd7cddfSDavid du Colombier return tval; 4217dd7cddfSDavid du Colombier } 4227dd7cddfSDavid du Colombier 4233e12c5d1SDavid du Colombier /* 4243e12c5d1SDavid du Colombier * for sun kernel boots, replace the requested file name with 4253e12c5d1SDavid du Colombier * a one from our database. If the database doesn't specify a file, 4263e12c5d1SDavid du Colombier * don't answer. 4273e12c5d1SDavid du Colombier */ 4283e12c5d1SDavid du Colombier char* 4293e12c5d1SDavid du Colombier sunkernel(char *name) 4303e12c5d1SDavid du Colombier { 4313e12c5d1SDavid du Colombier ulong addr; 4327dd7cddfSDavid du Colombier uchar v4[IPv4addrlen]; 4337dd7cddfSDavid du Colombier uchar v6[IPaddrlen]; 434da51d93aSDavid du Colombier char buf[256]; 435da51d93aSDavid du Colombier char ipbuf[128]; 43627e10919SDavid du Colombier char *suffix; 4373e12c5d1SDavid du Colombier 43827e10919SDavid du Colombier addr = strtoul(name, &suffix, 16); 43927e10919SDavid du Colombier if(suffix-name != 8 || (strcmp(suffix, "") != 0 && strcmp(suffix, ".SUN") != 0)) 4403e12c5d1SDavid du Colombier return name; 4413e12c5d1SDavid du Colombier 4427dd7cddfSDavid du Colombier v4[0] = addr>>24; 4437dd7cddfSDavid du Colombier v4[1] = addr>>16; 4447dd7cddfSDavid du Colombier v4[2] = addr>>8; 4457dd7cddfSDavid du Colombier v4[3] = addr; 4467dd7cddfSDavid du Colombier v4tov6(v6, v4); 4477dd7cddfSDavid du Colombier sprint(ipbuf, "%I", v6); 448da51d93aSDavid du Colombier return lookup("ip", ipbuf, "bootf", buf, sizeof buf); 4497dd7cddfSDavid du Colombier } 4507dd7cddfSDavid du Colombier 4517dd7cddfSDavid du Colombier void 4527dd7cddfSDavid du Colombier remoteaddr(char *dir, char *raddr, int len) 4537dd7cddfSDavid du Colombier { 4547dd7cddfSDavid du Colombier char buf[64]; 4557dd7cddfSDavid du Colombier int fd, n; 4567dd7cddfSDavid du Colombier 4577dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/remote", dir); 4587dd7cddfSDavid du Colombier fd = open(buf, OREAD); 4597dd7cddfSDavid du Colombier if(fd < 0){ 4607dd7cddfSDavid du Colombier snprint(raddr, sizeof(raddr), "unknown"); 4617dd7cddfSDavid du Colombier return; 4627dd7cddfSDavid du Colombier } 4637dd7cddfSDavid du Colombier n = read(fd, raddr, len-1); 4647dd7cddfSDavid du Colombier close(fd); 4657dd7cddfSDavid du Colombier if(n <= 0){ 4667dd7cddfSDavid du Colombier snprint(raddr, sizeof(raddr), "unknown"); 4677dd7cddfSDavid du Colombier return; 4687dd7cddfSDavid du Colombier } 4697dd7cddfSDavid du Colombier if(n > 0) 4707dd7cddfSDavid du Colombier n--; 4717dd7cddfSDavid du Colombier raddr[n] = 0; 4723e12c5d1SDavid du Colombier } 473