Add IP-based checking to fossil. [rsc] --rw-rw-r-- M 1428987 jmk sys 4438 Jan 28 11:32 sys/src/cmd/fossil/9.h /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9.h:44,57 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9.h:44,62 MsgF = 4, }; + enum { + ConNoneAllow = 1<<0, + ConNoAuthCheck = 1<<1, + ConNoPermCheck = 1<<2, + ConWstatAllow = 1<<3, + ConIPCheck = 1<<4, + }; struct Con { char* name; uchar* data; /* max, not negotiated */ int isconsole; /* immutable */ - int noauth; /* immutable */ - int noperm; /* immutable */ - int wstatallow; /* immutable */ - + int flags; /* immutable */ + char remote[128]; /* immutable */ VtLock* lock; int state; int fd; /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9.h:191,197 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9.h:196,202 /* * 9proc.c */ - extern Con* conAlloc(int, char*); + extern Con* conAlloc(int, char*, int); extern void conInit(void); extern void msgFlush(Msg*); extern void msgInit(void); [rsc] --rw-rw-r-- M 1428987 rsc sys 3863 Jan 28 11:32 sys/src/cmd/fossil/9auth.c /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9auth.c:84,93 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9auth.c:84,99 * authentication. */ vtRLock(con->alock); - if(!con->isconsole && - (strcmp(fid->uname, unamenone) != 0 || !con->aok)){ + if(con->isconsole){ + /* anything goes */ + }else if((con->flags&ConNoneAllow) || con->aok){ + consPrint("attach %s as %s: allowing as none\n", fsysGetName(fsys), fid->uname); + vtMemFree(fid->uname); + fid->uname = vtStrDup(unamenone); + }else{ vtRUnlock(con->alock); consPrint("attach %s as %s: connection not authenticated, not console\n", fsysGetName(fsys), fid->uname); + vtSetError("cannot attach as none before authentication"); return 0; } vtRUnlock(con->alock); /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9auth.c:94,99 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9auth.c:100,106 if((fid->uid = uidByUname(fid->uname)) == nil){ consPrint("attach %s as %s: unknown uname\n", fsysGetName(fsys), fid->uname); + vtSetError("unknown user"); return 0; } return 1; /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9auth.c:101,106 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9auth.c:108,114 if((afid = fidGet(con, t->afid, 0)) == nil){ consPrint("attach %s as %s: bad afid\n", fsysGetName(fsys), fid->uname); + vtSetError("bad authentication fid"); return 0; } /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9auth.c:111,121 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9auth.c:119,131 if(!(afid->qid.type & QTAUTH)){ consPrint("attach %s as %s: afid not an auth file\n", fsysGetName(fsys), fid->uname); fidPut(afid); + vtSetError("bad authentication fid"); return 0; } if(strcmp(afid->uname, fid->uname) != 0 || afid->fsys != fsys){ consPrint("attach %s as %s: afid is for %s as %s\n", fsysGetName(fsys), fid->uname, fsysGetName(afid->fsys), afid->uname); fidPut(afid); + vtSetError("attach/auth mismatch"); return 0; } /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9auth.c:125,130 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9auth.c:135,141 vtUnlock(afid->alock); consPrint("attach %s as %s: %R\n", fsysGetName(fsys), fid->uname); fidPut(afid); + vtSetError("authentication protocol not finished"); return 0; } } /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9auth.c:134,139 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9auth.c:145,151 if((fid->uid = uidByUname(afid->cuname)) == nil){ consPrint("attach %s as %s: unknown cuname %s\n", fsysGetName(fsys), fid->uname, afid->cuname); fidPut(afid); + vtSetError("unknown user"); return 0; } [rsc] --rw-rw-r-- M 1428987 rsc sys 3024 Jan 28 12:31 sys/src/cmd/fossil/9lstn.c /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:5,10 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:5,11 typedef struct Lstn Lstn; typedef struct Lstn { int afd; + int flags; char* address; char dir[NETPATHLEN]; /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:45,51 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:46,52 Lstn *lstn; int dfd, lfd; char newdir[NETPATHLEN]; - + vtThreadSetName("listen"); lstn = a; /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:54,71 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:55,70 fprint(2, "listen: listen '%s': %r", lstn->dir); break; } - if((dfd = accept(lfd, newdir)) >= 0) - conAlloc(dfd, newdir); + conAlloc(dfd, newdir, lstn->flags); else - fprint(2, "listen: accept '%s': %r", newdir); - close(lfd); + fprint(2, "listen: accept %s: %r\n", newdir); } lstnFree(lstn); } static Lstn* - lstnAlloc(char* address) + lstnAlloc(char* address, int flags) { int afd; Lstn *lstn; /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:89,94 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:88,94 lstn = vtMemAllocZ(sizeof(Lstn)); lstn->afd = afd; lstn->address = vtStrDup(address); + lstn->flags = flags; memmove(lstn->dir, dir, NETPATHLEN); if(lbox.tail != nil){ /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:114,125 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:114,125 static int cmdLstn(int argc, char* argv[]) { - int dflag; + int dflag, flags; Lstn *lstn; - char *usage = "usage: listen [-d] [address]"; + char *usage = "usage: listen [-dIN] [address]"; dflag = 0; - + flags = 0; ARGBEGIN{ default: return cliError(usage); /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:126,131 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:126,137 case 'd': dflag = 1; break; + case 'I': + flags |= ConIPCheck; + break; + case 'N': + flags |= ConNoneAllow; + break; }ARGEND switch(argc){ /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9lstn.c:139,145 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9lstn.c:145,151 break; case 1: if(!dflag){ - if(lstnAlloc(argv[0]) == nil) + if(lstnAlloc(argv[0], flags) == nil) return 0; break; } [rsc] --rw-rw-r-- M 1428987 rsc sys 22935 Jan 28 11:32 sys/src/cmd/fossil/9p.c [diffs elided - too long] [diff -c /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9p.c /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9p.c] [rsc] --rw-rw-r-- M 1428987 rsc sys 15148 Jan 28 12:31 sys/src/cmd/fossil/9proc.c /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9proc.c:63,69 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9proc.c:63,69 } con->state = ConDead; con->aok = 0; - con->noauth = con->noperm = con->wstatallow = 0; + con->flags = 0; con->isconsole = 0; vtLock(cbox.alock); /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9proc.c:502,510 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9proc.c:502,512 } Con* - conAlloc(int fd, char* name) + conAlloc(int fd, char* name, int flags) { Con *con; + char buf[128], *p; + int rfd, n; vtLock(cbox.alock); while(cbox.ahead == nil){ /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9proc.c:558,565 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9proc.c:560,578 con->name = vtStrDup(name); else con->name = vtStrDup("unknown"); - con->aok = 0; - con->noauth = con->noperm = con->wstatallow = 0; + con->remote[0] = 0; + snprint(buf, sizeof buf, "%s/remote", con->name); + if((rfd = open(buf, OREAD)) >= 0){ + n = read(rfd, buf, sizeof buf-1); + close(rfd); + if(n > 0){ + buf[n] = 0; + if((p = strchr(buf, '\n')) != nil) + *p = 0; + strecpy(con->remote, con->remote+sizeof con->remote, buf); + } + } + con->flags = flags; con->isconsole = 0; vtUnlock(cbox.alock); /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9proc.c:692,698 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9proc.c:705,711 cmdWho(int argc, char* argv[]) { char *usage = "usage: who"; - int i; + int i, l1, l2, l; Con *con; Fid *fid, *last; /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/9proc.c:705,712 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/9proc.c:718,733 return cliError(usage); vtRLock(cbox.clock); + l1 = 0; + l2 = 0; for(con=cbox.chead; con; con=con->cnext){ - consPrint("\t%q:", con->name); + if((l = strlen(con->name)) > l1) + l1 = l; + if((l = strlen(con->remote)) > l2) + l2 = l; + } + for(con=cbox.chead; con; con=con->cnext){ + consPrint("\t%-*s %-*s", l1, con->name, l2, con->remote); vtLock(con->fidlock); last = nil; for(i=0; isrvfd, -1); else{ - con = conAlloc(fd[1], srv->mntpnt); + con = conAlloc(fd[1], srv->mntpnt, conflags); if(con == nil) r = 0; - else{ + else r = 1; - con->noauth = Aflag; - con->noperm = Pflag; - con->wstatallow = Wflag; - } } if(r == 0){ close(fd[1]); [rsc] --rw-rw-r-- M 1428987 rsc sys 7985 Jan 28 11:32 sys/src/cmd/fossil/Ccmd.c /n/sourcesdump/2006/0128/plan9/sys/src/cmd/fossil/Ccmd.c:446,452 - /n/sourcesdump/2006/0129/plan9/sys/src/cmd/fossil/Ccmd.c:446,452 if(pipe(cbox.confd) < 0) return 0; - if((cbox.con = conAlloc(cbox.confd[1], "console")) == nil){ + if((cbox.con = conAlloc(cbox.confd[1], "console", 0)) == nil){ close(cbox.confd[0]); close(cbox.confd[1]); cbox.confd[0] = cbox.confd[1] = -1; [rsc] --rw-rw-r-- M 1428987 rsc sys 18276 Jan 28 11:37 sys/man/8/fossilcons /n/sourcesdump/2006/0128/plan9/sys/man/8/fossilcons:33,39 - /n/sourcesdump/2006/0129/plan9/sys/man/8/fossilcons:33,39 .PP .B listen [ - .B -d + .B -INd ] [ .I address /n/sourcesdump/2006/0128/plan9/sys/man/8/fossilcons:400,405 - /n/sourcesdump/2006/0129/plan9/sys/man/8/fossilcons:400,427 .I listen to remove the listener at the given address. + By default, the user + .I none + is only allowed to attach on a connection after + at least one other user has successfully attached. + The + .B -N + flag allows connections from + .I none + at any time. + The + .B -I + flag causes + .I fossil + to check the IP address of incoming connections + against + .BR /mnt/ipok , + rejecting attaches from disallowed addresses. + This mechanism is not intended for general use. + The server + .I sources.cs.bell-labs.com + uses it to comply with U.S. crytography + export regulations. .PP .I Msg prints the maximum internal 9P message queue size [rsc] --rw-rw-r-- M 1428987 rsc sys 3024 Jan 28 12:31 sys/src/cmd/fossil/9lstn.c [rsc] --rw-rw-r-- M 1428987 rsc sys 15148 Jan 28 12:31 sys/src/cmd/fossil/9proc.c