📄 u9fs.c
字号:
sysfatal("strdup(%.20s) fails", p); return p;}char*estrpath(char *p, char *q){ char *r, *s; if(strcmp(q, "..") == 0){ r = estrdup(p); if((s = strrchr(r, '/')) && s > r) *s = '\0'; else if(s == r) s[1] = '\0'; return r; } r = emalloc(strlen(p)+1+strlen(q)+1); strcpy(r, p); if(r[0]=='\0' || r[strlen(r)-1] != '/') strcat(r, "/"); strcat(r, q); return r;}Fid *fidtab[1];Fid*lookupfid(int fid){ Fid *f; for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) if(f->fid == fid) return f; return nil;}Fid*newfid(int fid, char **ep){ Fid *f; if(lookupfid(fid) != nil){ *ep = Efidactive; return nil; } f = emalloc(sizeof(*f)); f->next = fidtab[fid%nelem(fidtab)]; if(f->next) f->next->prev = f; fidtab[fid%nelem(fidtab)] = f; f->fid = fid; f->fd = -1; f->omode = -1; return f;}Fid*newauthfid(int fid, void *magic, char **ep){ Fid *af; af = newfid(fid, ep); if (af == nil) return nil; af->auth = 1; af->authmagic = magic; return af;}Fid*oldfidex(int fid, int auth, char **ep){ Fid *f; if((f = lookupfid(fid)) == nil){ *ep = Ebadfid; return nil; } if (auth != -1 && f->auth != auth) { *ep = Ebadfid; return nil; } if (!f->auth) { if(userchange(f->u, ep) < 0) return nil; } return f;}Fid*oldfid(int fid, char **ep){ return oldfidex(fid, 0, ep);}Fid*oldauthfid(int fid, void **magic, char **ep){ Fid *af; af = oldfidex(fid, 1, ep); if (af == nil) return nil; *magic = af->authmagic; return af;}voidfreefid(Fid *f){ if(f->prev) f->prev->next = f->next; else fidtab[f->fid%nelem(fidtab)] = f->next; if(f->next) f->next->prev = f->prev; if(f->dir) closedir(f->dir); if(f->fd) close(f->fd); free(f->path); free(f);}intfidstat(Fid *fid, char **ep){ if(stat(fid->path, &fid->st) < 0){ fprint(2, "fidstat(%s) failed\n", fid->path); if(ep) *ep = strerror(errno); return -1; } if(S_ISDIR(fid->st.st_mode)) fid->st.st_size = 0; return 0;}intuserchange(User *u, char **ep){ if(defaultuser) return 0; if(setreuid(0, 0) < 0){ fprint(2, "setreuid(0, 0) failed\n"); *ep = "cannot setuid back to root"; return -1; } /* * Initgroups does not appear to be SUSV standard. * But it exists on SGI and on Linux, which makes me * think it's standard enough. We have to do something * like this, and the closest other function I can find is * setgroups (which initgroups eventually calls). * Setgroups is the same as far as standardization though, * so we're stuck using a non-SUSV call. Sigh. */ if(initgroups(u->name, u->defaultgid) < 0) fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); if(setreuid(-1, u->id) < 0){ fprint(2, "setreuid(-1, %s) failed\n", u->name); *ep = strerror(errno); return -1; } return 0;}/* * We do our own checking here, then switch to root temporarily * to set our gid. In a perfect world, you'd be allowed to set your * egid to any of the supplemental groups of your euid, but this * is not the case on Linux 2.2.14 (and perhaps others). * * This is a race, of course, but it's a race against processes * that can edit the group lists. If you can do that, you can * change your own group without our help. */intgroupchange(User *u, User *g, char **ep){ if(g == nil) return -1; if(!useringroup(u, g)){ if(chatty9p) fprint(2, "%s not in group %s\n", u->name, g->name); *ep = Enotingroup; return -1; } setreuid(0,0); if(setregid(-1, g->id) < 0){ fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); *ep = strerror(errno); return -1; } if(userchange(u, ep) < 0) return -1; return 0;}/* * An attempt to enforce permissions by looking at the * file system. Separation of checking permission and * actually performing the action is a terrible idea, of * course, so we use setreuid for most of the permission * enforcement. This is here only so we can give errors * on open(ORCLOSE) in some cases. */intuserperm(User *u, char *path, int type, int need){ char *p, *q; int i, have; struct stat st; User *g; switch(type){ default: fprint(2, "bad type %d in userperm\n", type); return -1; case Tdot: if(stat(path, &st) < 0){ fprint(2, "userperm: stat(%s) failed\n", path); return -1; } break; case Tdotdot: p = estrdup(path); if((q = strrchr(p, '/'))==nil){ fprint(2, "userperm(%s, ..): bad path\n", p); free(p); return -1; } if(q > p) *q = '\0'; else *(q+1) = '\0'; if(stat(p, &st) < 0){ fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", p, path); free(p); return -1; } free(p); break; } if(u == none){ fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); have = st.st_mode&7; if((have&need)==need) return 0; return -1; } have = st.st_mode&7; if((uid_t)u->id == st.st_uid) have |= (st.st_mode>>6)&7; if((have&need)==need) return 0; if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ return -1; g = gid2user(st.st_gid); for(i=0; i<g->nmem; i++){ if(strcmp(g->mem[i], u->name) == 0){ have |= (st.st_mode>>3)&7; break; } } if((have&need)==need) return 0; return -1;}intuserwalk(User *u, char **path, char *elem, Qid *qid, char **ep){ char *npath; struct stat st; npath = estrpath(*path, elem); if(stat(npath, &st) < 0){ free(npath); *ep = strerror(errno); return -1; } *qid = stat2qid(&st); free(*path); *path = npath; return 0;}intuseropen(Fid *fid, int omode, char **ep){ int a, o; /* * Check this anyway, to try to head off problems later. */ if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ *ep = Eperm; return -1; } switch(omode&3){ default: *ep = "programmer error"; return -1; case OREAD: a = R_OK; o = O_RDONLY; break; case ORDWR: a = R_OK|W_OK; o = O_RDWR; break; case OWRITE: a = W_OK; o = O_WRONLY; break; case OEXEC: a = X_OK; o = O_RDONLY; break; } if(omode & OTRUNC){ a |= W_OK; o |= O_TRUNC; } if(S_ISDIR(fid->st.st_mode)){ if(a != R_OK){ fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); *ep = Eperm; return -1; } if((fid->dir = opendir(fid->path)) == nil){ *ep = strerror(errno); return -1; } }else{ /* * This is wrong because access used the real uid * and not the effective uid. Let the open sort it out. * if(access(fid->path, a) < 0){ *ep = strerror(errno); return -1; } * */ if((fid->fd = open(fid->path, o)) < 0){ *ep = strerror(errno); return -1; } } fid->omode = omode; return 0;}intusercreate(Fid *fid, char *elem, int omode, long perm, char **ep){ int o, m; char *opath, *npath; struct stat st, parent; if(stat(fid->path, &parent) < 0){ *ep = strerror(errno); return -1; } /* * Change group so that created file has expected group * by Plan 9 semantics. If that fails, might as well go * with the user's default group. */ if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) return -1; m = (perm & DMDIR) ? 0777 : 0666; perm = perm & (~m | (fid->st.st_mode & m)); npath = estrpath(fid->path, elem); if(perm & DMDIR){ if((omode&~ORCLOSE) != OREAD){ *ep = Eperm; free(npath); return -1; } if(stat(npath, &st) >= 0 || errno != ENOENT){ *ep = Eexist; free(npath); return -1; } /* race */ if(mkdir(npath, perm&0777) < 0){ *ep = strerror(errno); free(npath); return -1; } if((fid->dir = opendir(npath)) == nil){ *ep = strerror(errno); remove(npath); /* race */ free(npath); return -1; } }else{ o = O_CREAT|O_EXCL; switch(omode&3){ default: *ep = "programmer error"; return -1; case OREAD: case OEXEC: o |= O_RDONLY; break; case ORDWR: o |= O_RDWR; break; case OWRITE: o |= O_WRONLY; break; } if(omode & OTRUNC) o |= O_TRUNC; if((fid->fd = open(npath, o, perm&0777)) < 0){ if(chatty9p) fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); *ep = strerror(errno); free(npath); return -1; } } opath = fid->path; fid->path = npath; if(fidstat(fid, ep) < 0){ fprint(2, "stat after create on %s failed\n", npath); remove(npath); /* race */ free(npath); fid->path = opath; if(fid->fd >= 0){ close(fid->fd); fid->fd = -1; }else{ closedir(fid->dir); fid->dir = nil; } return -1; } fid->omode = omode; free(opath); return 0;}intuserremove(Fid *fid, char **ep){ if(remove(fid->path) < 0){ *ep = strerror(errno); return -1; } return 0;}voidusage(void){ fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); exit(1);}intmain(int argc, char **argv){ char *authtype; int i; int fd; int logflag; auth = authmethods[0]; logflag = O_WRONLY|O_APPEND|O_CREAT; ARGBEGIN{ case 'D': chatty9p = 1; break; case 'a': authtype = EARGF(usage()); auth = nil; for(i=0; i<nelem(authmethods); i++) if(strcmp(authmethods[i]->name, authtype)==0) auth = authmethods[i]; if(auth == nil) sysfatal("unknown auth type '%s'", authtype); break; case 'A': autharg = EARGF(usage()); break; case 'l': logfile = EARGF(usage()); break; case 'm': msize = strtol(EARGF(usage()), 0, 0); break; case 'n': network = 0; break; case 'u': defaultuser = EARGF(usage()); break; case 'z': logflag |= O_TRUNC; }ARGEND if(argc > 1) usage(); fd = open(logfile, logflag, 0666); if(fd < 0) sysfatal("cannot open log '%s'", logfile); if(dup2(fd, 2) < 0) sysfatal("cannot dup fd onto stderr"); fprint(2, "u9fs\nkill %d\n", (int)getpid()); fmtinstall('F', fcallconv); fmtinstall('D', dirconv); fmtinstall('M', dirmodeconv); rxbuf = emalloc(msize); txbuf = emalloc(msize); databuf = emalloc(msize); if(auth->init) auth->init(); if(network) getremotehostname(remotehostname, sizeof remotehostname); if(gethostname(hostname, sizeof hostname) < 0) strcpy(hostname, "gnot"); umask(0); if(argc == 1) if(chroot(argv[0]) < 0) sysfatal("chroot '%s' failed", argv[0]); none = uname2user("none"); serve(0, 1); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -