2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct Srv Srv;
|
|
|
|
struct Srv
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
char *owner;
|
|
|
|
ulong perm;
|
|
|
|
Chan *chan;
|
|
|
|
Srv *link;
|
|
|
|
ulong path;
|
|
|
|
};
|
|
|
|
|
|
|
|
static QLock srvlk;
|
|
|
|
static Srv *srv;
|
|
|
|
static int qidpath;
|
|
|
|
|
2012-02-07 23:00:42 +00:00
|
|
|
static Srv*
|
|
|
|
srvlookup(char *name, ulong qidpath)
|
|
|
|
{
|
|
|
|
Srv *sp;
|
2013-06-17 19:58:38 +00:00
|
|
|
|
|
|
|
for(sp = srv; sp != nil; sp = sp->link) {
|
|
|
|
if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
|
2012-02-07 23:00:42 +00:00
|
|
|
return sp;
|
2013-06-17 19:58:38 +00:00
|
|
|
}
|
2012-02-07 23:00:42 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
static int
|
2012-02-07 23:00:42 +00:00
|
|
|
srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Srv *sp;
|
|
|
|
Qid q;
|
|
|
|
|
|
|
|
if(s == DEVDOTDOT){
|
|
|
|
devdir(c, c->qid, "#s", 0, eve, 0555, dp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
qlock(&srvlk);
|
2013-06-17 19:58:38 +00:00
|
|
|
if(name != nil)
|
2012-02-07 23:00:42 +00:00
|
|
|
sp = srvlookup(name, -1);
|
|
|
|
else {
|
2013-06-17 19:58:38 +00:00
|
|
|
for(sp = srv; sp != nil && s > 0; sp = sp->link)
|
2012-02-07 23:00:42 +00:00
|
|
|
s--;
|
|
|
|
}
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) {
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&srvlk);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
mkqid(&q, sp->path, 0, QTFILE);
|
|
|
|
/* make sure name string continues to exist after we release lock */
|
|
|
|
kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
|
|
|
|
devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
|
|
|
|
qunlock(&srvlk);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
srvinit(void)
|
|
|
|
{
|
|
|
|
qidpath = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Chan*
|
|
|
|
srvattach(char *spec)
|
|
|
|
{
|
|
|
|
return devattach('s', spec);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Walkqid*
|
|
|
|
srvwalk(Chan *c, Chan *nc, char **name, int nname)
|
|
|
|
{
|
|
|
|
return devwalk(c, nc, name, nname, 0, 0, srvgen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
srvstat(Chan *c, uchar *db, int n)
|
|
|
|
{
|
|
|
|
return devstat(c, db, n, 0, 0, srvgen);
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
srvname(Chan *c)
|
|
|
|
{
|
|
|
|
Srv *sp;
|
|
|
|
char *s;
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
s = nil;
|
|
|
|
qlock(&srvlk);
|
|
|
|
for(sp = srv; sp != nil; sp = sp->link) {
|
2011-03-30 12:46:40 +00:00
|
|
|
if(sp->chan == c){
|
2013-06-17 19:58:38 +00:00
|
|
|
s = malloc(3+strlen(sp->name)+1);
|
|
|
|
if(s != nil)
|
|
|
|
sprint(s, "#s/%s", sp->name);
|
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2013-06-17 19:58:38 +00:00
|
|
|
}
|
|
|
|
qunlock(&srvlk);
|
|
|
|
return s;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static Chan*
|
|
|
|
srvopen(Chan *c, int omode)
|
|
|
|
{
|
|
|
|
Srv *sp;
|
2013-06-17 19:58:38 +00:00
|
|
|
Chan *nc;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if(c->qid.type == QTDIR){
|
|
|
|
if(omode & ORCLOSE)
|
|
|
|
error(Eperm);
|
|
|
|
if(omode != OREAD)
|
|
|
|
error(Eisdir);
|
|
|
|
c->mode = omode;
|
|
|
|
c->flag |= COPEN;
|
|
|
|
c->offset = 0;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
qlock(&srvlk);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&srvlk);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
sp = srvlookup(nil, c->qid.path);
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp == nil || sp->chan == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Eshutdown);
|
|
|
|
|
|
|
|
if(omode&OTRUNC)
|
2011-08-14 09:11:51 +00:00
|
|
|
error(Eexist);
|
kernel: implement per file descriptor OCEXEC flag, reject ORCLOSE when opening /fd, /srv and /shr
The OCEXEC flag used to be maintained per channel,
making it shared between all the file desciptors.
This has a unexpected side effects with regard to
channel passing drivers such as devdup (/fd),
devsrv (/srv) and devshr (/shr).
For example, opening a /srv file with OCEXEC
makes it impossible to be remounted by exportfs
as it internally does a exec() to mount and
re-export it. There is no way to reset the flag.
This change makes the OCEXEC flag per file descriptor,
so a open with the OCEXEC flag only affects the fd
group of the calling process, and not the channel
itself.
On rfork(RFFDG), the per file descriptor flags get
copied.
On dup(), the per file descriptor flags are reset.
The second modification is that /fd, /srv and /shr
should reject the ORCLOSE flag, as the files that
are returned have already been opend.
2020-12-13 15:04:09 +00:00
|
|
|
if(omode&ORCLOSE)
|
|
|
|
error(Eperm);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
|
|
|
|
error(Eperm);
|
|
|
|
devpermcheck(sp->owner, sp->perm, omode);
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
nc = sp->chan;
|
|
|
|
incref(nc);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&srvlk);
|
|
|
|
poperror();
|
2013-06-17 19:58:38 +00:00
|
|
|
|
|
|
|
cclose(c);
|
|
|
|
return nc;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-08-17 21:27:31 +00:00
|
|
|
static Chan*
|
2011-03-30 12:46:40 +00:00
|
|
|
srvcreate(Chan *c, char *name, int omode, ulong perm)
|
|
|
|
{
|
|
|
|
Srv *sp;
|
|
|
|
|
|
|
|
if(openmode(omode) != OWRITE)
|
|
|
|
error(Eperm);
|
|
|
|
|
2012-02-07 23:00:42 +00:00
|
|
|
if(strlen(name) >= sizeof(up->genbuf))
|
2012-02-08 01:32:03 +00:00
|
|
|
error(Etoolong);
|
2012-02-07 23:00:42 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
sp = smalloc(sizeof *sp);
|
2013-06-17 19:58:38 +00:00
|
|
|
kstrdup(&sp->name, name);
|
|
|
|
kstrdup(&sp->owner, up->user);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
qlock(&srvlk);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&srvlk);
|
2013-06-17 19:58:38 +00:00
|
|
|
free(sp->owner);
|
|
|
|
free(sp->name);
|
|
|
|
free(sp);
|
2011-03-30 12:46:40 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
2013-06-17 19:58:38 +00:00
|
|
|
if(srvlookup(name, -1) != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Eexist);
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
sp->perm = perm&0777;
|
2011-03-30 12:46:40 +00:00
|
|
|
sp->path = qidpath++;
|
2013-06-17 19:58:38 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
c->qid.path = sp->path;
|
2013-06-17 19:58:38 +00:00
|
|
|
c->qid.type = QTFILE;
|
|
|
|
|
|
|
|
sp->link = srv;
|
2011-03-30 12:46:40 +00:00
|
|
|
srv = sp;
|
2013-06-17 19:58:38 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&srvlk);
|
|
|
|
poperror();
|
|
|
|
|
|
|
|
c->flag |= COPEN;
|
|
|
|
c->mode = OWRITE;
|
2013-06-17 19:58:38 +00:00
|
|
|
|
2011-08-17 21:27:31 +00:00
|
|
|
return c;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
srvremove(Chan *c)
|
|
|
|
{
|
|
|
|
Srv *sp, **l;
|
|
|
|
|
|
|
|
if(c->qid.type == QTDIR)
|
|
|
|
error(Eperm);
|
|
|
|
|
|
|
|
qlock(&srvlk);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&srvlk);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
l = &srv;
|
2013-06-17 19:58:38 +00:00
|
|
|
for(sp = *l; sp != nil; sp = *l) {
|
2011-03-30 12:46:40 +00:00
|
|
|
if(sp->path == c->qid.path)
|
|
|
|
break;
|
|
|
|
l = &sp->link;
|
|
|
|
}
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Enonexist);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only eve can remove system services.
|
|
|
|
*/
|
|
|
|
if(strcmp(sp->owner, eve) == 0 && !iseve())
|
|
|
|
error(Eperm);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No removing personal services.
|
|
|
|
*/
|
|
|
|
if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
|
|
|
|
error(Eperm);
|
|
|
|
|
|
|
|
*l = sp->link;
|
2013-06-17 19:58:38 +00:00
|
|
|
sp->link = nil;
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&srvlk);
|
|
|
|
poperror();
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp->chan != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
cclose(sp->chan);
|
|
|
|
free(sp->owner);
|
|
|
|
free(sp->name);
|
|
|
|
free(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
srvwstat(Chan *c, uchar *dp, int n)
|
|
|
|
{
|
|
|
|
char *strs;
|
|
|
|
Srv *sp;
|
2013-06-17 19:58:38 +00:00
|
|
|
Dir d;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if(c->qid.type & QTDIR)
|
|
|
|
error(Eperm);
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
strs = smalloc(n);
|
|
|
|
if(waserror()){
|
|
|
|
free(strs);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
n = convM2D(dp, n, &d, strs);
|
|
|
|
if(n == 0)
|
|
|
|
error(Eshortstat);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qlock(&srvlk);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&srvlk);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
sp = srvlookup(nil, c->qid.path);
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Enonexist);
|
|
|
|
|
|
|
|
if(strcmp(sp->owner, up->user) != 0 && !iseve())
|
|
|
|
error(Eperm);
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
if(d.name != nil && *d.name && strcmp(sp->name, d.name) != 0) {
|
2011-03-30 12:46:40 +00:00
|
|
|
if(strchr(d.name, '/') != nil)
|
|
|
|
error(Ebadchar);
|
2012-02-07 23:00:42 +00:00
|
|
|
if(strlen(d.name) >= sizeof(up->genbuf))
|
2012-02-08 01:32:03 +00:00
|
|
|
error(Etoolong);
|
2011-03-30 12:46:40 +00:00
|
|
|
kstrdup(&sp->name, d.name);
|
|
|
|
}
|
2013-06-17 19:58:38 +00:00
|
|
|
if(d.uid != nil && *d.uid)
|
|
|
|
kstrdup(&sp->owner, d.uid);
|
2013-06-18 20:09:40 +00:00
|
|
|
if(d.mode != ~0UL)
|
|
|
|
sp->perm = d.mode & 0777;
|
2013-06-17 19:58:38 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&srvlk);
|
2013-06-17 19:58:38 +00:00
|
|
|
poperror();
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
free(strs);
|
|
|
|
poperror();
|
2013-06-17 19:58:38 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
srvclose(Chan *c)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* in theory we need to override any changes in removability
|
|
|
|
* since open, but since all that's checked is the owner,
|
|
|
|
* which is immutable, all is well.
|
|
|
|
*/
|
|
|
|
if(c->flag & CRCLOSE){
|
|
|
|
if(waserror())
|
|
|
|
return;
|
|
|
|
srvremove(c);
|
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
srvread(Chan *c, void *va, long n, vlong)
|
|
|
|
{
|
|
|
|
isdir(c);
|
|
|
|
return devdirread(c, va, n, 0, 0, srvgen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
srvwrite(Chan *c, void *va, long n, vlong)
|
|
|
|
{
|
|
|
|
Srv *sp;
|
|
|
|
Chan *c1;
|
|
|
|
int fd;
|
|
|
|
char buf[32];
|
|
|
|
|
|
|
|
if(n >= sizeof buf)
|
2012-02-08 01:32:03 +00:00
|
|
|
error(Etoobig);
|
2011-03-30 12:46:40 +00:00
|
|
|
memmove(buf, va, n); /* so we can NUL-terminate */
|
|
|
|
buf[n] = 0;
|
|
|
|
fd = strtoul(buf, 0, 0);
|
|
|
|
|
|
|
|
c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
|
|
|
|
|
|
|
|
qlock(&srvlk);
|
|
|
|
if(waserror()) {
|
|
|
|
qunlock(&srvlk);
|
|
|
|
cclose(c1);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
if(c1->qid.type & QTAUTH)
|
|
|
|
error("cannot post auth file in srv");
|
|
|
|
sp = srvlookup(nil, c->qid.path);
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Enonexist);
|
|
|
|
|
2013-06-17 19:58:38 +00:00
|
|
|
if(sp->chan != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadusefd);
|
|
|
|
|
|
|
|
sp->chan = c1;
|
2013-06-17 19:58:38 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&srvlk);
|
|
|
|
poperror();
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dev srvdevtab = {
|
|
|
|
's',
|
|
|
|
"srv",
|
|
|
|
|
|
|
|
devreset,
|
|
|
|
srvinit,
|
|
|
|
devshutdown,
|
|
|
|
srvattach,
|
|
|
|
srvwalk,
|
|
|
|
srvstat,
|
|
|
|
srvopen,
|
|
|
|
srvcreate,
|
|
|
|
srvclose,
|
|
|
|
srvread,
|
|
|
|
devbread,
|
|
|
|
srvwrite,
|
|
|
|
devbwrite,
|
|
|
|
srvremove,
|
|
|
|
srvwstat,
|
|
|
|
};
|
2011-05-09 08:32:14 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
srvrenameuser(char *old, char *new)
|
|
|
|
{
|
|
|
|
Srv *sp;
|
|
|
|
|
|
|
|
qlock(&srvlk);
|
2013-06-17 19:58:38 +00:00
|
|
|
for(sp = srv; sp != nil; sp = sp->link) {
|
|
|
|
if(sp->owner != nil && strcmp(old, sp->owner) == 0)
|
2011-05-09 08:32:14 +00:00
|
|
|
kstrdup(&sp->owner, new);
|
2013-06-17 19:58:38 +00:00
|
|
|
}
|
2011-05-09 08:32:14 +00:00
|
|
|
qunlock(&srvlk);
|
|
|
|
}
|