ref: 285644aadb1b58735651a5068703372f8fc9adac
dir: /user.c/
#include "all.h" static User *lruuser; /* least recently used user */ static RWLock userslock; char userserrmsg[Nuserserrmsg]; int checkname9p2(char* name) { char *p; /* * Return length of string if valid, 0 if not. */ if(name == nil) return 0; for(p = name; *p != 0; p++){ if((*p & 0xFF) <= 040) return 0; } return p-name; } int baduname(char *name) { int n; if((n = checkname9p2(name)) == 0 || n+1 > Userlen || strchr(name,'-') || (strlen(name) == 1 && name[0] == '\0')){ dprint("mafs: bad user name %s\n", name); return 1; } return 0; } User * leastid(User *us) { User *u; if(us == nil) return nil; for(u = us; u->prev != nil; u = u->prev) ; return u; } s16 lookupid(char *name) { User *u; s16 id; rlock(&userslock); for(u = leastid(lruuser); u != nil; u = u->next) if(strcmp(u->name, name) == 0) break; if(u == nil) id = 0; else id = u->id; chkrunlock(&userslock); return id; } /* there is a chance that u->name could be free'ed. Hence, always call this with an rlock(&userslock) */ char * username(s16 uid, char *username) { User *u; char *ret; ret = nil; rlock(&userslock); for(u = leastid(lruuser); u != nil; u = u->next){ if(u->id == uid){ if(username == nil) username = emalloc9p(Userlen); /* potential for a leak */ snprint(username, Userlen, "%s", u->name); ret = username; break; } } chkrunlock(&userslock); return ret; } int ingroup(s16 uid, s16 gid, int locked) { User *u; s16 i, found; found = 0; if(locked == 0) rlock(&userslock); if(uid == gid){ found = 1; goto Found; } for(u = leastid(lruuser); u != nil; u = u->next){ if(u->id == gid){ for(i = 0; i < u->nmembers; i++){ if(u->members[i] == uid){ found = 1; break; } } break; } } Found: if(locked == 0) chkrunlock(&userslock); return found; } /* used by wstat */ int leadgroup(s16 uid, s16 gid) { User *u; int ret; if(uid == gid) return 1; rlock(&userslock); for(u = leastid(lruuser); u != nil; u = u->next) if(u->id == gid){ if(u->lid == uid){ ret = 1; goto Unlock; } if(u->lid == 0){ ret = ingroup(uid, gid, 1); goto Unlock; } ret = 0; goto Unlock; } ret = 0; Unlock: chkrunlock(&userslock); return ret; } void freeusers(User *us) { User *u, *tmp; if(us == nil) return; u = leastid(us); while(u != nil){ if(u->members != nil) free(u->members); tmp = u; u = u->next; free(tmp); } } /* used by the parseusers(). No locking needed. */ s16 lookforid(User *us, char *name) { User *u; s16 id; for(u = leastid(us); u != nil; u = u->next) if(strcmp(u->name, name) == 0) break; if(u == nil) id = 0; else id = u->id; return id; } User * lookforuser(User *us, s16 uid) { User *u; for(u = leastid(us); u != nil; u = u->next) if(u->id == uid) return u; return nil; } char * lookforname(User *us, s16 uid) { User *u; for(u = leastid(us); u != nil; u = u->next) if(u->id == uid) return u->name; return nil; } int adduser(User *us, int id, char *name, User **up) { User *u, *prevu, *new; if(name == nil) return snprint(userserrmsg, Nuserserrmsg-1, "invalid name"); if(baduname(name)) return snprint(userserrmsg, Nuserserrmsg-1, "invalid name"); for(u = leastid(us); u != nil; u = u->next){ if(u->id == id){ return snprint(userserrmsg, Nuserserrmsg-1, "mafs: duplicate user ID %d (name %q)\n", id, u->name); }else if(strcmp(u->name, name) == 0){ return snprint(userserrmsg, Nuserserrmsg-1, "mafs: duplicate user name %q (id %d)\n", name, u->id); } } new = emalloc9p(sizeof(User)); new->id = id; new->nmembers = 0; strncpy(new->name, name, Userlen); *up = new; if(us == nil) return 0; for(prevu = u = leastid(us); u != nil && u->id < id; u = u->next){ prevu = u; } /* at the top/last */ if(u == nil){ prevu->next = new; new->prev = prevu; return 0; } if(u->prev != nil) u->prev->next = new; new->next = u; new->prev = u->prev; u->prev = new; return 0; } void addmember(User *us, User *u, char *memname) { s16 x; int i; if(us == nil || u == nil || memname == nil) return; x = lookforid(us, memname); if(x > 0){ /* check for duplicate members */ for(i=0; i<u->nmembers; i++) if(x == u->members[i]) return; if(i == u->nmembers){ if(u->members == nil){ u->nalloc = 1; u->members = emalloc9p(u->nalloc*sizeof(s16)); }else if(u->nmembers == u->nalloc){ u->nalloc++; u->members = erealloc9p(u->members, u->nalloc*sizeof(s16)); } u->members[u->nmembers++] = x; } } } int addmembers(User *us, User *u, char *members) { char *p, *ep; char memname[Userlen]; if(u == nil) return snprint(userserrmsg, Nuserserrmsg-1, "invalid user"); p = members; while((ep = strchr(p, ',')) != nil){ if(ep-p >= Userlen) return snprint(userserrmsg, Nuserserrmsg-1, "memname too long"); else if(ep-p > 0){ *ep = '\0'; strncpy(memname, p, ep-p); memname[ep-p] = '\0'; if(memname != nil){ if(baduname(memname)) return snprint(userserrmsg, Nuserserrmsg-1, "bad memname"); addmember(us, u, memname); } } p = ep+1; } if(p != nil && p[0] != '\0'){ if(baduname(p)) return snprint(userserrmsg, Nuserserrmsg-1, "last memname bad"); addmember(us, u, p); } return 0; } int addleader(User *us, User *u, char *leader) { if(u == nil) return snprint(userserrmsg, Nuserserrmsg-1, "invalid user"); if(leader == nil || leader[0] == '\0' || baduname(leader)) u->lid = 0; else if(strcmp(u->name, leader) == 0) u->lid = u->id; else u->lid = lookforid(us, leader); return 0; } /* (uid:name:leader:member1,member2,...\n)+ first parse are the names, then, parse again to add the leader and members to the group. */ s32 parseusers(User **usp, s8 *raw, u64 usize) { char *p, *ep, *line; char *flds[5]; User *u, *us; s32 i; s32 rv; u = us = nil; p = raw; while(p-raw <= usize && (ep = strchr(p, '\n')) != nil){ /* skip blank lines or empty lines of :::*/ if(ep-p > 4){ line = emalloc9p(ep-p+1); memcpy(line, p, ep-p); if(getfields(line, flds, 4, 0, ":") != 4){ free(line); dprint("invalid user data"); freeusers(us); return Einvusers; } if((rv = adduser(us, atoi(flds[0]), flds[1], &u)) != 0){ free(line); dprint("invalid adduser"); freeusers(us); return rv; } if(us == nil && u != nil) *usp = us = u; free(line); } p = ep+1; } if(us == nil) return Enousers; p = raw; while((ep = strchr(p, '\n')) != nil){ /* skip blank lines or empty lines of ::::*/ if(ep-p > 4){ line = emalloc9p(ep-p+1); memcpy(line, p, ep-p); if(getfields(line, flds, 4, 0, ":") != 4){ free(line); dprint("invalid user data"); freeusers(us); return Einvusers; } u = lookforuser(us, atoi(flds[0])); if((rv = addleader(us, u, flds[2])) != 0){ free(line); dprint("invalid addmembers"); freeusers(us); return rv; } if((rv = addmembers(us, u, flds[3])) != 0){ free(line); dprint("invalid addmembers %s\n", Nuserserrmsg); freeusers(us); return rv; } free(line); } p = ep+1; } if(chatty9p > 2) for(u = leastid(us); u != nil; u = u->next){ dprint("%d:%s:%d(%s):", u->id, u->name, u->lid, lookforname(us, u->lid)); for(i = 0; i<u->nmembers; i++) dprint(" %d(%s)", u->members[i], lookforname(us, u->lid)); dprint("\n"); } *usp = us; return 0; } void usersinit(void) { Iobuf *ubuf; s8 *buf; u64 usize; User *us; int rv; ubuf = egetmetachk(Bdusersinuse, Breadonly, Tdentry, Qpusersinuse); usize = ubuf->d->size+1; buf = emalloc9p(usize); putbuf(ubuf, 0); if(waserror()){ free(buf); nexterror(); } readfile(Bdusersinuse, Qpusersinuse, buf, usize, 0); if((rv=parseusers(&us, buf, usize)) != 0) error("could not parse /a/users/inuse rv %d\n", rv); poperror(); free(buf); lruuser = us; } /* read from /a/user/staging check that the contents are valid check that -1 is the first entry TODO check that 0 is the next entry TODO write the contents to /a/users/inuse lruuser points to these new contents */ void syncusers(void) { Iobuf *ubuf; s8 *buf; u64 usize; User *us, *old; ubuf = egetmetachk(Bdusersstaging, Breadonly, Tdentry, Qpusersstaging); usize = ubuf->d->size+1; buf = emalloc9p(usize); putbuf(ubuf, 0); if(waserror()){ free(buf); nexterror(); } readfile(Bdusersstaging, Qpusersstaging, buf, usize, 0); if(parseusers(&us, buf, usize) != 0) error("could not parse /a/users/staging\n"); wlock(&userslock); old = lruuser; if(waserror()){ wunlock(&userslock); nexterror(); } writefile(Bdusersinuse, Qpusersinuse, -1, buf, usize, 0); lruuser = us; poperror(); wunlock(&userslock); freeusers(old); poperror(); free(buf); }