add simple acl parser (not yet integrated and no matcher so far)
This commit is contained in:
@@ -68,8 +68,3 @@ it runs, you can use ldapclient to query a specific record:
|
||||
objectName "cn=Felix von Leitner,o=fefe,c=de"
|
||||
mail:felix-tinyldap@fefe.de
|
||||
|
||||
ldapclient is quite a stupid client. It can only ask for specific
|
||||
records, for example. LDAP also defines complex queries like AND and OR
|
||||
compound queries or substring searches. tinyldap answers those, but to
|
||||
ask those you should install openldap and use the ldapsearch tool that
|
||||
comes with it.
|
||||
|
||||
2
TODO
2
TODO
@@ -25,3 +25,5 @@ Think about a shared calendar in LDAP. Using ISO date format and
|
||||
ordered matching it can be done. Design tinyldap so this actually
|
||||
scales. How would conflict detection and resolution be done?
|
||||
Think about an iCal frontend.
|
||||
|
||||
Make tinyldap a good back-end for blogs and message boards.
|
||||
|
||||
220
acl.c
Normal file
220
acl.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
tinyldap acl syntax:
|
||||
|
||||
acl login-in-as-dn target-dn attrib
|
||||
|
||||
e.g.
|
||||
|
||||
# root@fefe.de can do everything
|
||||
acl dn:cn=root,o=fefe,c=de * +rwdR;
|
||||
# noone can read userPassword
|
||||
acl * * userPassword -r;
|
||||
# but everyone can authenticate using it
|
||||
acl * self +a;
|
||||
# admins at fefe.de can write in their tree
|
||||
acl dn:*ou=admin,o=fefe,c=de dn:*,o=fefe,c=de +rwdR;
|
||||
*/
|
||||
|
||||
#include <buffer.h>
|
||||
#include <stralloc.h>
|
||||
#include <str.h>
|
||||
#include <uint32.h>
|
||||
#include <string.h>
|
||||
#include <errmsg.h>
|
||||
#include <fmt.h>
|
||||
#include <byte.h>
|
||||
|
||||
const char Any[]="*";
|
||||
const char Self[]="self";
|
||||
const char Dn[]="dn";
|
||||
|
||||
enum {
|
||||
acl_read = 1,
|
||||
acl_write = 2,
|
||||
acl_auth = 4,
|
||||
acl_delete = 8,
|
||||
acl_rendn = 16,
|
||||
};
|
||||
|
||||
struct assertion {
|
||||
const char* attr;
|
||||
uint32 where;
|
||||
const char* what;
|
||||
struct assertion* sameas;
|
||||
};
|
||||
|
||||
struct acl {
|
||||
struct assertion login,target;
|
||||
const char* attrib;
|
||||
short may,maynot;
|
||||
struct acl* next;
|
||||
};
|
||||
|
||||
static unsigned long lines;
|
||||
static stralloc x;
|
||||
|
||||
void parseerror() {
|
||||
char buf[FMT_ULONG];
|
||||
buf[fmt_ulong(buf,lines)]=0;
|
||||
die(1,"parse error in line ",buf);
|
||||
}
|
||||
|
||||
int skipws(buffer* in) {
|
||||
char c;
|
||||
for (;;) {
|
||||
if (in->p < in->n && buffer_feed(in)<1) return 0;
|
||||
c=*buffer_peek(in);
|
||||
if (c=='\n') ++lines;
|
||||
if (c==' ' || c=='\n' || c=='\t') {
|
||||
buffer_getc(in,&c);
|
||||
continue;
|
||||
} else if (c=='#') {
|
||||
for (;;) {
|
||||
int r=buffer_getc(in,&c);
|
||||
if (r!=1) return r;
|
||||
if (c=='\n') break;
|
||||
}
|
||||
} else return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parseacldn(buffer* in,struct assertion* a) {
|
||||
int r;
|
||||
/* possible forms:
|
||||
* -> "dn", Any
|
||||
dn:*foo -> "dn", "*foo" */
|
||||
a->sameas=0;
|
||||
if ((r=skipws(in))!=1) return r;
|
||||
stralloc_zero(&x);
|
||||
do {
|
||||
r=buffer_get_token_sa(in,&x," \t",2);
|
||||
if (r!=1) return r;
|
||||
} while (!x.len || x.s[x.len-1]!='\\');
|
||||
stralloc_chop(&x);
|
||||
if (!stralloc_0(&x)) return -1;
|
||||
r=byte_chr(x.s,x.len,':');
|
||||
if (x.s[r]==':') {
|
||||
x.s[r]=0;
|
||||
if (str_equal(x.s,"dn")) {
|
||||
a->attr=Dn;
|
||||
a->what=strdup(x.s+r+1);
|
||||
if (!a->what) return -1;
|
||||
} else {
|
||||
a->attr=malloc(x.len);
|
||||
if (!a->attr) return -1;
|
||||
byte_copy((char*)a->attr,x.len,x.s);
|
||||
a->what=a->attr+r+1;
|
||||
}
|
||||
} else {
|
||||
a->attr=Dn;
|
||||
if (str_equal(x.s,"*"))
|
||||
a->what=Any;
|
||||
else if (str_equal(x.s,"self"))
|
||||
a->what=Self;
|
||||
else {
|
||||
a->what=strdup(x.s);
|
||||
if (!a->what) return -1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parseaclattrib(buffer* in,struct acl* a) {
|
||||
/* possible forms:
|
||||
cn,sn
|
||||
mail
|
||||
*
|
||||
*/
|
||||
int r;
|
||||
a->attrib=0;
|
||||
if ((r=skipws(in))!=1) return r;
|
||||
r=buffer_get_new_token_sa(in,&x," \t",2);
|
||||
if (r!=1) return r;
|
||||
stralloc_chop(&x);
|
||||
if (!stralloc_0(&x)) return -1;
|
||||
if (str_equal(x.s,"*")) {
|
||||
a->attrib=Any;
|
||||
return 1;
|
||||
}
|
||||
return ((a->attrib=strdup(x.s))?1:-1);
|
||||
}
|
||||
|
||||
int parseaclpermissions(buffer* in,struct acl* a) {
|
||||
char c;
|
||||
int r;
|
||||
short* s;
|
||||
a->may=a->maynot=0; s=&a->may;
|
||||
for (;;) {
|
||||
r=buffer_getc(in,&c);
|
||||
if (r<1) return r;
|
||||
switch (c) {
|
||||
case '+': s=&a->may; break;
|
||||
case '-': s=&a->maynot; break;
|
||||
case 'r': *s|=acl_read; break;
|
||||
case 'w': *s|=acl_write; break;
|
||||
case 'a': *s|=acl_auth; break;
|
||||
case 'd': *s|=acl_delete; break;
|
||||
case 'R': *s|=acl_rendn; break;
|
||||
case ' ': case '\t': case '\n': break;
|
||||
case ';': return 1;
|
||||
default: parseerror();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int parseacl(buffer* in,struct acl* a) {
|
||||
int i,r;
|
||||
char c;
|
||||
if ((r=skipws(in))!=1) return r;
|
||||
for (i=0; i<3; ++i)
|
||||
if (buffer_getc(in,&c)!=1 && c!="acl"[i]) parseerror();
|
||||
if ((r=parseacldn(in,&a->login))!=1) return r;
|
||||
if ((r=parseacldn(in,&a->target))!=1) return r;
|
||||
if ((r=parseaclattrib(in,a))!=1) return r;
|
||||
if ((r=parseaclpermissions(in,a))!=1) return r;
|
||||
a->next=0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void fold(struct assertion* a,struct assertion* b) {
|
||||
if (a->sameas || b->sameas) return;
|
||||
if (a->attr==b->attr || str_equal(a->attr,b->attr))
|
||||
if (a->what==b->what || str_equal(a->what,b->what))
|
||||
b->sameas=a;
|
||||
}
|
||||
|
||||
static void optimize(struct acl* a) {
|
||||
struct acl* b;
|
||||
for (; a; a=a->next)
|
||||
for (b=a; b; b=b->next) {
|
||||
fold(&a->login,&b->login);
|
||||
fold(&a->target,&b->target);
|
||||
fold(&a->login,&a->target);
|
||||
fold(&a->login,&b->target);
|
||||
fold(&b->login,&a->target);
|
||||
fold(&b->login,&b->target);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
buffer b;
|
||||
struct acl* root,**next, a;
|
||||
int r;
|
||||
root=0; next=&root;
|
||||
|
||||
if (buffer_mmapread(&b,"acls")==-1) diesys(1,"buffer_mmapread");
|
||||
|
||||
while ((r=parseacl(&b,&a))!=-1) {
|
||||
*next=malloc(sizeof(struct acl));
|
||||
if (!*next) diesys(1,"malloc");
|
||||
**next=a;
|
||||
next=&(*next)->next;
|
||||
if (r==0) break;
|
||||
}
|
||||
if (r==-1) parseerror();
|
||||
|
||||
buffer_close(&b);
|
||||
optimize(root);
|
||||
return 0;
|
||||
}
|
||||
8
acls
Normal file
8
acls
Normal file
@@ -0,0 +1,8 @@
|
||||
# root@fefe.de can do everything
|
||||
acl dn:cn=root,o=fefe,c=de * +rwdR;
|
||||
# noone can read userPassword
|
||||
acl * * userPassword -r;
|
||||
# but everyone can authenticate using it
|
||||
acl * self +a;
|
||||
# admins at fefe.de can write in their tree
|
||||
acl dn:*ou=admin,o=fefe,c=de dn:*,o=fefe,c=de +rwdR;
|
||||
Reference in New Issue
Block a user