271 lines
4.6 KiB
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;
|
|
}
|