int connect(char *system, char *tree, int oldserver) { char buf[ERRMAX], dir[128], *na; int fd, n; char *authp; na = netmkaddr(system, 0, "exportfs"); procsetname("dial %s", na); if((fd = dial(na, 0, dir, 0)) < 0) sysfatal("can't dial %s: %r", system); if(doauth){ if(oldserver) authp = "p9sk2"; else authp = "p9any"; procsetname("auth_proxy auth_getkey proto=%q role=client %s", authp, keyspec); ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", authp, keyspec); if(ai == nil) sysfatal("%r: %s", system); } if(!skiptree){ procsetname("writing tree name %s", tree); n = write(fd, tree, strlen(tree)); if(n < 0) sysfatal("can't write tree: %r"); strcpy(buf, "can't read tree"); procsetname("awaiting OK for %s", tree); n = read(fd, buf, sizeof buf - 1); if(n!=2 || buf[0]!='O' || buf[1]!='K'){ if (timedout) sysfatal("timed out connecting to %s", na); buf[sizeof buf - 1] = '\0'; sysfatal("bad remote tree: %s", buf); } } if(oldserver) return old9p(fd); return fd; }
/* * process to notify other servers of changes * (also reads in new databases) */ void notifyproc(void) { Request req; switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ case -1: return; case 0: break; default: return; } procsetname("notify slaves"); memset(&req, 0, sizeof req); req.isslave = 1; /* don't fork off subprocesses */ for(;;){ getactivity(&req, 0); notify_areas(owned, &req); putactivity(0); sleep(60*1000); } }
int passive(void) { int fd; /* * Ignore doauth==0 on purpose. Is it useful here? */ procsetname("auth_proxy auth_getkey proto=p9any role=server"); ai = auth_proxy(0, auth_getkey, "proto=p9any role=server"); if(ai == nil) sysfatal("auth_proxy: %r"); if(auth_chuid(ai, nil) < 0) sysfatal("auth_chuid: %r"); putenv("service", "import"); fd = dup(0, -1); close(0); open("/dev/null", ORDWR); close(1); open("/dev/null", ORDWR); return fd; }
/* * plan9 authentication followed by rc4 encryption */ static int p9auth(int fd) { uchar key[16]; uchar digest[SHA1dlen]; char fromclientsecret[21]; char fromserversecret[21]; int i; AuthInfo *ai; procsetname("%s: auth_proxy proto=%q role=client %s", origargs, p9authproto, keyspec); ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", p9authproto, keyspec); if(ai == nil) return -1; memmove(key+4, ai->secret, ai->nsecret); if(ealgs == nil) return fd; /* exchange random numbers */ srand(truerand()); for(i = 0; i < 4; i++) key[i] = rand(); procsetname("writing p9 key"); if(write(fd, key, 4) != 4) return -1; procsetname("reading p9 key"); if(readn(fd, key+12, 4) != 4) return -1; /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); mksecret(fromclientsecret, digest); mksecret(fromserversecret, digest+10); /* set up encryption */ procsetname("pushssl"); i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); if(i < 0) werrstr("can't establish ssl connection: %r"); return i; }
void newproc(void (*f)(void *), void *arg, char *text) { int kid = rfork(RFPROC|RFMEM|RFNOWAIT); if (kid < 0) sysfatal("can't fork: %r"); if (kid == 0) { procsetname("%s", text); (*f)(arg); exits("child returned"); } }
char* rexcall(int *fd, char *host, char *service) { char *na; char dir[MaxStr]; char err[ERRMAX]; char msg[MaxStr]; int n; na = netmkaddr(host, 0, service); procsetname("dialing %s", na); if((*fd = dial(na, 0, dir, 0)) < 0) return "can't dial"; /* negotiate authentication mechanism */ if(ealgs != nil) snprint(msg, sizeof(msg), "%s %s", am->name, ealgs); else snprint(msg, sizeof(msg), "%s", am->name); procsetname("writing %s", msg); writestr(*fd, msg, negstr, 0); procsetname("awaiting auth method"); n = readstr(*fd, err, sizeof err); if(n < 0) return negstr; if(*err){ werrstr(err); return negstr; } /* authenticate */ procsetname("%s: auth via %s", origargs, am->name); *fd = (*am->cf)(*fd); if(*fd < 0) return "can't authenticate"; return 0; }
void testrand(void *arg) { Chan *reply; size_t i; int j; ulong r; procsetname("testrand"); reply = arg; for(i = 0; i < alen(tests); i++){ procsrand(tests[i].seed); for(j = 0; j < Nrand; j++){ r = procrand(); if(r != tests[i].expect[j]){ printf("fail: (seed %lu, j %d) -- expected %lu got %lu\n", tests[i].seed, j, tests[i].expect[j], r); chansend(reply, &(int){1}); } }
void mountinit(char *service, char *mntpt) { int f; int p[2]; char buf[32]; if(pipe(p) < 0) abort(); /* "pipe failed" */; switch(rfork(RFFDG|RFPROC)){ case 0: /* child: hang around and (re)start main proc */ close(p[1]); procsetname("%s restarter", mntpt); mfd[0] = mfd[1] = p[0]; break; case -1: abort(); /* "fork failed\n" */; default: /* parent: make /srv/dns, mount it, exit */ close(p[0]); /* * make a /srv/dns */ f = create(service, 1, 0666); if(f < 0) abort(); /* service */; snprint(buf, sizeof buf, "%d", p[1]); if(write(f, buf, strlen(buf)) != strlen(buf)) abort(); /* "write %s", service */; close(f); /* * put ourselves into the file system * it's too soon; we need 9p service running. */ // if(mount(p[1], -1, mntpt, MAFTER, "") < 0) // dnslog("dns mount -a on %s failed: %r", mntpt); close(p[1]); _exits(0); } }
int old9p(int fd) { int p[2]; procsetname("old9p"); if(pipe(p) < 0) sysfatal("pipe: %r"); switch(rfork(RFPROC|RFMEM|RFFDG|RFNAMEG)) { case -1: sysfatal("rfork srvold9p: %r"); case 0: if(fd != 1){ dup(fd, 1); close(fd); } if(p[0] != 0){ dup(p[0], 0); close(p[0]); } close(p[1]); if(0){ fd = open("/sys/log/cpu", OWRITE); if(fd != 2){ dup(fd, 2); close(fd); } execl("/bin/srvold9p", "srvold9p", "-ds", nil); } else execl("/bin/srvold9p", "srvold9p", "-s", nil); sysfatal("exec srvold9p: %r"); default: close(fd); close(p[0]); } return p[1]; }
void main(int argc, char *argv[]) { int len, rcode; char tname[32]; char *err, *ext = ""; unsigned char buf[64*1024], callip[IPaddrlen]; DNSmsg reqmsg, repmsg; Request req; alarm(2*60*1000); cfg.cachedb = 1; ARGBEGIN{ case 'd': debug++; break; case 'f': dbfile = EARGF(usage()); break; case 'r': cfg.resolver = 1; break; case 'R': norecursion = 1; break; case 'x': ext = EARGF(usage()); break; default: usage(); break; }ARGEND if(debug < 2) debug = 0; if(argc > 0) getcaller(argv[0]); cfg.inside = 1; dninit(); snprint(mntpt, sizeof mntpt, "/net%s", ext); if(myipaddr(ipaddr, mntpt) < 0) sysfatal("can't read my ip address"); dnslog("dnstcp call from %s to %I", caller, ipaddr); memset(callip, 0, sizeof callip); parseip(callip, caller); db2cache(1); memset(&req, 0, sizeof req); setjmp(req.mret); req.isslave = 0; procsetname("main loop"); /* loop on requests */ for(;; putactivity(0)){ now = time(nil); memset(&repmsg, 0, sizeof repmsg); len = readmsg(0, buf, sizeof buf); if(len <= 0) break; getactivity(&req, 0); req.aborttime = timems() + S2MS(15*Min); rcode = 0; memset(&reqmsg, 0, sizeof reqmsg); err = convM2DNS(buf, len, &reqmsg, &rcode); if(err){ dnslog("server: input error: %s from %s", err, caller); free(err); break; } if (rcode == 0) { if(reqmsg.qdcount < 1){ dnslog("server: no questions from %s", caller); break; } else if(reqmsg.flags & Fresp){ dnslog("server: reply not request from %s", caller); break; } else if((reqmsg.flags & Omask) != Oquery){ dnslog("server: op %d from %s", reqmsg.flags & Omask, caller); break; } } if(debug) dnslog("[%d] %d: serve (%s) %d %s %s", getpid(), req.id, caller, reqmsg.id, reqmsg.qd->owner->name, rrname(reqmsg.qd->type, tname, sizeof tname)); /* loop through each question */ while(reqmsg.qd) if(reqmsg.qd->type == Taxfr) dnzone(&reqmsg, &repmsg, &req); else { dnserver(&reqmsg, &repmsg, &req, callip, rcode); reply(1, &repmsg, &req); rrfreelist(repmsg.qd); rrfreelist(repmsg.an); rrfreelist(repmsg.ns); rrfreelist(repmsg.ar); } rrfreelist(reqmsg.qd); /* qd will be nil */ rrfreelist(reqmsg.an); rrfreelist(reqmsg.ns); rrfreelist(reqmsg.ar); if(req.isslave){ putactivity(0); _exits(0); } } refreshmain(mntpt); }
void main(int argc, char **argv) { int i, nets = 0; char *ann; rfork(RFNOTEG); formatinit(); machinit(); conf.confdev = "n"; /* Devnone */ ARGBEGIN{ case 'a': /* announce on this net */ ann = EARGF(usage()); if (nets >= Maxnets) { fprint(2, "%s: too many networks to announce: %s\n", argv0, ann); exits("too many nets"); } annstrs[nets++] = ann; break; case 'c': /* use new, faster cache layout */ oldcachefmt = 0; break; case 'f': /* enter configuration mode first */ conf.configfirst++; break; case 'm': /* name device-map file */ conf.devmap = EARGF(usage()); break; default: usage(); break; }ARGEND if (argc != 1) usage(); conf.confdev = argv[0]; /* config string for dev holding full config */ Binit(&bin, 0, OREAD); confinit(); print("\nPlan 9 %d-bit cached-worm file server with %d-deep indir blks\n", sizeof(Off)*8 - 1, NIBLOCK); printsizes(); qlock(&reflock); qunlock(&reflock); serveq = newqueue(1000, "9P service"); /* tunable */ raheadq = newqueue(1000, "readahead"); /* tunable */ mbinit(); netinit(); scsiinit(); files = malloc(conf.nfile * sizeof *files); for(i=0; i < conf.nfile; i++) { qlock(&files[i]); qunlock(&files[i]); } wpaths = malloc(conf.nwpath * sizeof(*wpaths)); uid = malloc(conf.nuid * sizeof(*uid)); gidspace = malloc(conf.gidspace * sizeof(*gidspace)); authinit(); print("iobufinit\n"); iobufinit(); arginit(); boottime = time(nil); print("sysinit\n"); sysinit(); /* * Ethernet i/o processes */ netstart(); /* * read ahead processes */ newproc(rahead, 0, "rah"); /* * server processes */ for(i=0; i < conf.nserve; i++) newproc(serve, 0, "srv"); /* * worm "dump" copy process */ newproc(wormcopy, 0, "wcp"); /* * processes to read the console */ consserve(); /* * "sync" copy process * this doesn't return. */ procsetname("scp"); synccopy(); }
/* * a process to act as a dns server for outside reqeusts */ void dnudpserver(char *mntpt) { volatile int fd, len, op, rcode; char *volatile err; volatile char tname[32]; volatile uchar buf[Udphdrsize + Maxudp + 1024]; volatile DNSmsg reqmsg, repmsg; Inprogress *volatile p; volatile Request req; Udphdr *volatile uh; /* * fork sharing text, data, and bss with parent. * stay in the same note group. */ switch(rfork(RFPROC|RFMEM|RFNOWAIT)){ case -1: break; case 0: break; default: return; } fd = -1; restart: procsetname("udp server announcing"); if(fd >= 0) close(fd); while((fd = udpannounce(mntpt)) < 0) sleep(5000); // procsetname("udp server"); memset(&req, 0, sizeof req); if(setjmp(req.mret)) putactivity(0); req.isslave = 0; req.id = 0; req.aborttime = 0; /* loop on requests */ for(;; putactivity(0)){ procsetname("served %d udp; %d alarms", stats.qrecvdudp, stats.alarms); memset(&repmsg, 0, sizeof repmsg); memset(&reqmsg, 0, sizeof reqmsg); alarm(60*1000); len = read(fd, buf, sizeof buf); alarm(0); if(len <= Udphdrsize) goto restart; redistrib(buf, len); uh = (Udphdr*)buf; len -= Udphdrsize; // dnslog("read received UDP from %I to %I", // ((Udphdr*)buf)->raddr, ((Udphdr*)buf)->laddr); getactivity(&req, 0); req.aborttime = timems() + Maxreqtm; // req.from = smprint("%I", ((Udphdr*)buf)->raddr); req.from = smprint("%I", buf); rcode = 0; stats.qrecvdudp++; err = convM2DNS(&buf[Udphdrsize], len, &reqmsg, &rcode); if(err){ /* first bytes in buf are source IP addr */ dnslog("server: input error: %s from %I", err, buf); free(err); goto freereq; } if (rcode == 0) if(reqmsg.qdcount < 1){ dnslog("server: no questions from %I", buf); goto freereq; } else if(reqmsg.flags & Fresp){ dnslog("server: reply not request from %I", buf); goto freereq; } op = reqmsg.flags & Omask; if(op != Oquery && op != Onotify){ dnslog("server: op %d from %I", reqmsg.flags & Omask, buf); goto freereq; } if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))) dnslog("%d: serve (%I/%d) %d %s %s", req.id, buf, uh->rport[0]<<8 | uh->rport[1], reqmsg.id, reqmsg.qd->owner->name, rrname(reqmsg.qd->type, tname, sizeof tname)); p = clientrxmit(&reqmsg, buf); if(p == nil){ if(debug) dnslog("%d: duplicate", req.id); goto freereq; } if (Logqueries) { RR *rr; for (rr = reqmsg.qd; rr; rr = rr->next) syslog(0, "dnsq", "id %d: (%I/%d) %d %s %s", req.id, buf, uh->rport[0]<<8 | uh->rport[1], reqmsg.id, reqmsg.qd->owner->name, rrname(reqmsg.qd->type, tname, sizeof tname)); } /* loop through each question */ while(reqmsg.qd){ memset(&repmsg, 0, sizeof repmsg); switch(op){ case Oquery: dnserver(&reqmsg, &repmsg, &req, buf, rcode); break; case Onotify: dnnotify(&reqmsg, &repmsg, &req); break; } /* send reply on fd to address in buf's udp hdr */ reply(fd, buf, &repmsg, &req); freeanswers(&repmsg); } p->inuse = 0; freereq: free(req.from); req.from = nil; freeanswers(&reqmsg); if(req.isslave){ putactivity(0); _exits(0); } } }
void main(int argc, char **argv) { char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err; int ac, fd, ms, data; char *av[10]; quotefmtinstall(); origargs = procgetname(); /* see if we should use a larger message size */ fd = open("/dev/draw", OREAD); if(fd > 0){ ms = iounit(fd); if(msgsize < ms+IOHDRSZ) msgsize = ms+IOHDRSZ; close(fd); } user = getuser(); if(user == nil) fatal(1, "can't read user name"); ARGBEGIN{ case 'a': p = EARGF(usage()); if(setam(p) < 0) fatal(0, "unknown auth method %s", p); break; case 'e': ealgs = EARGF(usage()); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; case 'd': dbg++; break; case 'f': /* ignored but accepted for compatibility */ break; case 'R': /* From listen */ remoteside(); break; case 'h': system = EARGF(usage()); break; case 'c': cflag++; cmd[0] = '!'; cmd[1] = '\0'; while(p = ARGF()) { strcat(cmd, " "); strcat(cmd, p); } break; case 'k': keyspec = smprint("%s %s", keyspec, EARGF(usage())); break; case 'P': patternfile = EARGF(usage()); break; case 'u': user = EARGF(usage()); keyspec = smprint("%s user=%s", keyspec, user); break; default: usage(); }ARGEND; if(argc != 0) usage(); if(system == nil) { p = getenv("cpu"); if(p == 0) fatal(0, "set $cpu"); system = p; } if(err = rexcall(&data, system, srvname)) fatal(1, "%s: %s", err, system); procsetname("%s", origargs); /* Tell the remote side the command to execute and where our working directory is */ if(cflag) writestr(data, cmd, "command", 0); if(getwd(dat, sizeof(dat)) == 0) writestr(data, "NO", "dir", 0); else writestr(data, dat, "dir", 0); /* start up a process to pass along notes */ lclnoteproc(data); /* * Wait for the other end to execute and start our file service * of /mnt/term */ if(readstr(data, buf, sizeof(buf)) < 0) fatal(1, "waiting for FS: %r"); if(strncmp("FS", buf, 2) != 0) { print("remote cpu: %s", buf); exits(buf); } /* Begin serving the gnot namespace */ close(0); dup(data, 0); close(data); sprint(buf, "%d", msgsize); ac = 0; av[ac++] = exportfs; av[ac++] = "-m"; av[ac++] = buf; if(dbg) av[ac++] = "-d"; if(patternfile != nil){ av[ac++] = "-P"; av[ac++] = patternfile; } av[ac] = nil; exec(exportfs, av); fatal(1, "starting exportfs"); }
void main(int argc, char **argv) { char *mntpt, *srvpost, srvfile[64]; int backwards = 0, fd, mntflags, oldserver; quotefmtinstall(); srvpost = nil; oldserver = 0; mntflags = MREPL; ARGBEGIN{ case 'A': doauth = 0; break; case 'a': mntflags = MAFTER; break; case 'b': mntflags = MBEFORE; break; case 'c': mntflags |= MCREATE; break; case 'C': mntflags |= MCACHE; break; case 'd': debug++; break; case 'f': /* ignored but allowed for compatibility */ break; case 'O': case 'o': oldserver = 1; break; case 'E': if ((encproto = lookup(EARGF(usage()), encprotos)) < 0) usage(); break; case 'e': ealgs = EARGF(usage()); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; case 'k': keyspec = EARGF(usage()); break; case 'p': filterp = aan; break; case 'n': anstring = EARGF(usage()); break; case 's': srvpost = EARGF(usage()); break; case 'B': backwards = 1; break; case 'z': skiptree = 1; break; default: usage(); }ARGEND; mntpt = 0; /* to shut up compiler */ if(backwards){ switch(argc) { default: mntpt = argv[0]; break; case 0: usage(); } } else { switch(argc) { case 2: mntpt = argv[1]; break; case 3: mntpt = argv[2]; break; default: usage(); } } if (encproto == Enctls) sysfatal("%s: tls has not yet been implemented", argv[0]); notify(catcher); alarm(60*1000); if (backwards) fd = passive(); else fd = connect(argv[0], argv[1], oldserver); if (!oldserver) fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter", encprotos[encproto]); if (encproto != Encnone && ealgs && ai) { uchar key[16], digest[SHA1dlen]; char fromclientsecret[21]; char fromserversecret[21]; int i; assert(ai->nsecret <= sizeof(key)-4); memmove(key+4, ai->secret, ai->nsecret); /* exchange random numbers */ srand(truerand()); for(i = 0; i < 4; i++) key[i] = rand(); if(write(fd, key, 4) != 4) sysfatal("can't write key part: %r"); if(readn(fd, key+12, 4) != 4) sysfatal("can't read key part: %r"); /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); mksecret(fromclientsecret, digest); mksecret(fromserversecret, digest+10); if (filterp) fd = filter(fd, filterp, backwards ? nil : argv[0]); /* set up encryption */ procsetname("pushssl"); fd = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); if(fd < 0) sysfatal("can't establish ssl connection: %r"); } else if (filterp) fd = filter(fd, filterp, backwards ? nil : argv[0]); if(ai) auth_freeAI(ai); if(srvpost){ snprint(srvfile, sizeof(srvfile), "/srv/%s", srvpost); remove(srvfile); post(srvfile, srvpost, fd); } procsetname("mount on %s", mntpt); if(mount(fd, -1, mntpt, mntflags, "") < 0) sysfatal("can't mount %s: %r", argv[1]); alarm(0); if(backwards && argc > 1){ exec(argv[1], &argv[1]); sysfatal("exec: %r"); } exits(0); }
void io(void) { volatile long n; volatile uchar mdata[IOHDRSZ + Maxfdata]; Job *volatile job; Mfile *volatile mf; volatile Request req; memset(&req, 0, sizeof req); /* * a slave process is sometimes forked to wait for replies from other * servers. The master process returns immediately via a longjmp * through 'mret'. */ if(setjmp(req.mret)) putactivity(0); req.isslave = 0; stop = 0; while(!stop){ procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms", stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms); n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n<=0){ dnslog("error reading 9P from %s: %r", mntpt); sleep(2000); /* don't thrash after read error */ return; } stats.qrecvd9prpc++; job = newjob(); if(convM2S(mdata, n, &job->request) != n){ freejob(job); continue; } mf = newfid(job->request.fid, 0); if(debug) dnslog("%F", &job->request); getactivity(&req, 0); req.aborttime = timems() + Maxreqtm; req.from = "9p"; switch(job->request.type){ default: warning("unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: /* &req is handed to dnresolve() */ rwrite(job, mf, &req); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } freejob(job); /* * slave processes die after replying */ if(req.isslave){ putactivity(0); _exits(0); } putactivity(0); } /* kill any udp server, notifier, etc. processes */ postnote(PNGROUP, getpid(), "die"); sleep(1000); }