/* Copyright (C) Charles Forsyth * See /doc/license/NOTICE.Plan9-9k.txt for details about the licensing. */ /* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio * See /doc/license/gpl-2.0.txt for details about the licensing. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" typedef struct User User; struct User { char* name; char* leader; User* next; int n; char* mem[]; }; enum{ Ulog= 6, Usize= 1<= 0x7F && r < 0xA0 || jehanne_strchr(invalid, r) != nil) r = Runeerror; }else s += jehanne_chartorune(&r, s); if(r == Runeerror) error("invalid character in name"); } } static uint32_t hashpjw(char *s) { uint32_t h, g; h = 0; for(; *s != 0; s++){ h = (h << 4) + (*s&0xFF); g = h & 0xf0000000; if(g != 0) h ^= ((g >> 24) & 0xff) | g; } return h & 0x7FFFFFFF; } static User** lookuser(char *name) { uint32_t h; User **l, *u; h = hashpjw(name) & Umask; for(l = &users.hash[h]; (u = *l) != nil; l = &u->next) if(jehanne_strcmp(u->name, name) == 0) break; return l; } static char* tack(char **p, char *s) { char *o; o = *p; jehanne_strcpy(o, s); *p += jehanne_strlen(o)+1; return o; } void adduser(char *uid, char *leader, int nm, char **mem) { User **l, *u, *v; char *o; int i, nc; if(leader != nil){ if(*leader == '\0') leader = nil; else if(jehanne_strcmp(leader, uid) == 0) leader = uid; } checkname(uid); nc = jehanne_strlen(uid)+1; if(leader != nil && leader != uid){ checkname(leader); nc += jehanne_strlen(leader)+1; } for(i = 0; i < nm; i++){ checkname(mem[i]); nc += jehanne_strlen(mem[i])+1; } v = jehanne_mallocz(sizeof(User)+nm*sizeof(v->mem[0])+nc, 1); if(v == nil) error(Enomem); o = (char*)(v+1)+nm*sizeof(v->mem[0]); v->name = tack(&o, uid); if(leader == nil) v->leader = nil; else if(jehanne_strcmp(v->name, leader) != 0) v->leader = tack(&o, leader); else v->leader = v->name; v->n = nm; for(i = 0; i < nm; i++) v->mem[i] = tack(&o, mem[i]); lock(&users); l = lookuser(uid); u = *l; if(u != nil){ /* replace */ v->next = u->next; jehanne_free(u); } *l = v; unlock(&users); } int deluser(char *name) { User **l, *u; lock(&users); l = lookuser(name); u = *l; if(u == nil){ unlock(&users); return 0; } *l = u->next; unlock(&users); jehanne_free(u); return 1; } static int ismember(char *s, int n, char **mem) { int i; for(i = 0; i < n; i++) if(jehanne_strcmp(s, mem[i]) == 0) return 1; return 0; } int ingroup(char *uid, char *gid) { User *g; if(jehanne_strcmp(uid, gid) == 0) return 1; lock(&users); g = *lookuser(gid); if(g != nil && ismember(uid, g->n, g->mem)){ unlock(&users); return 1; } unlock(&users); return 0; } int leadsgroup(char *uid, char *gid) { User *g; lock(&users); g = *lookuser(gid); if(g != nil){ if(g->leader != nil && jehanne_strcmp(uid, g->leader) == 0 || g->leader == nil && ismember(uid, g->n, g->mem)){ unlock(&users); return 1; } } unlock(&users); return g == nil && jehanne_strcmp(uid, gid) == 0; } char* usersread(void) { int i, m; User *u; Fmt fmt; jehanne_fmtstrinit(&fmt); for(i = 0; i < nelem(users.hash); i++){ lock(&users); for(u = users.hash[i]; u != nil; u = u->next){ jehanne_fmtprint(&fmt, "%q", u->name); if(u->leader != nil || u->n != 0){ jehanne_fmtprint(&fmt, " %q", u->leader != nil? u->leader: ""); for(m = 0; m < u->n; m++) jehanne_fmtprint(&fmt, " %q", u->mem[m]); } jehanne_fmtprint(&fmt, "\n"); } unlock(&users); } return jehanne_fmtstrflush(&fmt); } long userswrite(void *buf, long n) { int i, nf; char *p, *s, *e, *flds[100]; if(n <= 0) return n; if(n > 16*1024) error(Etoobig); p = jehanne_malloc(n+1); if(p == nil) error(Enomem); if(waserror()){ jehanne_free(p); nexterror(); } jehanne_memmove(p, buf, n); p[n] = '\0'; if(p[n-1] != '\n') error("incomplete line"); for(s = p; (e = jehanne_strchr(s, '\n')) != nil; s = e){ *e++ = '\0'; if(*s == '#') continue; nf = jehanne_tokenize(s, flds, nelem(flds)); if(nf == nelem(flds)) error("too many group members"); if(jehanne_strcmp(flds[0], "-") == 0){ for(i = 1; i < nf; i++) deluser(flds[i]); }else if(nf > 1) adduser(flds[0], flds[1], nf-2, flds+2); else if(nf != 0) adduser(flds[0], nil, 0, nil); } poperror(); jehanne_free(p); return n; }