--- /n/sources/plan9/sys/src/cmd/exportfs/exportfs.c Sun Apr 14 16:33:20 2019 +++ /sys/src/cmd/exportfs/exportfs.c Tue Jun 23 00:00:00 2026 @@ -1,5 +1,9 @@ /* * exportfs - Export a plan 9 name space across a network + * + * convert 9P messages from the network into file system calls under the + * mountpoint of this server, and the reverse for results of those system + * calls back to 9P. the inverse of devmnt. */ #include #include @@ -9,6 +13,8 @@ #define Extern #include "exportfs.h" +#define MAXRPC (IOHDRSZ+16*1024) /* see MAXRPC in devmnt; was 8K+IOHDRSZ */ + #define QIDPATH ((1LL<<48)-1) vlong newqid = 0; @@ -46,9 +52,10 @@ int srvfd = -1; int nonone = 1; char *filterp; -char *ealgs = "rc4_256 sha1"; +char *ealgs = "rc4_256 sha1"; /* ssl only */ char *aanfilter = "/bin/aan"; int encproto = Encnone; +char *tlscert = "/sys/lib/tls/cert.pem"; int readonly; static void mksecret(char *, uchar *); @@ -58,6 +65,7 @@ char *netdir = "", *local = "", *remote = ""; int filter(int, char *); +void procsetname(char *fmt, ...); void usage(void) @@ -82,6 +90,28 @@ freenetconninfo(nci); } +static int +pushtlsserver(int fd, char *tlscert) +{ + int efd, certlen; + uchar *cert; + TLSconn conn; + + if (tlscert == nil) + return fd; + memset(&conn, 0, sizeof conn); + cert = readcert(tlscert, &certlen); + if (cert == nil) { + syslog(0, "cpu", "cpu -R: can't read cert %s: %r", tlscert); + return fd; + } + conn.cert = cert; + conn.certlen = certlen; + efd = tlsServer(fd, &conn); + free(conn.cert); + return efd; +} + void main(int argc, char **argv) { @@ -106,71 +136,55 @@ case 'a': doauth = 1; break; - case 'd': dbg++; break; - case 'e': ealgs = EARGF(usage()); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; - case 'f': dbfile = EARGF(usage()); break; - case 'k': keyspec = EARGF(usage()); break; - case 'm': messagesize = strtoul(EARGF(usage()), nil, 0); break; - case 'n': nonone = 0; break; - case 'r': srv = EARGF(usage()); break; - case 's': srv = "/"; break; - case 'A': anstring = EARGF(usage()); break; - case 'B': na = EARGF(usage()); break; - case 'F': /* accepted but ignored, for backwards compatibility */ break; - case 'N': nsfile = EARGF(usage()); break; - case 'P': patternfile = EARGF(usage()); break; - case 'R': readonly = 1; break; - case 'S': if(srvfdfile) usage(); srvfdfile = EARGF(usage()); break; - default: usage(); }ARGEND @@ -178,12 +192,13 @@ if(doauth){ /* - * We use p9any so we don't have to visit this code again, with the - * cost that this code is incompatible with the old world, which - * requires p9sk2. (The two differ in who talks first, so compatibility - * is awkward.) + * We use p9any so we don't have to visit this code again, with + * the cost that this code is incompatible with the old world, + * which requires p9sk2. (The two differ in who talks first, + * so compatibility is awkward.) */ - ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec); + ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", + keyspec); if(ai == nil) fatal("auth_proxy: %r"); if(nonone && strcmp(ai->cuid, "none") == 0) @@ -193,10 +208,8 @@ putenv("service", "exportfs"); } - if(srvfdfile){ - if((srvfd = open(srvfdfile, ORDWR)) < 0) - sysfatal("open '%s': %r", srvfdfile); - } + if(srvfdfile && (srvfd = open(srvfdfile, ORDWR)) < 0) + sysfatal("open '%s': %r", srvfdfile); if(na){ if(srv == nil) @@ -207,7 +220,8 @@ if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0) sysfatal("can't dial %s: %r", na); - ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec); + ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", + keyspec); if(ai == nil) sysfatal("%r: %s", na); @@ -236,7 +250,7 @@ if(messagesize == 0){ messagesize = iounit(netfd); if(messagesize == 0) - messagesize = 16*1024+IOHDRSZ; + messagesize = MAXRPC; } Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); @@ -291,8 +305,9 @@ fatal("open ack write"); if (readn(netfd, &initial, sizeof(ulong)) < sizeof(ulong)) - fatal("can't read initial string: %r\n"); + fatal("can't read initial string: %r"); + /* parse any import options */ if (strncmp((char *)&initial, "impo", sizeof(ulong)) == 0) { char buf[128], *p, *args[3]; @@ -302,10 +317,10 @@ p = buf; while (p - buf < sizeof buf) { if ((n = read(netfd, p, 1)) < 0) - fatal("can't read impo arguments: %r\n"); + fatal("can't read impo arguments: %r"); if (n == 0) - fatal("connection closed while reading arguments\n"); + fatal("connection closed while reading arguments"); if (*p == '\n') *p = '\0'; @@ -314,24 +329,22 @@ } if (tokenize(buf, args, nelem(args)) != 2) - fatal("impo arguments invalid: impo%s...\n", buf); + fatal("impo arguments invalid: impo%s...", buf); if (strcmp(args[0], "aan") == 0) filterp = aanfilter; else if (strcmp(args[0], "nofilter") != 0) - fatal("import filter argument unsupported: %s\n", args[0]); + fatal("import filter argument unsupported: %s", args[0]); if (strcmp(args[1], "ssl") == 0) encproto = Encssl; else if (strcmp(args[1], "tls") == 0) encproto = Enctls; else if (strcmp(args[1], "clear") != 0) - fatal("import encryption proto unsupported: %s\n", args[1]); - - if (encproto == Enctls) - sysfatal("%s: tls has not yet been implemented", argv[0]); + fatal("import encryption proto unsupported: %s", args[1]); } + /* optionally start encrypting (server side) */ if (encproto != Encnone && ealgs && ai) { uchar key[16]; uchar digest[SHA1dlen]; @@ -347,12 +360,12 @@ key[i+12] = rand(); if (initial) - fatal("Protocol botch: old import\n"); + fatal("Protocol botch: old import"); if(readn(netfd, key, 4) != 4) - fatal("can't read key part; %r\n"); + fatal("can't read key part; %r"); if(write(netfd, key+12, 4) != 4) - fatal("can't write key part; %r\n"); + fatal("can't write key part; %r"); /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); @@ -362,22 +375,25 @@ if (filterp) netfd = filter(netfd, filterp); + procsetname("push%s server", encproto == Enctls? "tls": "ssl"); switch (encproto) { case Encssl: netfd = pushssl(netfd, ealgs, fromserversecret, fromclientsecret, nil); break; case Enctls: + netfd = pushtlsserver(netfd, tlscert); + break; default: - fatal("Unsupported encryption protocol\n"); + fatal("Unsupported encryption protocol"); } if(netfd < 0) - fatal("can't establish ssl connection: %r"); + fatal("can't establish ssl or tls connection: %r"); } else if (filterp) { if (initial) - fatal("Protocol botch: don't know how to deal with this\n"); + fatal("Protocol botch: don't know how to deal with this"); netfd = filter(netfd, filterp); } @@ -920,9 +936,9 @@ fatal("rfork record module"); case 0: if (dup(p[0], 1) < 0) - fatal("filter: Cannot dup to 1; %r\n"); + fatal("filter: Cannot dup to 1; %r"); if (dup(p[0], 0) < 0) - fatal("filter: Cannot dup to 0; %r\n"); + fatal("filter: Cannot dup to 0; %r"); close(p[0]); close(p[1]); exec(file, argv); --- /n/sources/plan9/sys/src/cmd/exportfs/exportsrv.c Sun Apr 14 16:33:20 2019 +++ /sys/src/cmd/exportfs/exportsrv.c Tue Jun 23 00:00:00 2026 @@ -5,6 +5,14 @@ #define Extern extern #include "exportfs.h" +enum { + /* + * reduce output messages this much to leave room for encapsulations + * (e.g., 9P in TLS in 9P) + */ + Encaproom = 0, +}; + extern char *netdir, *local, *remote; char Ebadfid[] = "Bad fid"; @@ -596,7 +604,7 @@ arg[0] = "exportfs"; snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd); arg[1] = fdbuf; - snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ); + snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ-Encaproom); arg[2] = mbuf; arg[3] = nil; @@ -715,6 +723,7 @@ Fcall *work, rhdr; Fid *f; int n; + long mszlim; work = &p->work; @@ -724,7 +733,11 @@ return; } - n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; + mszlim = messagesize-IOHDRSZ; + mszlim -= Encaproom; + if (mszlim < 256) + mszlim = messagesize-IOHDRSZ; + n = (work->count > mszlim)? mszlim: work->count; p->canint = 1; if(p->flushtag != NOTAG) return; --- /n/sources/plan9/sys/src/cmd/exportfs/pattern.c Sun Apr 14 16:33:20 2019 +++ /sys/src/cmd/exportfs/pattern.c Tue Jun 23 00:00:00 2026 @@ -21,7 +21,7 @@ f = Bopen(patternfile, OREAD); if(f == nil) - fatal("cannot open patternfile"); + fatal("cannot open patternfile %s: %r", patternfile); ni = 0; nmaxi = 100; include = malloc(nmaxi*sizeof(*include)); --- /n/sources/plan9/sys/man/4/exportfs Sat Aug 3 10:50:02 2013 +++ /sys/man/4/exportfs Tue Jun 23 00:00:00 2026 @@ -31,7 +31,16 @@ The service is started either by the .IR cpu (1) command or by a network listener process. An initial protocol -establishes a root directory for the exported name space. +establishes a root directory for the exported name space, +optional use of +.IR aan (8), +and type of encryption: +.B clear +(none), +.B ssl +(SSLv2), +or +.BR tls . The connection to .I exportfs @@ -97,7 +106,8 @@ .B -e '\fIenc auth\fL' Set the encryption and authentication algorithms to use for encrypting the wire traffic (see -.IR ssl (3)). +.IR ssl (3)) +if using SSLv2. The defaults are .B rc4_256 and @@ -126,11 +136,15 @@ to be matched against path names relative to the current working directory and starting with -.BR ./ . -For a file to be exported, all lines with a prefix -.B + -must match and all those with prefix -.B - +.LR ./ . +For a file to be exported, +.I all +lines with a prefix +.L + +must match and +.I all +those with prefix +.L - must not match. .TP .B -R @@ -262,6 +276,9 @@ .B /sys/src/cmd/srvfs.c .SH SEE ALSO .IR dial (2), +.IR tls (3), .IR import (4), .IR aan (8), .IR listen (8) +.SH BUGS +SSLv2 and RC4 are deprecated.