jehanne/sys/src/kern/port/uidgid.c

271 lines
4.6 KiB
C

/* 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 <giacomo@tesio.it>
* 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<<Ulog,
Umask= Usize-1,
};
static struct{
Lock;
User* hash[Usize];
} users;
static void
checkname(char *s)
{
Rune r;
static char invalid[] = "#:,()";
if(*s == 0 || *s == '-' || *s == '+')
error("illegal name");
while((r = *s) != 0){
if(r < Runeself){
s++;
if(r < 0x20 || r >= 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;
}