diff options
author | aiju <aiju@phicode.de> | 2012-08-07 17:57:04 +0200 |
---|---|---|
committer | aiju <aiju@phicode.de> | 2012-08-07 17:57:04 +0200 |
commit | b21b9ba89cf66a8fac6f94efb79cfb425a2c4df2 (patch) | |
tree | 42047f997cda3eddec9faeafeb74435cc72a4786 /sys/src/cmd/hjfs/auth.c | |
parent | ef1c1863051d0530a31b291f4e334ee7601c318c (diff) |
added hjfs
Diffstat (limited to 'sys/src/cmd/hjfs/auth.c')
-rw-r--r-- | sys/src/cmd/hjfs/auth.c | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/sys/src/cmd/hjfs/auth.c b/sys/src/cmd/hjfs/auth.c new file mode 100644 index 000000000..efd026066 --- /dev/null +++ b/sys/src/cmd/hjfs/auth.c @@ -0,0 +1,508 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +typedef struct User User; +typedef struct PUser PUser; + +enum { USERMAX = 64 }; + +struct User { + short uid; + char name[USERMAX]; + short lead; + int nmemb; + short *memb; +}; + +struct PUser { + short uid; + char name[USERMAX]; + char lead[USERMAX]; + int nmemb; + char (*memb)[USERMAX]; +}; + +User udef[] = { + {-1, "adm", -1, 0, nil}, + {0, "none", -1, 0, nil}, + {1, "tor", 1, 0, nil}, + {2, "glenda", 2, 0, nil}, + {10000, "sys", NOUID, 0, nil}, + {10001, "map", 10001, 0, nil}, + {10002, "doc", NOUID, 0, nil}, + {10003, "upas", 10003, 0, nil}, + {10004, "font", NOUID, 0, nil}, +}; + +static int +validuser(char *n) +{ + char *p; + + if(*n == 0) + return 0; + for(p = n; *p != 0; p++) + if((uchar) *p < ' ' || strchr("?=+-/:", *p) != nil) + return 0; + return n - p < USERMAX; +} + +static void +usersparseline(char *l, PUser **u, int *nu) +{ + PUser v; + char *f[5], *r, *s; + int c; + + if(*l == 0 || *l == '#') + return; + c = getfields(l, f, 5, 0, ":"); + if(c < 4) + return; + v.uid = strtol(f[0], &r, 10); + if(*r != 0) + return; + if(!validuser(f[1]) || *f[2] != 0 && !validuser(f[2])) + return; + strcpy(v.name, f[1]); + strcpy(v.lead, f[2]); + v.memb = nil; + v.nmemb = 0; + r = f[3]; + while(r != nil && *r != 0){ + s = strchr(r, ','); + if(s != nil) + *s = 0; + if(!validuser(r)){ + free(v.memb); + return; + } + v.memb = realloc(v.memb, (v.nmemb + 1) * USERMAX); + strcpy(v.memb[v.nmemb++], r); + if(s == nil) + r = nil; + else + r = s + 1; + } + *u = realloc(*u, (*nu + 1) * sizeof(PUser)); + memcpy(&(*u)[(*nu)++], &v, sizeof(PUser)); +} + +static int +puserlook(PUser *u, int nu, char *name) +{ + PUser *v; + + if(*name == 0) + return NOUID; + for(v = u; v < u + nu; v++) + if(strcmp(v->name, name) == 0) + return v->uid; + return NOUID; +} + +static int +uidcomp(void *a, void *b) +{ + short *aa, *bb; + + aa = a; + bb = b; + return *aa - *bb; +} + +static int +usercomp(void *a, void *b) +{ + User *aa, *bb; + + aa = a; + bb = b; + return aa->uid - bb->uid; +} + +int +usersload(Fs *fs, Chan *ch) +{ + char *buf, *p, *q; + int bufl, i, j, rc, nu; + PUser *u; + User *v; + + buf = nil; + bufl = 0; + u = nil; + v = nil; + nu = 0; + for(;;){ + if((bufl & 1023) == 0) + buf = realloc(buf, bufl + 1024); + rc = chanread(ch, buf + bufl, 1024, bufl); + if(rc < 0) + goto err; + if(rc == 0) + break; + bufl += rc; + } + if(buf == nil) + goto done; + buf[bufl] = 0; + for(p = buf; q = strchr(p, '\n'); p = q + 1){ + *q = 0; + usersparseline(p, &u, &nu); + } + usersparseline(p, &u, &nu); + free(buf); + if(nu == 0) + goto done; + v = emalloc(sizeof(User) * nu); + for(i = 0; i < nu; i++){ + v[i].uid = u[i].uid; + strcpy(v[i].name, u[i].name); + v[i].lead = puserlook(u, nu, u[i].lead); + v[i].nmemb = u[i].nmemb; + v[i].memb = emalloc(sizeof(short) * v[i].nmemb); + for(j = 0; j < v[i].nmemb; j++) + v[i].memb[j] = puserlook(u, nu, u[i].memb[j]); + qsort(v[i].memb, v[i].nmemb, sizeof(ushort), uidcomp); + } + qsort(v, nu, sizeof(User), usercomp); +done: + wlock(&fs->udatal); + if(fs->udata != nil){ + for(i = 0; i < fs->nudata; i++) + free(((User *)fs->udata)[i].memb); + free(fs->udata); + } + fs->udata = v; + fs->nudata = nu; + wunlock(&fs->udatal); + return 0; +err: + free(buf); + return -1; +} + +int +userssave(Fs *fs, Chan *ch) +{ + User *u, *v; + int nu, i; + char buf[512], *p, *e; + uvlong off; + + rlock(&fs->udatal); + u = fs->udata; + if(u == nil){ + u = udef; + nu = nelem(udef); + }else + nu = fs->nudata; + off = 0; + for(v = u; v < u + nu; v++){ + p = buf; + e = buf + sizeof(buf); + p = seprint(p, e, "%d:%s:", v->uid, v->name); + if(v->lead != NOUID) + p = strecpy(p, e, uid2name(fs, v->lead)); + if(p < e) + *p++ = ':'; + for(i = 0; i < v->nmemb; i++){ + if(v->memb[i] == NOUID) + continue; + if(p < e && i > 0) + *p++ = ','; + p = strecpy(p, e, uid2name(fs, v->memb[i])); + } + *p++ = '\n'; + if(ch == nil) + write(2, buf, p - buf); + else if(chanwrite(ch, buf, p - buf, off) < p - buf) + goto err; + off += p - buf; + } + runlock(&fs->udatal); + return 0; +err: + runlock(&fs->udatal); + return -1; +} + +static User * +lookupuid(Fs *fs, short uid) +{ + User *u; + int i, j, k; + + u = fs->udata; + i = 0; + j = fs->nudata; + if(u == nil){ + u = udef; + j = nelem(udef); + } + if(j == 0) + return nil; + while(i < j){ + k = (i + j) / 2; + if(u[k].uid < uid) + i = k + 1; + else + j = k; + } + if(u[i].uid == uid) + return &u[i]; + return nil; +} + +int +ingroup(Fs *fs, short uid, short gid, int leader) +{ + User *g; + int i, j, k; + + if(uid == gid) + return 1; + rlock(&fs->udatal); + g = lookupuid(fs, gid); + if(g == nil) + goto nope; + if(g->lead == uid) + goto yes; + if(leader && g->lead != NOUID) + goto nope; + if(g->nmemb == 0) + goto nope; + i = 0; + j = g->nmemb; + while(i < j){ + k = (i + j) / 2; + if(g->memb[k] < uid) + i = k + 1; + else + j = k; + } + if(g->memb[i] == uid) + goto yes; +nope: + runlock(&fs->udatal); + return 0; +yes: + runlock(&fs->udatal); + return 1; +} + +int +permcheck(Fs *fs, Dentry *d, short uid, int mode) +{ + int perm; + + if((fs->flags & FSNOPERM) != 0) + return 1; + perm = d->mode & 0777; + if(d->uid == uid) + perm >>= 6; + else if(ingroup(fs, uid, d->gid, 0)) + perm >>= 3; + switch(mode & 3){ + case OREAD: + return (perm & 4) != 0; + case OWRITE: + return (perm & 2) != 0; + case OEXEC: + return (perm & 1) != 0; + case ORDWR: + return (perm & 5) == 5; + } + return 0; +} + +char * +uid2name(Fs *fs, short uid) +{ + User *u; + char *s; + + rlock(&fs->udatal); + u = lookupuid(fs, uid); + if(u == nil) + s = smprint("%d", uid); + else + s = strdup(u->name); + runlock(&fs->udatal); + return s; +} + +int +name2uid(Fs *fs, char *name, short *uid) +{ + char *r; + User *u, *v; + + *uid = strtol(name, &r, 10); + if(*r == 0) + return 1; + rlock(&fs->udatal); + u = fs->udata; + v = u + fs->nudata; + if(u == nil){ + u = udef; + v = udef + nelem(udef); + } + for(; u < v; u++) + if(strcmp(u->name, name) == 0){ + *uid = u->uid; + runlock(&fs->udatal); + return 1; + } + runlock(&fs->udatal); + werrstr(Einval); + return -1; +} + +static void +createuserdir(Fs *fs, char *name, short uid) +{ + Chan *ch; + Buf *b, *c; + Dentry *d; + FLoc f; + + ch = chanattach(fs, 0); + if(ch == nil) + return; + ch->uid = -1; + if(chanwalk(ch, "usr") <= 0 || (ch->loc->type & QTDIR) == 0){ + direrr: + chanclunk(ch); + return; + } + chbegin(ch); + if(willmodify(ch->fs, ch->loc, 0) < 0){ + direrr1: + chend(ch); + goto direrr; + } + b = getbuf(ch->fs->d, ch->loc->blk, TDENTRY, 0); + if(b == nil) + goto direrr1; + if(newentry(ch->fs, ch->loc, b, name, &f) <= 0){ + direrr2: + putbuf(b); + goto direrr1; + } + modified(ch, &b->de[ch->loc->deind]); + c = getbuf(ch->fs->d, f.blk, TDENTRY, 0); + if(c == nil) + goto direrr2; + d = &c->de[f.deind]; + memset(d, 0, sizeof(Dentry)); + strcpy(d->name, name); + d->uid = uid; + d->muid = uid; + d->gid = uid; + d->mode = DALLOC | 0775; + if(newqid(fs, &d->path) < 0){ + direrr3: + putbuf(c); + goto direrr2; + } + d->type = QTDIR; + d->atime = time(0); + d->mtime = d->atime; + c->op |= BDELWRI; + goto direrr3; +} + +int +cmdnewuser(int argc, char **argv) +{ + short uid, gid; + User *u, *v; + Fs *fs; + int resort, createdir, i, j; + extern Fs *fsmain; + + if(argc < 2) + return -9001; + if(!validuser(argv[1])){ + werrstr(Einval); + return -1; + } + fs = fsmain; + resort = 0; + createdir = 0; + wlock(&fs->udatal); + if(fs->udata == nil){ + wunlock(&fs->udatal); + werrstr("newuser: no user database"); + return -1; + } + uid = 0; + gid = 10000; + for(u = fs->udata; u < fs->udata + fs->nudata; u++){ + if(strcmp(u->name, argv[1]) == 0) + goto found; + if(u->uid == uid) + uid++; + if(u->uid == gid) + gid++; + } + resort = 1; + fs->udata = realloc(fs->udata, sizeof(User) * (fs->nudata + 1)); + u = fs->udata + fs->nudata++; + strcpy(u->name, argv[1]); + u->nmemb = 0; + u->memb = nil; + u->uid = gid; + u->lead = NOUID; + if(argc == 2 || strcmp(argv[2], ":") != 0){ + u->lead = u->uid = uid; + createdir = 1; + } +found: + for(i = 2; i < argc; i++){ + if(strcmp(argv[i], ":") == 0) + continue; + if(*argv[i] != '+' && *argv[i] != '-' && *argv[i] != '='){ + if(!validuser(argv[i])) + goto erropt; + strcpy(u->name, argv[i]); + continue; + } + for(v = fs->udata; v < fs->udata + fs->nudata; v++) + if(strcmp(v->name, argv[i] + 1) == 0) + break; + if(v == fs->udata + fs->nudata) + goto erropt; + if(*argv[i] == '='){ + u->lead = v->uid; + continue; + } + for(j = 0; j < u->nmemb && u->memb[j] < v->uid; j++) + ; + if(*argv[i] == '-'){ + if(u->memb[j] != v->uid) + goto erropt; + memmove(&u->memb[j], &u->memb[j + 1], sizeof(short) * (u->nmemb - j - 1)); + u->memb = realloc(u->memb, sizeof(short) * --u->nmemb); + }else{ + u->memb = realloc(u->memb, sizeof(short) * ++u->nmemb); + memmove(&u->memb[j + 1], &u->memb[j], sizeof(short) * (u->nmemb - j - 1)); + u->memb[j] = v->uid; + } + continue; + erropt: + dprint("hjfs: newuser: ignoring erroneous option %s\n", argv[i]); + } + if(resort) + qsort(fs->udata, fs->nudata, sizeof(User), usercomp); + wunlock(&fs->udatal); + writeusers(fs); + if(createdir) + createuserdir(fs, argv[2], uid); + return 1; +} |