int iaccess(File *f, Dentry *d, int m) { if(wstatallow) return 0; /* * owner is next */ if(f->uid == d->uid) if((m<<6) & d->mode) return 0; /* * group membership is hard */ if(ingroup(f->uid, d->gid)) if((m<<3) & d->mode) return 0; /* * other access for everyone except members of group 9999 */ if(m & d->mode){ /* * walk directories regardless. * otherwise its impossible to get * from the root to noworld's directories. */ if((d->mode & DDIR) && (m == DEXEC)) return 0; if(!ingroup(f->uid, 9999)) return 0; } return 1; }
int main(int argc, char **argv) { struct cmd *c; effective_uid = geteuid(); real_uid = getuid(); effective_gid = getegid(); real_gid = getgid(); PRIV_END; /* be safe */ openlog("lpc", 0, LOG_LPR); if (--argc > 0) { c = getcmd(*++argv); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); exit(1); } if (c == 0) { printf("?Invalid command\n"); exit(1); } if (c->c_priv && real_uid && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); exit(1); } (*c->c_handler)(argc, argv); exit(0); } fromatty = isatty(fileno(stdin)); signal(SIGINT, intr); for (;;) cmdscanner(); }
int iaccess(File *f, Dentry *d, int m) { /* uid none gets only other permissions */ if(f->uid != 0) { /* * owner */ if(f->uid == d->uid) if((m<<6) & d->mode) return 0; /* * group membership */ if(ingroup(f->uid, d->gid)) if((m<<3) & d->mode) return 0; } /* * other */ if(m & d->mode) { if((d->mode & DDIR) && (m == DEXEC)) return 0; if(!ingroup(f->uid, 9999)) return 0; } /* * various forms of superuser */ if(wstatallow) return 0; if(duallow != 0 && duallow == f->uid) if((d->mode & DDIR) && (m == DREAD || m == DEXEC)) return 0; return 1; }
/* * Command parser. */ static void cmdscanner(void) { struct cmd *c; for (;;) { if (gotintr) { putchar('\n'); gotintr = 0; } if (fromatty) { printf("lpc> "); fflush(stdout); } siginterrupt(SIGINT, 1); if (fgets(cmdline, MAX_CMDLINE, stdin) == NULL) { if (errno == EINTR && gotintr) { siginterrupt(SIGINT, 0); return; } siginterrupt(SIGINT, 0); quit(0, NULL); } siginterrupt(SIGINT, 0); makeargv(); if (margc == 0) break; c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); continue; } if (c == 0) { printf("?Invalid command\n"); continue; } if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); continue; } (*c->c_handler)(margc, margv); } }
/* * Delete logins according to the criteria given in options. */ void userdel(void) { struct login *lp, *lprev = NULL; if (dflag == 0 && pflag == 0 && selgrp == NULL) return; for (lp = l0; lp; lp = lp->l_next) if (pflag && (lp->l_pwdp == NULL || *lp->l_pwdp != '\0') || selgrp && !ingroup(lp) || dflag && !duplicate(lp)) { if (lprev != NULL) lprev->l_next = lp->l_next; else l0 = lp->l_next; } else lprev = lp; }
int main(int argc, char *argv[]) { register struct cmd *c; euid = geteuid(); uid = getuid(); PRIV_END progname = argv[0]; openlog("lpd", 0, LOG_LPR); if (--argc > 0) { c = getcmd(*++argv); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); exit(1); } if (c == NULL) { printf("?Invalid command\n"); exit(1); } if ((c->c_opts & LPC_PRIVCMD) && getuid() && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); exit(1); } if (c->c_generic != NULL) generic(c->c_generic, c->c_opts, c->c_handler, argc, argv); else (*c->c_handler)(argc, argv); exit(0); } fromatty = isatty(fileno(stdin)); if (!fromatty) signal(SIGINT, intr); for (;;) { cmdscanner(); } }
int isevegroup(void) { return ingroup(up->user, eve); }
/* * Command parser. */ static void cmdscanner(void) { register struct cmd *c; static EditLine *el; static History *hist; HistEvent he; size_t len; int num; const char *bp; num = 0; bp = NULL; el = NULL; hist = NULL; for (;;) { if (fromatty) { if (!el) { el = el_init("lpc", stdin, stdout, stderr); hist = history_init(); history(hist, &he, H_SETSIZE, 100); el_set(el, EL_HIST, history, hist); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_PROMPT, lpc_prompt); el_set(el, EL_SIGNAL, 1); el_source(el, NULL); /* * EditLine init may call 'cgetset()' to set a * capability-db meant for termcap (eg: to set * terminal type 'xterm'). Reset that now, or * that same db-information will be used for * printcap (giving us an "xterm" printer, with * all kinds of invalid capabilities...). */ cgetset(NULL); } if ((bp = el_gets(el, &num)) == NULL || num == 0) quit(0, NULL); len = (num > MAX_CMDLINE - 1) ? MAX_CMDLINE - 1 : num; memcpy(cmdline, bp, len); cmdline[len] = 0; history(hist, &he, H_ENTER, bp); } else { if (fgets(cmdline, MAX_CMDLINE, stdin) == NULL) quit(0, NULL); if (cmdline[0] == 0 || cmdline[0] == '\n') break; } makeargv(); if (margc == 0) continue; if (el != NULL && el_parse(el, margc, margv) != -1) continue; c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); continue; } if (c == NULL) { printf("?Invalid command\n"); continue; } if ((c->c_opts & LPC_PRIVCMD) && getuid() && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); continue; } /* * Two different commands might have the same generic rtn * (eg: "clean" and "tclean"), and just use different * handler routines for distinct command-setup. The handler * routine might also be set on a generic routine for * initial parameter processing. */ if (c->c_generic != NULL) generic(c->c_generic, c->c_opts, c->c_handler, margc, margv); else (*c->c_handler)(margc, margv); } }
/* -------------------------------------------------------------------- */ void renamegroup(void) { label groupname, newname; char desc[80]; int groupslot, locked, hidden, autoAdd; getString("group", groupname, NAMESIZE, FALSE, ECHO, ""); groupslot = partialgroup(groupname); if ( grpBuf.group[groupslot].hidden && !ingroup(groupslot) && !onConsole) groupslot = ERROR; if ( groupslot == ERROR || !strlen(groupname) ) { mPrintf("\n No such group."); return; } doCR(); mPrintf(" Group: %s ", grpBuf.group[groupslot].groupname); if (grpBuf.group[groupslot].lockout) { mPrintf("(Locked) "); } if (grpBuf.group[groupslot].hidden) { mPrintf("(Hidden) "); } if (grpBuf.group[groupslot].autoAdd) { mPrintf("(Auto-Add)"); } doCR(); mPrintf(" Descibed: %s ", grpBuf.group[groupslot].desc); doCR(); getString("new group name", newname, NAMESIZE, FALSE, ECHO, grpBuf.group[groupslot].groupname); getString("new group description", desc, 79, FALSE, ECHO, ""); if (groupexists(newname) != ERROR && stricmp(newname, grpBuf.group[groupslot].groupname) != SAMESTRING) { mPrintf("\n A \'%s\' group already exists.", newname); return; } /* locked group? */ locked = (getYesNo("Lock group from aides", (char)grpBuf.group[groupslot].lockout )); hidden = (getYesNo("Make group hidden", (char)grpBuf.group[groupslot].hidden )); if (groupslot) { autoAdd = (getYesNo("Make group auto-add", (char)grpBuf.group[groupslot].autoAdd)); } if (getYesNo(confirm, 0)) { grpBuf.group[groupslot].lockout = locked; grpBuf.group[groupslot].hidden = hidden; grpBuf.group[groupslot].autoAdd = autoAdd; strcpy(grpBuf.group[groupslot].groupname, newname); if (*desc) { strcpy(grpBuf.group[groupslot].desc, desc); } sprintf(msgBuf->mbtext, "Group %s renamed %s", groupname, newname); trap(msgBuf->mbtext, T_SYSOP); putGroup(); } }
/* -------------------------------------------------------------------- */ void listgroup(void) { label groupname; int i, groupslot; getString("", groupname, NAMESIZE, FALSE, ECHO, ""); outFlag = OUTOK; if ( !strlen(groupname)) { for (i = 0; i < MAXGROUPS; i++) { /* can they see the group */ if ( grpBuf.group[i].g_inuse && (!grpBuf.group[i].lockout || sysop) && (!grpBuf.group[i].hidden || onConsole || ingroup(i)) ) { mPrintf(" %-30s %c%c%c ", grpBuf.group[i].groupname, grpBuf.group[i].lockout ? 'L' : ' ', grpBuf.group[i].hidden ? 'H' : ' ', (grpBuf.group[i].autoAdd || !i) ? 'A' : ' ' ); mPrintf("%s", grpBuf.group[i].desc); doCR(); } } return; } groupslot = partialgroup(groupname); if ( grpBuf.group[groupslot].hidden && !ingroup(groupslot) ) groupslot = ERROR; if (groupslot == ERROR) { mPrintf("\n No such group."); return; } if ( grpBuf.group[groupslot].lockout && (!(logBuf.lbflags.SYSOP || onConsole)) ) { mPrintf("\n Group is locked."); return; } doCR(); outFlag = OUTOK; mPrintf(" Users:"); doCR(); prtList(LIST_START); for (i = 0; ( ( i < cfg.MAXLOGTAB) && (outFlag != OUTSKIP) && (outFlag != OUTNEXT) ); i++) { if (logTab[i].ltpwhash != 0 && logTab[i].ltnmhash != 0) { getLog(&lBuf, logTab[i].ltlogSlot); if (lBuf.groups[groupslot] == grpBuf.group[groupslot].groupgen) { prtList(lBuf.lbname); /* doCR(); mPrintf(" %s", lBuf.lbname); */ } else { mAbort(FALSE); } } if (outFlag == OUTSKIP) { doCR(); return; } } prtList(LIST_END); if (outFlag == OUTSKIP) { doCR(); return; } outFlag = OUTOK; doCR(); mPrintf(" Rooms:"); doCR(); prtList(LIST_START); for (i = 0; ( ( i < MAXROOMS) && (outFlag != OUTSKIP) && (outFlag != OUTNEXT) ); i++) { if ( roomTab[i].rtflags.INUSE && roomTab[i].rtflags.GROUPONLY && (roomTab[i].grpno == (unsigned char)groupslot) /* && (roomTab[i].grpgen == grpBuf.group[groupslot].groupgen) */ ) { prtList(roomTab[i].rtname); } } prtList(LIST_END); if (outFlag == OUTSKIP) { doCR(); return; } outFlag = OUTOK; doCR(); mPrintf(" Hallways:"); for (i = 0; ( ( i < MAXHALLS) && (outFlag != OUTSKIP) && (outFlag != OUTNEXT) ); i++) { if ( hallBuf->hall[i].h_inuse && hallBuf->hall[i].owned && (hallBuf->hall[i].grpno == (unsigned char)groupslot) ) { doCR(); mPrintf(" %s", hallBuf->hall[i].hallname); } } doCR(); }
/* -------------------------------------------------------------------- */ void groupfunc(void) { label who; label groupname; int groupslot, logNo; getString("group", groupname, NAMESIZE, FALSE, ECHO, ""); groupslot = partialgroup(groupname); if (groupslot != ERROR) { if ( grpBuf.group[groupslot].lockout && !sysop ) groupslot = ERROR; if( grpBuf.group[groupslot].hidden && !ingroup(groupslot) && !onConsole ) groupslot = ERROR; } if ( groupslot == ERROR || !strlen(groupname) ) { mPrintf("\n No such group."); return; } getNormStr("who", who, NAMESIZE, ECHO); logNo = findPerson(who, &lBuf); if (logNo == ERROR || !strlen(who) ) { mPrintf("No \'%s\' known. \n ", who); return; } if (lBuf.groups[groupslot] == grpBuf.group[groupslot].groupgen) { if (getYesNo("Remove from group", 0)) { lBuf.groups[groupslot] = (uchar)((grpBuf.group[groupslot].groupgen + (MAXGROUPGEN - 1)) % MAXGROUPGEN); sprintf(msgBuf->mbtext, "%s kicked out of group %s by %s", lBuf.lbname, grpBuf.group[groupslot].groupname, logBuf.lbname ); trap(msgBuf->mbtext, T_AIDE); aideMessage(); } } else if (getYesNo("Add to group", 0)) { lBuf.groups[groupslot] = grpBuf.group[groupslot].groupgen; sprintf(msgBuf->mbtext, "%s added to group %s by %s", lBuf.lbname, grpBuf.group[groupslot].groupname, logBuf.lbname ); trap(msgBuf->mbtext, T_AIDE); aideMessage(); } putLog(&lBuf, logNo); /* see if it is us: */ if (loggedIn && strcmpi(logBuf.lbname, who) == SAMESTRING) { logBuf.groups[groupslot] = lBuf.groups[groupslot]; } }
/* -------------------------------------------------------------------- */ void globaluser(void) { label who; int groupslot, yn, logNo; getNormStr("who", who, NAMESIZE, ECHO); logNo = findPerson(who, &lBuf); if (logNo == ERROR || !strlen(who) ) { mPrintf("No \'%s\' known. \n ", who); return; } for(groupslot=0; groupslot < MAXGROUPS; groupslot++) { if (grpBuf.group[groupslot].g_inuse && ( !grpBuf.group[groupslot].lockout || sysop ) && ( !grpBuf.group[groupslot].hidden || ingroup(groupslot) ) ) { mPrintf(" %s", grpBuf.group[groupslot].groupname); if (lBuf.groups[groupslot] == grpBuf.group[groupslot].groupgen) { if ((yn = getYesNo("Remove from group", 3)) != 0 /*NULL*/) { if (yn == 2) { SaveAideMess(); return; } lBuf.groups[groupslot] = (uchar)((grpBuf.group[groupslot].groupgen + (MAXGROUPGEN - 1)) % MAXGROUPGEN); sprintf(msgBuf->mbtext, "%s kicked out of group %s by %s", lBuf.lbname, grpBuf.group[groupslot].groupname, logBuf.lbname ); trap(msgBuf->mbtext, T_AIDE); amPrintf(" %s\n", msgBuf->mbtext); } } else { if ((yn = getYesNo("Add to group", 3)) != /* NULL */ 0) { if (yn == 2) { SaveAideMess(); return; } lBuf.groups[groupslot] = grpBuf.group[groupslot].groupgen; sprintf(msgBuf->mbtext, "%s added to group %s by %s", lBuf.lbname, grpBuf.group[groupslot].groupname, logBuf.lbname ); trap(msgBuf->mbtext, T_SYSOP); amPrintf(" %s\n",msgBuf->mbtext); } } putLog(&lBuf, logNo); /* see if it is us: */ if (loggedIn && strcmpi(logBuf.lbname, who) == SAMESTRING) { logBuf.groups[groupslot] = lBuf.groups[groupslot]; } } } SaveAideMess(); }
/* -------------------------------------------------------------------- */ void globalgroup(void) { label groupname; int groupslot, i, yn, add, logNo; mPrintf("(A/R/[B]): "); switch (toupper( iCharNE() )) { case 'A': mPrintf("Add\n "); add = 1; break; case 'R': mPrintf("Remove\n "); add = 2; break; case '?': tutorial("grpglob.mnu"); return; case 'B': case 10: case 13: default: mPrintf("Both\n "); add = 0; break; } getString("group", groupname, NAMESIZE, FALSE, ECHO, ""); groupslot = partialgroup(groupname); if ( grpBuf.group[groupslot].hidden && !ingroup(groupslot) ) groupslot = ERROR; if ( groupslot == ERROR || !strlen(groupname) ) { mPrintf("\n No such group."); return; } if ( grpBuf.group[groupslot].lockout && !sysop ) { mPrintf("\n Group is locked."); return; } for (i = 0; i < cfg.MAXLOGTAB; i++) { if (logTab[i].ltpwhash != 0 && logTab[i].ltnmhash !=0) { logNo=logTab[i].ltlogSlot; getLog(&lBuf, logNo); /* Get out.. */ outFlag = OUTOK; if (mAbort(FALSE)) break; outFlag = IMPERVIOUS; if (lBuf.groups[groupslot] == grpBuf.group[groupslot].groupgen) { if(add == 2 || add == 0) { mPrintf(" 3%s0", lBuf.lbname); yn=getYesNo("Remove from group", 0+3); if (yn == 2) { SaveAideMess(); return; } if (yn) { lBuf.groups[groupslot] = (uchar)((grpBuf.group[groupslot].groupgen + (MAXGROUPGEN - 1)) % MAXGROUPGEN); sprintf(msgBuf->mbtext, "%s kicked out of group %s by %s", lBuf.lbname, grpBuf.group[groupslot].groupname, logBuf.lbname ); trap(msgBuf->mbtext, T_SYSOP); amPrintf(" %s\n", msgBuf->mbtext); } } } else { if (add == 0 || add == 1) { mPrintf(" 3%s0", lBuf.lbname); yn=getYesNo("Add to group", 0+3); if (yn == 2) { SaveAideMess(); return; } if (yn) { lBuf.groups[groupslot] = grpBuf.group[groupslot].groupgen; sprintf(msgBuf->mbtext, "%s added to group %s by %s", lBuf.lbname, grpBuf.group[groupslot].groupname, logBuf.lbname ); trap(msgBuf->mbtext, T_AIDE); amPrintf(" %s\n",msgBuf->mbtext); } } } putLog(&lBuf, logNo); /* see if it is us: */ if (loggedIn && strcmpi(logBuf.lbname, lBuf.lbname) == SAMESTRING) { logBuf.groups[groupslot] = lBuf.groups[groupslot]; } } } SaveAideMess(); }
void negotiate(void) { int groupslot, i; int firstime = TRUE; float priority = 0; clearthisAccount(); for (groupslot = 0; groupslot < MAXGROUPS; groupslot++) { if (ingroup(groupslot) && accountBuf.group[groupslot].account.have_acc) { /* is in a group with accounting */ thisAccount.have_acc = TRUE; if (accountBuf.group[groupslot].account.priority >= priority) { if (accountBuf.group[groupslot].account.priority > priority) { /********************************/ clearthisAccount(); /* if it's more imp, start over */ thisAccount.have_acc = TRUE;/*otherwise, compromise!*/ firstime = TRUE; } /************************/ priority = accountBuf.group[groupslot].account.priority; for ( i = 0; i < 7; ++i) if (accountBuf.group[groupslot].account.days[i]) thisAccount.days[i] = 1; for ( i = 0; i < 24; ++i) { if (accountBuf.group[groupslot].account.hours[i]) thisAccount.hours[i] = 1; if (accountBuf.group[groupslot].account.special[i]) thisAccount.special[i] = 1; } if (accountBuf.group[groupslot].account.dayinc > thisAccount.dayinc || firstime) thisAccount.dayinc = accountBuf.group[groupslot].account.dayinc; if (accountBuf.group[groupslot].account.sp_dayinc > thisAccount.sp_dayinc || firstime) thisAccount.sp_dayinc = accountBuf.group[groupslot].account.sp_dayinc; if (accountBuf.group[groupslot].account.maxbal > thisAccount.maxbal) thisAccount.maxbal = accountBuf.group[groupslot].account.maxbal; /* these are */ thisAccount.dlmult = /* special */ accountBuf.group[groupslot].account.dlmult; /* */ /* */ thisAccount.ulmult = /*-----------*/ accountBuf.group[groupslot].account.ulmult; firstime = FALSE; } /* if */ } /* if */ } /* for */ }
int doremove(File *f, int iscon) { Iobuf *p, *p1; Dentry *d, *d1; int32_t addr; int slot, err; p = 0; p1 = 0; if(isro(f->fs->dev) || (f->cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { err = Eronly; goto out; } /* * check on parent directory of file to be deleted */ if(f->wpath == 0 || f->wpath->addr == f->addr) { err = Ephase; goto out; } p1 = getbuf(f->fs->dev, f->wpath->addr, Bread); d1 = getdir(p1, f->wpath->slot); if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) { err = Ephase; goto out; } if(!iscon && iaccess(f, d1, DWRITE)) { err = Eaccess; goto out; } accessdir(p1, d1, FWRITE); putbuf(p1); p1 = 0; /* * check on file to be deleted */ p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { err = Ealloc; goto out; } if(err = mkqidcmp(&f->qid, d)) goto out; /* * if deleting a directory, make sure it is empty */ if((d->mode & DDIR)) for(addr=0;; addr++) { p1 = dnodebuf(p, d, addr, 0); if(!p1) break; if(checktag(p1, Tdir, d->qid.path)) { err = Ephase; goto out; } for(slot=0; slot<DIRPERBUF; slot++) { d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) continue; err = Eempty; goto out; } putbuf(p1); } /* * do it */ dtrunc(p, d); memset(d, 0, sizeof(Dentry)); settag(p, Tdir, QPNONE); out: if(p1) putbuf(p1); if(p) putbuf(p); return err; }
void f_write(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d; File *f; Tlock *t; int32_t offset, addr, tim; int count, nwrite, o, n; if(CHAT(cp)) { print("c_write %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" offset = %ld\n", in->offset); print(" count = %ld\n", in->count); } offset = in->offset; count = in->count; nwrite = 0; p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(!(f->open & FWRITE)) { ou->err = Eopen; goto out; } if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { ou->err = Eronly; goto out; } if(count < 0 || count > MAXDAT) { ou->err = Ecount; goto out; } if(offset < 0) { ou->err = Eoffset; goto out; } p = getbuf(f->fs->dev, f->addr, Bread|Bmod); d = getdir(p, f->slot); if(!d || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(t = f->tlock) { tim = time(0); if(t->time < tim || t->file != f) { ou->err = Ebroken; goto out; } /* renew the lock */ t->time = tim + TLOCK; } accessdir(p, d, FWRITE); if(d->mode & DAPND) offset = d->size; if(offset+count > d->size) d->size = offset+count; while(count > 0) { addr = offset / BUFSIZE; o = offset % BUFSIZE; n = BUFSIZE - o; if(n > count) n = count; p1 = dnodebuf(p, d, addr, Tfile); if(p1 == 0) { ou->err = Efull; goto out; } if(checktag(p1, Tfile, d->qid.path)) { putbuf(p1); ou->err = Ephase; goto out; } memmove(p1->iobuf+o, in->data+nwrite, n); p1->flags |= Bmod; putbuf(p1); count -= n; nwrite += n; offset += n; } if(CHAT(cp)) print(" nwrite = %d\n", nwrite); out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; ou->count = nwrite; }
void f_create(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d, *d1; File *f; int slot, slot1, fmod; int32_t addr, addr1, path; Qid qid; Tlock *t; Wpath *w; if(CHAT(cp)) { print("c_create %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" name = %s\n", in->name); print(" perm = %lx+%lo\n", (in->perm>>28)&0xf, in->perm&0777); print(" mode = %d\n", in->mode); } p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { ou->err = Eronly; goto out; } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; if(!(d->mode & DDIR)) { ou->err = Edir2; goto out; } if(cp != cons.chan && iaccess(f, d, DWRITE) && !writeallow) { ou->err = Eaccess; goto out; } accessdir(p, d, FREAD); if(!strncmp(in->name, ".", sizeof(in->name)) || !strncmp(in->name, "..", sizeof(in->name))) { ou->err = Edot; goto out; } if(checkname(in->name)) { ou->err = Ename; goto out; } addr1 = 0; slot1 = 0; /* set */ for(addr=0;; addr++) { p1 = dnodebuf(p, d, addr, 0); if(!p1) { if(addr1) break; p1 = dnodebuf(p, d, addr, Tdir); } if(p1 == 0) { ou->err = Efull; goto out; } if(checktag(p1, Tdir, d->qid.path)) { putbuf(p1); goto phase; } for(slot=0; slot<DIRPERBUF; slot++) { d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) { if(!addr1) { addr1 = p1->addr; slot1 = slot + addr*DIRPERBUF; } continue; } if(!strncmp(in->name, d1->name, sizeof(in->name))) { putbuf(p1); ou->err = Eexist; goto out; } } putbuf(p1); } switch(in->mode & 7) { case MEXEC: case MREAD: /* seems only useful to make directories */ fmod = FREAD; break; case MWRITE: fmod = FWRITE; break; case MBOTH: fmod = FREAD+FWRITE; break; default: ou->err = Emode; goto out; } if(in->perm & PDIR) if((in->mode & MTRUNC) || (in->perm & PAPND) || (fmod & FWRITE)) goto badaccess; /* * do it */ path = qidpathgen(&f->fs->dev); p1 = getbuf(f->fs->dev, addr1, Bread|Bimm|Bmod); d1 = getdir(p1, slot1); if(!d1 || checktag(p1, Tdir, d->qid.path)) { if(p1) putbuf(p1); goto phase; } if(d1->mode & DALLOC) { putbuf(p1); goto phase; } strncpy(d1->name, in->name, sizeof(in->name)); /* * bogus argument passing -- see console.c */ if(cp == cons.chan) { d1->uid = cons.uid; d1->gid = cons.gid; } else { d1->uid = f->uid; d1->gid = d->gid; in->perm &= d->mode | ~0666; if(in->perm & PDIR) in->perm &= d->mode | ~0777; } d1->qid.path = path; d1->qid.version = 0; d1->mode = DALLOC | (in->perm & 0777); if(in->perm & PDIR) { d1->mode |= DDIR; d1->qid.path |= QPDIR; } if(in->perm & PAPND) d1->mode |= DAPND; t = 0; if(in->perm & PLOCK) { d1->mode |= DLOCK; t = tlocked(p1, d1); } accessdir(p1, d1, FWRITE); mkqid(&qid, d1, 0); putbuf(p1); accessdir(p, d, FWRITE); /* * do a walk to new directory entry */ w = newwp(); if(!w) { ou->err = Ewalk; goto out; } w->addr = f->addr; w->slot = f->slot; w->up = f->wpath; f->wpath = w; f->qid = qid; f->tlock = t; f->lastra = 0; if(in->mode & MRCLOSE) fmod |= FREMOV; f->open = fmod; f->addr = addr1; f->slot = slot1; if(t) t->file = f; mkqid9p1(&ou->qid, &qid); goto out; badaccess: ou->err = Eaccess; goto out; phase: ou->err = Ephase; out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; }
void f_open(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p; Dentry *d; File *f; Tlock *t; Qid qid; int ro, fmod; if(CHAT(cp)) { print("c_open %d\n", cp->chan); print(" fid = %d\n", in->fid); print(" mode = %o\n", in->mode); } p = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } /* * if remove on close, check access here */ ro = isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup)); if(in->mode & MRCLOSE) { if(ro) { ou->err = Eronly; goto out; } /* * check on parent directory of file to be deleted */ if(f->wpath == 0 || f->wpath->addr == f->addr) { ou->err = Ephase; goto out; } p = getbuf(f->fs->dev, f->wpath->addr, Bread); d = getdir(p, f->wpath->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ephase; goto out; } if(iaccess(f, d, DWRITE)) { ou->err = Eaccess; goto out; } putbuf(p); } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; mkqid(&qid, d, 1); switch(in->mode & 7) { case MREAD: if(iaccess(f, d, DREAD) && !writeallow) goto badaccess; fmod = FREAD; break; case MWRITE: if((d->mode & DDIR) || (iaccess(f, d, DWRITE) && !writeallow)) goto badaccess; if(ro) { ou->err = Eronly; goto out; } fmod = FWRITE; break; case MBOTH: if((d->mode & DDIR) || (iaccess(f, d, DREAD) && !writeallow) || (iaccess(f, d, DWRITE) && !writeallow)) goto badaccess; if(ro) { ou->err = Eronly; goto out; } fmod = FREAD+FWRITE; break; case MEXEC: if((d->mode & DDIR) || iaccess(f, d, DEXEC)) goto badaccess; fmod = FREAD; break; default: ou->err = Emode; goto out; } if(in->mode & MTRUNC) { if((d->mode & DDIR) || (iaccess(f, d, DWRITE) && !writeallow)) goto badaccess; if(ro) { ou->err = Eronly; goto out; } } t = 0; if(d->mode & DLOCK) { t = tlocked(p, d); if(t == 0) { ou->err = Elocked; goto out; } t->file = f; } if(in->mode & MRCLOSE) fmod |= FREMOV; f->open = fmod; if(in->mode & MTRUNC) if(!(d->mode & DAPND)) dtrunc(p, d); f->tlock = t; f->lastra = 0; mkqid9p1(&ou->qid, &qid); goto out; badaccess: ou->err = Eaccess; f->open = 0; out: if(p) putbuf(p); if(f) qunlock(f); ou->fid = in->fid; }
void f_wstat(Chan *cp, Oldfcall *in, Oldfcall *ou) { Iobuf *p, *p1; Dentry *d, *d1, xd; File *f; int slot; int32_t addr; if(CHAT(cp)) { print("c_wstat %d\n", cp->chan); print(" fid = %d\n", in->fid); } p = 0; p1 = 0; d1 = 0; f = filep(cp, in->fid, 0); if(!f) { ou->err = Efid; goto out; } if(isro(f->fs->dev) || (cp != cons.chan && writegroup && !ingroup(f->uid, writegroup))) { ou->err = Eronly; goto out; } /* * first get parent */ if(f->wpath) { p1 = getbuf(f->fs->dev, f->wpath->addr, Bread); d1 = getdir(p1, f->wpath->slot); if(!d1 || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)) { ou->err = Ephase; goto out; } } p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ealloc; goto out; } if(ou->err = mkqidcmp(&f->qid, d)) goto out; convM2D9p1(in->stat, &xd); if(CHAT(cp)) { print(" d.name = %s\n", xd.name); print(" d.uid = %d\n", xd.uid); print(" d.gid = %d\n", xd.gid); print(" d.mode = %.4x\n", xd.mode); } /* * if chown, * must be god */ while(xd.uid != d->uid) { if(wstatallow) /* set to allow chown during boot */ break; ou->err = Enotu; goto out; } /* * if chgroup, * must be either * a) owner and in new group * b) leader of both groups */ while(xd.gid != d->gid) { if(wstatallow || writeallow) /* set to allow chgrp during boot */ break; if(d->uid == f->uid && ingroup(f->uid, xd.gid)) break; if(leadgroup(f->uid, xd.gid)) if(leadgroup(f->uid, d->gid)) break; ou->err = Enotg; goto out; } /* * if rename, * must have write permission in parent */ if(xd.name[0] == 0) strncpy(xd.name, d->name, sizeof(xd.name)); while(strncmp(d->name, xd.name, sizeof(d->name)) != 0) { if(checkname(xd.name)) { ou->err = Ename; goto out; } if(strcmp(xd.name, ".") == 0 || strcmp(xd.name, "..") == 0) { ou->err = Ename; goto out; } /* * drop entry to prevent lock, then * check that destination name is unique, */ putbuf(p); for(addr=0;; addr++) { p = dnodebuf(p1, d1, addr, 0); if(!p) break; if(checktag(p, Tdir, d1->qid.path)) { putbuf(p); continue; } for(slot=0; slot<DIRPERBUF; slot++) { d = getdir(p, slot); if(!(d->mode & DALLOC)) continue; if(!strncmp(xd.name, d->name, sizeof(xd.name))) { ou->err = Eexist; goto out; } } putbuf(p); } /* * reacquire entry */ p = getbuf(f->fs->dev, f->addr, Bread); d = getdir(p, f->slot); if(!d || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) { ou->err = Ephase; goto out; } if(wstatallow || writeallow) /* set to allow rename during boot */ break; if(!d1 || iaccess(f, d1, DWRITE)) { ou->err = Eaccess; goto out; } break; } /* * if mode/time, either * a) owner * b) leader of either group */ while(d->mtime != xd.mtime || ((d->mode^xd.mode) & (DAPND|DLOCK|0777))) { if(wstatallow) /* set to allow chmod during boot */ break; if(d->uid == f->uid) break; if(leadgroup(f->uid, xd.gid)) break; if(leadgroup(f->uid, d->gid)) break; ou->err = Enotu; goto out; } d->mtime = xd.mtime; d->uid = xd.uid; d->gid = xd.gid; d->mode = (xd.mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR)); strncpy(d->name, xd.name, sizeof(d->name)); if(wstatallow) { p->flags |= Bmod; if(xd.atime) d->atime = xd.atime; if(xd.mtime) d->mtime = xd.mtime; } else accessdir(p, d, FWSTAT); out: if(p) putbuf(p); if(p1) putbuf(p1); if(f) qunlock(f); ou->fid = in->fid; }