added mapping of plan9 frogs in and out of u9fs (\r is mapped to \0d and vice cerca). updated the u9fs manual paged and added an authentication section giving a more detailed description of p9any auth. -Steve Reference: /n/sources/patch/applied/u9fs-frogs Date: Sun Jan 13 02:21:06 CET 2008 Signed-off-by: steve@quintile.net --- /sys/man/4/u9fs Sun Jan 13 02:11:56 2008 +++ /sys/man/4/u9fs Sun Jan 13 02:11:52 2008 @@ -44,6 +44,8 @@ and multiplexes access to multiple Plan 9 clients over the single wire. It assumes Plan 9 uids match Unix login names, and changes to the corresponding Unix effective uid when processing requests. +Characters in file and directory names unacceptable to plan9 are translated +into a the three character sequence \\ followed by two hex codes. .I U9fs serves both 9P1 (the 9P protocol as used by the second and third editions of Plan 9) and 9P2000. @@ -113,9 +115,6 @@ .B -A option), is consulted for the authentication data. -The file must contain exactly three lines: -the plaintext password, the user id, and -the authentication domain. .TP .BI -A " autharg Used to specify an argument to the authentication method. @@ -224,8 +223,51 @@ .IR execnet (4) is useful for running .I u9fs -via mechanisms like -.IR ssh . +via other network mechanisms; the script +.IR srvssh (4) +provides this for the ssh protocol. +.SH AUTHENTICATION +.LP +The Nill authentication scheme +.I none +is normally only used when a secure channel has already +been established, for example using ssh to a Unix host. +.LP +Rhosts authentication consults the file +.I .rhosts +in the Unix users home directory on the Unix machine. If the calling +plan9 host is listed in this file then the connection will succeed. +Various other machine and site specific restrictions may be +applied to the .rhosts file's contents and metadata; See rhosts(5) +and ruserok(3) on the relevant host for more information. +.LP +The strongest authentication is plan9 specific \- +.IR p9any , +generally this uses a plan9 account for each Unix server. The account details +should be placed in the Unix file /etc/u9fs.key, which should be owned and +readable only by +.BR root . +This file must contain exactly three lines: +.LP +.EX + secret + u9fs\-user + plan9\-auth.dom +.EE +.LP +Where +.I secret +is the plaintext password, +.I u9fs\-user +the user id, and +.I plan9\-auth.dom +the authentication domain. +.LP +Finally factotum must be taught a key of the form: +.LP +.EX +key proto=p9sk1 dom=plan9\-auth.dom user=u9fs\-user !password=secret +.EE .SH SOURCE .B /sys/src/cmd/unix/u9fs .SH DIAGNOSTICS --- /sys/src/cmd/unix/u9fs/u9fs.c Sun Jan 13 02:12:07 2008 +++ /sys/src/cmd/unix/u9fs/u9fs.c Sun Jan 13 02:12:00 2008 @@ -69,7 +69,7 @@ void* emalloc(size_t); void* erealloc(void*, size_t); char* estrdup(char*); -char* estrpath(char*, char*); +char* estrpath(char*, char*, int); void sysfatal(char*, ...); int okuser(char*); @@ -156,6 +156,20 @@ Auth *auth; +/* + * frogs: characters not valid in plan9 + * filenames, keep this list in sync with + * /sys/src/9/port/chan.c:1656 + */ +char isfrog[256]={ + /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, + /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, + ['/'] 1, + [0x7f] 1, +}; + void getfcallnew(int fd, Fcall *fc, int have) { @@ -624,11 +638,52 @@ return qid; } + +char * +enfrog(char *src) +{ + char *s, *d, *dst; + + dst = emalloc(strlen(src)*3+1); + s = src; + d = dst; + while(*s){ + if(isfrog[(unsigned)*s] || *s == '\\') + d += sprintf(d, "\\%02x", (unsigned)*s++); + else + *d++ = *s++; + } + *d = 0; + return dst; +} + +char * +defrog(char *src) +{ + char *s, *d, *dst, buf[3]; + + dst = emalloc(strlen(src)); + s = src; + d = dst; + while(*s){ + if(*s == '\\'){ + strncpy(buf, s+1, 2); + buf[2] = 0; + s += 3; + *d++ = strtoul(buf, NULL, 16); + } + else + *d++ = *s++; + } + *d = 0; + return dst; +} + void stat2dir(char *path, struct stat *st, Dir *d) { User *u; - char *q; + char *q, *p, *npath; memset(d, 0, sizeof(*d)); d->qid = stat2qid(st); @@ -642,9 +697,9 @@ d->muid = ""; if((q = strrchr(path, '/')) != nil) - d->name = q+1; + d->name = enfrog(q+1); else - d->name = path; + d->name = enfrog(path); } void @@ -703,7 +758,7 @@ fid->dirent = nil; continue; } - path = estrpath(fid->path, fid->dirent->d_name); + path = estrpath(fid->path, fid->dirent->d_name, 0); memset(&st, 0, sizeof st); if(stat(path, &st) < 0){ fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno)); @@ -938,8 +993,7 @@ seterror(tx, "whoops: can't happen in u9fs"); return; } - - new = estrpath(dir, d.name); + new = estrpath(dir, d.name, 1); if(strcmp(old, new) != 0 && rename(old, new) < 0){ if(chatty9p) fprint(2, "rename(%s, %s) failed\n", old, new); @@ -1139,7 +1193,7 @@ } char* -estrpath(char *p, char *q) +estrpath(char *p, char *q, int frog) { char *r, *s; @@ -1152,11 +1206,16 @@ return r; } + if(frog) + q = defrog(q); + else + q = strdup(q); r = emalloc(strlen(p)+1+strlen(q)+1); strcpy(r, p); if(r[0]=='\0' || r[strlen(r)-1] != '/') strcat(r, "/"); strcat(r, q); + free(q); return r; } @@ -1424,7 +1483,7 @@ char *npath; struct stat st; - npath = estrpath(*path, elem); + npath = estrpath(*path, elem, 1); if(stat(npath, &st) < 0){ free(npath); *ep = strerror(errno); @@ -1529,7 +1588,7 @@ m = (perm & DMDIR) ? 0777 : 0666; perm = perm & (~m | (fid->st.st_mode & m)); - npath = estrpath(fid->path, elem); + npath = estrpath(fid->path, elem, 1); if(perm & DMDIR){ if((omode&~ORCLOSE) != OREAD){ *ep = Eperm;