summaryrefslogtreecommitdiff
path: root/sys/src/cmd/hjfs/auth.c
diff options
context:
space:
mode:
authoraiju <aiju@phicode.de>2012-08-07 17:57:04 +0200
committeraiju <aiju@phicode.de>2012-08-07 17:57:04 +0200
commitb21b9ba89cf66a8fac6f94efb79cfb425a2c4df2 (patch)
tree42047f997cda3eddec9faeafeb74435cc72a4786 /sys/src/cmd/hjfs/auth.c
parentef1c1863051d0530a31b291f4e334ee7601c318c (diff)
added hjfs
Diffstat (limited to 'sys/src/cmd/hjfs/auth.c')
-rw-r--r--sys/src/cmd/hjfs/auth.c508
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;
+}