added acls

Thu, 28 Feb 2013 20:00:05 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 28 Feb 2013 20:00:05 +0100
changeset 51
b28cf69f42e8
parent 50
4d39adda7a38
child 52
aced2245fb1c

added acls

src/server/config/acl.c file | annotate | diff | comparison | revisions
src/server/config/acl.h file | annotate | diff | comparison | revisions
src/server/config/conf.c file | annotate | diff | comparison | revisions
src/server/config/objs.mk file | annotate | diff | comparison | revisions
src/server/daemon/acl.c file | annotate | diff | comparison | revisions
src/server/daemon/acl.h file | annotate | diff | comparison | revisions
src/server/daemon/acldata.c file | annotate | diff | comparison | revisions
src/server/daemon/acldata.h file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/objs.mk file | annotate | diff | comparison | revisions
src/server/daemon/ws-fn.c file | annotate | diff | comparison | revisions
src/server/safs/auth.c file | annotate | diff | comparison | revisions
src/server/safs/auth.h file | annotate | diff | comparison | revisions
src/server/safs/pathcheck.c file | annotate | diff | comparison | revisions
src/server/safs/pathcheck.h file | annotate | diff | comparison | revisions
src/server/ucx/map.h file | annotate | diff | comparison | revisions
src/server/ucx/string.c file | annotate | diff | comparison | revisions
src/server/ucx/string.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/acl.c	Thu Feb 28 20:00:05 2013 +0100
@@ -0,0 +1,257 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "acl.h"
+
+ACLFile* load_acl_file(char *file) {
+    FILE *in = fopen(file, "r");
+    if(in == NULL) {
+        return NULL;
+    }
+    
+    ACLFile *conf = malloc(sizeof(ACLFile));
+    conf->parser.parse = acl_parse;
+    conf->file = file;
+    conf->namedACLs = NULL;
+    conf->uriACLs = NULL;
+    conf->pathACLs = NULL;
+    
+    int r = cfg_parse_basic_file((ConfigParser*)conf, in);
+    if(r != 0) {
+        free_acl_file(conf);
+        return NULL;
+    }
+
+    return conf;
+}
+
+void free_acl_file(ACLFile *aclfile) {
+    
+}
+
+int acl_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
+    ACLFile *aclf = p;
+    UcxMempool *mp = aclf->parser.mp;
+    
+    if(sstr_startswith(line, sstr("ACL "))) {
+        sstr_t param = sstrsubs(line, 4);
+        UcxList *plist = cfg_param_list(param, mp); 
+        ACLConfig *acl = OBJ_NEW(mp, ACLConfig);
+        acl->type.ptr = NULL;
+        acl->authparam = NULL;
+        acl->entries = NULL;
+        aclf->cur = acl;
+        
+        sstr_t type = cfg_param_get(plist, sstr("type"));
+        sstr_t name = cfg_param_get(plist, sstr("name"));
+        sstr_t path = cfg_param_get(plist, sstr("path"));
+        sstr_t uri  = cfg_param_get(plist, sstr("uri"));
+        
+        if(name.ptr) {
+            acl->id = name;
+            aclf->namedACLs = ucx_list_append(aclf->namedACLs, acl);
+        } else if(path.ptr) {
+            acl->id = path;
+            aclf->pathACLs = ucx_list_append(aclf->pathACLs, acl);
+        } else if(uri.ptr) {
+            acl->id = uri;
+            aclf->uriACLs = ucx_list_append(aclf->uriACLs, acl);
+        }
+        
+        if(type.ptr) {
+            acl->type = type;
+        }
+    } else if(sstr_startswith(line, sstr("Authenticate "))) {
+        sstr_t param = sstrsubs(line, 13);
+        UcxList *plist = cfg_param_list(param, mp); 
+        aclf->cur->authparam = plist;
+    } else {
+        if(parse_ace(aclf, line)) {
+            // TODO: error
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+int parse_ace(ACLFile *f, sstr_t line) {
+    ACLConfig *cur = f->cur;
+    UcxMempool *mp = f->parser.mp;
+    
+    size_t tkn = 0;
+    sstr_t *tk = sstrsplit(line, sstr(":"), &tkn);
+    if(!tk || tkn < 3) {
+        fprintf(stderr, "parse_ace: to few tokens\n");
+        return 1;
+    }
+    
+    ACEConfig *ace = OBJ_NEW(mp, ACEConfig);
+    memset(ace, 0, sizeof(ACEConfig));
+    
+    /*
+     * first step: determine who is affected by this ace
+     */
+    int n = 0;
+    sstr_t s = tk[0];
+    
+    if(!sstrcmp(s, sstr("user"))) {
+        // next token is the user name
+        s = tk[1];
+        n++;
+        ace->who = sstrdup_mp(mp, s);
+    } else if(!sstrcmp(s, sstr("group"))) {
+        // next token is the group name
+        s = tk[1];
+        n++;
+        ace->who = sstrdup_mp(mp, s);
+        ace->flags = ACLCFG_IDENTIFIER_GROUP;
+    } else if(!sstrcmp(s, sstr("owner@"))) {
+        ace->flags = ACLCFG_OWNER;
+    } else if(!sstrcmp(s, sstr("group@"))) {
+        ace->flags = ACLCFG_GROUP;
+    } else if(!sstrcmp(s, sstr("everyone@"))) {
+        ace->flags = ACLCFG_EVERYONE;
+    } else {
+        // you can specify only the user name in the ace
+        ace->who = sstrdup_mp(mp, s);
+    }
+    
+    n++; //next token
+    
+    /*
+     * get the access mask
+     */
+    
+    if(n >= tkn) {
+        // to few tokens
+        fprintf(stderr, "parse_ace: ace incomplete\n");
+        return 1;
+    }
+    s = tk[n];
+    
+    size_t maskn = 0;
+    sstr_t *accessmask = sstrsplit(s, sstr(","), &maskn);
+    for(int i=0;i<maskn;i++) {
+        sstr_t access = accessmask[i];
+        if(!sstrcmp(access, sstr("read"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_READ;
+        } else if(!sstrcmp(access, sstr("write"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_WRITE;
+        } else if(!sstrcmp(access, sstr("read_data"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_READ_DATA;
+        } else if(!sstrcmp(access, sstr("write_data"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_WRITE_DATA;
+        } else if(!sstrcmp(access, sstr("append"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_APPEND;
+        } else if(!sstrcmp(access, sstr("add_file"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_ADD_FILE;
+        } else if(!sstrcmp(access, sstr("add_subdirectory"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_ADD_SUBDIRECTORY;
+        } else if(!sstrcmp(access, sstr("read_xattr"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_READ_XATTR;
+        } else if(!sstrcmp(access, sstr("write_xattr"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_WRITE_XATTR;
+        } else if(!sstrcmp(access, sstr("execute"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_EXECUTE;
+        } else if(!sstrcmp(access, sstr("delete_child"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_DELETE_CHILD;
+        } else if(!sstrcmp(access, sstr("delete"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_DELETE;
+        } else if(!sstrcmp(access, sstr("read_attributes"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_READ_ATTRIBUTES;
+        } else if(!sstrcmp(access, sstr("write_attributes"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_WRITE_ATTRIBUTES;
+        } else if(!sstrcmp(access, sstr("list"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_LIST;
+        } else if(!sstrcmp(access, sstr("read_acl"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_READ_ACL;
+        } else if(!sstrcmp(access, sstr("write_acl"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_WRITE_ACL;
+        } else if(!sstrcmp(access, sstr("write_owner"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_WRITE_OWNER;
+        } else if(!sstrcmp(access, sstr("synchronize"))) {
+            ace->access_mask = ace->access_mask | ACLCFG_SYNCHRONIZE;
+        }
+    }
+    free(accessmask);
+    n++; // next token
+    
+    /*
+     * get flags (optional) and ace type
+     */
+    
+    int complete = 0;
+    while(n < tkn) {
+        s = tk[n];
+        if(!sstrcmp(s, sstr("allow"))) {
+            ace->type = ACLCFG_TYPE_ALLOWED;
+            complete = 1;
+            break;
+        } else if(!sstrcmp(s, sstr("deny"))) {
+            ace->type = ACLCFG_TYPE_DENIED;
+            complete = 1;
+            break;
+        } else if(!sstrcmp(s, sstr("audit"))) {
+            ace->type = ACLCFG_TYPE_AUDIT;
+            complete = 1;
+            break;
+        } else if(!sstrcmp(s, sstr("alarm"))) {
+            ace->type = ACLCFG_TYPE_ALARM;
+            complete = 1;
+            break;
+        } else {
+            // set flags
+            size_t fln = 0;
+            sstr_t *flags = sstrsplit(s, sstr(","), &fln);
+            for(int i=0;i<fln;i++) {
+                sstr_t flag = flags[i];
+                if(!sstrcmp(flag, sstr("successful_access_flag"))) {
+                    ace->flags = ace->flags | ACLCFG_SUCCESSFUL_ACCESS_FLAG;
+                } else if(!sstrcmp(flag, sstr("failed_access_flag"))) {
+                    ace->flags = ace->flags | ACLCFG_FAILED_ACCESS_ACE_FLAG;
+                }
+                // TODO: other flags
+            }
+            free(flags);
+        }
+        n++;
+    }
+    
+    if(!complete) {
+        fprintf(stderr, "parse_ace: ace incomplete\n");
+        return 1;
+    }
+    
+    cur->entries = ucx_list_append(cur->entries, ace);
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/acl.h	Thu Feb 28 20:00:05 2013 +0100
@@ -0,0 +1,133 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CONFIG_ACL_H
+#define	_CONFIG_ACL_H
+
+#include "conf.h"
+#include <inttypes.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct _acl_conf ACLConfig;
+    
+typedef struct _acl_file {
+    ConfigParser parser;
+    char         *file;
+    UcxList      *namedACLs; // ACLConfig list
+    UcxList      *uriACLs;   // ACLConfig list
+    UcxList      *pathACLs;  // ACLConfig list
+    
+    // temp data
+    ACLConfig    *cur;
+} ACLFile;
+
+struct _acl_conf {
+    sstr_t   id; // name, uri or path
+    sstr_t   type; // webserver ACL or file system ACL
+    UcxList  *authparam; // authentication parameters
+    UcxList  *entries; // ACEConfig list
+};
+
+typedef struct _ace_conf {
+    sstr_t   who;
+    uint32_t access_mask;
+    uint16_t flags;
+    uint16_t type;
+} ACEConfig;
+
+
+/*
+ * the flags are a duplicate of the webserver's acl flags
+ */
+
+/*
+ * access permissions
+ */
+#define ACLCFG_READ_DATA               0x0001
+#define ACLCFG_WRITE_DATA              0x0002
+#define ACLCFG_APPEND                  0x0002
+#define ACLCFG_ADD_FILE                0x0004
+#define ACLCFG_ADD_SUBDIRECTORY        0x0004
+#define ACLCFG_READ_XATTR              0x0008
+#define ACLCFG_WRITE_XATTR             0x0010
+#define ACLCFG_EXECUTE                 0x0020
+#define ACLCFG_DELETE_CHILD            0x0040
+#define ACLCFG_DELETE                  0x0040
+#define ACLCFG_READ_ATTRIBUTES         0x0080
+#define ACLCFG_WRITE_ATTRIBUTES        0x0100
+#define ACLCFG_LIST                    0x0200
+#define ACLCFG_READ_ACL                0x0400
+#define ACLCFG_WRITE_ACL               0x0800
+#define ACLCFG_WRITE_OWNER             0x1000
+#define ACLCFG_SYNCHRONIZE             0x2000
+
+#define ACLCFG_READ \
+        (ACLCFG_READ_DATA|ACLCFG_READ_XATTR|ACLCFG_READ_ATTRIBUTES)
+#define ACLCFG_WRITE \
+        (ACLCFG_WRITE_DATA|ACLCFG_WRITE_XATTR|ACLCFG_WRITE_ATTRIBUTES)
+
+/*
+ * ace flags
+ */
+#define ACLCFG_FILE_INHERIT            0x0001
+#define ACLCFG_DIR_INHERIT             0x0002
+#define ACLCFG_NO_PROPAGATE            0x0004
+#define ACLCFG_INHERIT_ONLY            0x0008
+#define ACLCFG_SUCCESSFUL_ACCESS_FLAG  0x0010
+#define ACLCFG_FAILED_ACCESS_ACE_FLAG  0x0020
+#define ACLCFG_IDENTIFIER_GROUP        0x0040
+#define ACLCFG_OWNER                   0x1000
+#define ACLCFG_GROUP                   0x2000
+#define ACLCFG_EVERYONE                0x4000
+
+/*
+ * ace type
+ */
+#define ACLCFG_TYPE_ALLOWED 0x01
+#define ACLCFG_TYPE_DENIED  0x02
+#define ACLCFG_TYPE_AUDIT   0x03
+#define ACLCFG_TYPE_ALARM   0x04
+
+
+ACLFile* load_acl_file(char *file);
+
+void free_acl_file(ACLFile *aclfile);
+
+
+int acl_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line);
+int parse_ace(ACLFile *f, sstr_t line);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _CONFIG_ACL_H */
+
--- a/src/server/config/conf.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/config/conf.c	Thu Feb 28 20:00:05 2013 +0100
@@ -251,7 +251,7 @@
 }
 
 /*
- * gets from a parameter list a value
+ * gets a value from a parameter
  */
 sstr_t cfg_param_get(UcxList *list, sstr_t name) {
     while(list != NULL) {
--- a/src/server/config/objs.mk	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/config/objs.mk	Thu Feb 28 20:00:05 2013 +0100
@@ -35,6 +35,7 @@
 CONFOBJ += initconf.o
 CONFOBJ += serverconf.o
 CONFOBJ += mimeconf.o
+CONFOBJ += acl.o
 
 CONFOBJS = $(CONFOBJ:%=$(CONF_OBJPRE)%)
 CONFSOURCE = $(CONFOBJ:%.o=config/%.c)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/acl.c	Thu Feb 28 20:00:05 2013 +0100
@@ -0,0 +1,205 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../util/pool.h"
+#include "../safs/auth.h"
+#include "acl.h"
+
+void acllist_createhandle(Session *sn, Request *rq) {
+    ACLListHandle *handle = pool_malloc(sn->pool, sizeof(ACLListHandle));
+    handle->defaultauthdb = NULL;
+    handle->listhead = NULL;
+    handle->listtail = NULL;
+    rq->acllist = handle;
+}
+
+void acllist_append(Session *sn, Request *rq, ACLList *acl) {
+    if(!rq->acllist) {
+        acllist_createhandle(sn, rq);
+    }
+    ACLListHandle *list = rq->acllist;
+    
+    if(!list->defaultauthdb && acl->authdb) {
+        list->defaultauthdb = acl->authdb;
+    }
+    
+    ACLListElm *elm = pool_malloc(sn->pool, sizeof(ACLListElm));
+    elm->acl = acl;
+    elm->next = NULL;
+    if(list->listhead == NULL) {
+        list->listhead = elm;
+        list->listtail = elm;
+    } else {
+        list->listtail->next = elm;
+        list->listtail = elm;
+    }
+}
+
+void acllist_prepend(Session *sn, Request *rq, ACLList *acl) {
+    if(!rq->acllist) {
+        acllist_createhandle(sn, rq);
+    }
+    ACLListHandle *list = rq->acllist;
+    
+    if(!list->defaultauthdb && acl->authdb) {
+        list->defaultauthdb = acl->authdb;
+    }
+    
+    ACLListElm *elm = pool_malloc(sn->pool, sizeof(ACLListElm));
+    elm->acl = acl;
+    elm->next = NULL;
+    if(list->listhead == NULL) {
+        list->listhead = elm;
+        list->listtail = elm;
+    } else {
+        elm->next = list->listhead;
+        list->listhead = elm;
+    }
+}
+
+
+int acl_evaluate(Session *sn, Request *rq, int access_mask) {
+    ACLListHandle *list = rq->acllist;
+    if(!list) {
+        return REQ_PROCEED;
+    }
+    
+    // get user
+    User *user = NULL;
+    if(list->defaultauthdb) {
+        char *usr;
+        char *pw;
+        if(!basicauth_getuser(sn, rq, &usr, &pw)) {
+            user = list->defaultauthdb->get_user(list->defaultauthdb, usr);
+            if(!user) {
+                // wrong user name
+                return REQ_ABORTED;
+            }
+            if(!user->verify_password(user, pw)) {
+                // wrong password
+                return REQ_ABORTED;
+            }
+            // ok - user is authenticated
+        }
+    } else {
+        // TODO
+        return REQ_ABORTED;
+    }
+    
+    // evaluate each acl until one denies access
+    ACLListElm *elm = list->listhead;
+    while(elm) {
+        ACLList *acl = elm->acl;
+        if(!wsacl_check(acl, user, access_mask)) {
+            // the acl denies access
+            
+            if(!user) {
+                pblock_nvinsert(
+                        "www-authenticate",
+                        "Basic realm=\"Webserver\"",
+                        rq->srvhdrs);
+                protocol_status(sn, rq, PROTOCOL_UNAUTHORIZED, NULL);
+            }
+            return REQ_ABORTED;
+        } 
+        elm = elm->next;
+    }
+    
+    // ok - all acls allowed access
+    return REQ_PROCEED;
+}
+
+int wsacl_check(ACLList *acl, User *user, int access_mask) { 
+    int allow = 0;
+    uint32_t allowed_access = 0;
+    // check each access control entry
+    for(int i=0;i<acl->acenum;i++) {
+        ACLEntry *ace = acl->ace[i];
+        int check_access = 0;
+        
+        /*
+         * an ace can affect
+         *   a named user or group (ace->who is set)
+         *   the owner of the resource (ACL_OWNER is set)
+         *   the owning group of the resource (ACL_GROUP is set)
+         *   everyone (ACL_EVERYONE is set)
+         * 
+         * Only one of this conditions should be true. The behavior on
+         * illegal flag combination is undefined. We assume that the acls
+         * are created correctly by the configuration loader.
+         */
+        
+        if(ace->who && user) {
+            // this ace is defined for a named user or group
+            if((ace->flags & ACL_IDENTIFIER_GROUP) == ACL_IDENTIFIER_GROUP) {
+                if(user->check_group(user, ace->who)) {
+                    // the user is in the group
+                    check_access = 1;
+                }
+            } else {
+                if(!strcmp(user->name, ace->who)) {
+                    check_access = 1;
+                }
+            }
+        } else if((ace->flags & ACL_OWNER) == ACL_OWNER) {
+            // TODO
+        } else if((ace->flags & ACL_GROUP) == ACL_GROUP) {
+            // TODO
+        } else if((ace->flags & ACL_EVERYONE) == ACL_EVERYONE) {
+            check_access = 1;
+        }
+        
+        
+        if(check_access) {
+            if(ace->type == ACL_TYPE_ALLOWED) {
+                // add all new access rights 
+                allowed_access = allowed_access |
+                        (access_mask & ace->access_mask);
+                // check if we have all requested rights
+                if((allowed_access & access_mask) == access_mask) {
+                    allow = 1;
+                    break;
+                }
+            } else {
+                // ACL_TYPE_DENIED
+                
+                if((ace->access_mask & access_mask) != 0) {
+                    // access denied
+                    break;
+                }
+            }
+        }
+    }
+    
+    // TODO: events
+    
+    return allow;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/acl.h	Thu Feb 28 20:00:05 2013 +0100
@@ -0,0 +1,154 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ACL_H
+#define	ACL_H
+
+#include "../public/nsapi.h"
+#include "authdb.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct ACLList  ACLList;
+typedef struct ACLEntry ACLEntry;
+// ACLListHandle typedef in nsapi.h
+
+typedef struct ACLListElm ACLListElm;
+
+/*
+ * a wrapper struct for acls
+ * 
+ * TODO: store more than one acl
+ */
+struct ACLListHandle {
+    AuthDB     *defaultauthdb;
+    ACLListElm *listhead;
+    ACLListElm *listtail;
+};
+
+struct ACLListElm {
+    ACLList    *acl;
+    ACLListElm *next;
+};
+
+/*
+ * a access control list
+ * 
+ * Access control is determined by the ace field. The ece field is a separat
+ * list for audit and alarm entries.
+ */
+struct ACLList {
+    AuthDB *authdb;
+    char   *authprompt;
+    ACLEntry **ace; // access control entries
+    ACLEntry **ece; // event control entries (audit/alarm entries)
+    int acenum; // number of aces
+    int ecenum; // number of eces
+};
+
+
+struct ACLEntry {
+    char     *who; // user or group name
+    uint32_t access_mask;
+    uint16_t flags;
+    uint16_t type;
+};
+
+
+/*
+ * access permissions
+ */
+#define ACL_READ_DATA               0x0001
+#define ACL_WRITE_DATA              0x0002
+#define ACL_APPEND                  0x0002
+#define ACL_ADD_FILE                0x0004
+#define ACL_ADD_SUBDIRECTORY        0x0004
+#define ACL_READ_XATTR              0x0008
+#define ACL_WRITE_XATTR             0x0010
+#define ACL_EXECUTE                 0x0020
+#define ACL_DELETE_CHILD            0x0040
+#define ACL_DELETE                  0x0040
+#define ACL_READ_ATTRIBUTES         0x0080
+#define ACL_WRITE_ATTRIBUTES        0x0100
+#define ACL_LIST                    0x0200
+#define ACL_READ_ACL                0x0400
+#define ACL_WRITE_ACL               0x0800
+#define ACL_WRITE_OWNER             0x1000
+#define ACL_SYNCHRONIZE             0x2000
+#define ACL_READ \
+        (ACL_READ_DATA|ACL_READ_XATTR|ACL_READ_ATTRIBUTES)
+#define ACL_WRITE \
+        (ACL_WRITE_DATA|ACL_WRITE_XATTR|ACL_WRITE_ATTRIBUTES)
+
+/*
+ * ace flags
+ */
+#define ACL_FILE_INHERIT            0x0001
+#define ACL_DIR_INHERIT             0x0002
+#define ACL_NO_PROPAGATE            0x0004
+#define ACL_INHERIT_ONLY            0x0008
+#define ACL_SUCCESSFUL_ACCESS_FLAG  0x0010
+#define ACL_FAILED_ACCESS_ACE_FLAG  0x0020
+#define ACL_IDENTIFIER_GROUP        0x0040
+#define ACL_OWNER                   0x1000
+#define ACL_GROUP                   0x2000
+#define ACL_EVERYONE                0x4000
+
+/*
+ * ace type
+ */
+#define ACL_TYPE_ALLOWED 0x01
+#define ACL_TYPE_DENIED  0x02
+#define ACL_TYPE_AUDIT   0x03
+#define ACL_TYPE_ALARM   0x04
+
+
+/*
+ * public API
+ */
+
+// list
+void acllist_append(Session *sn, Request *rq, ACLList *acl);
+void acllist_prepend(Session *sn, Request *rq, ACLList *acl);
+
+// eval
+int acl_evaluate(Session *sn, Request *rq, int access_mask);
+
+
+// private
+int wsacl_check(ACLList *acl, User *user, int access_mask);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* ACL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/acldata.c	Thu Feb 28 20:00:05 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "../config/acl.h"
+#include "config.h"
+
+#include "acldata.h"
+
+ACLData* acl_data_new() {
+    ACLData *dat = malloc(sizeof(ACLData));
+    dat->ref = 1;
+    
+    dat->namedACLs = ucx_map_new(16);
+    
+    return dat;
+}
+
+ACLList* acl_get(ACLData *acldata, char *name) {
+    ACLList *acl = ucx_map_cstr_get(acldata->namedACLs, name);
+    return acl;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/acldata.h	Thu Feb 28 20:00:05 2013 +0100
@@ -0,0 +1,59 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ACLCONF_H
+#define	ACLCONF_H
+
+#include "acl.h"
+#include "../config/acl.h"
+
+#include "../ucx/list.h"
+#include "../ucx/dlist.h"
+#include "../ucx/map.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+    
+typedef struct acl_data {
+    UcxMap  *namedACLs;
+    // TODO
+    
+    uint32_t ref;
+} ACLData;
+
+ACLData* acl_data_new();
+
+ACLList* acl_get(ACLData *acldata, char *name);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* ACLCONF_H */
+
--- a/src/server/daemon/config.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/daemon/config.c	Thu Feb 28 20:00:05 2013 +0100
@@ -501,6 +501,11 @@
     sstr_t objfile = cfg_directivelist_get_str(
             obj->directives,
             sstr("ObjectFile"));
+    sstr_t aclfile = cfg_directivelist_get_str(
+            obj->directives,
+            sstr("ACLFile"));
+    
+    // load the object config file
     sstr_t base = sstr("config/");
     sstr_t file;
     file.length = base.length + objfile.length + 1;
@@ -508,6 +513,7 @@
     file.ptr[file.length] = 0;
     file = sstrncat(2, file, base, objfile);
 
+    // the file is managed by the configuration manager
     ConfigFile *f = cfgmgr_get_file(file);
     if(f == NULL) {
         f = malloc(sizeof(ConfigFile));
@@ -519,6 +525,21 @@
     vs->objectfile = sstrdup(file); // TODO: pool
     vs->objects = (HTTPObjectConfig*)f->data; // TODO: ref
     
+    // load acl config file
+    file.length = base.length + aclfile.length + 1;
+    file.ptr = alloca(file.length);
+    file.ptr[file.length] = 0;
+    file = sstrncat(2, file, base, aclfile);
+    
+    ConfigFile *aclf = cfgmgr_get_file(file);
+    if(aclf == NULL) {
+        aclf = malloc(sizeof(ConfigFile));
+        aclf->file = sstrdup(file);
+        aclf->reload = acl_conf_reload;
+        aclf->reload(aclf, cfg);
+        cfgmgr_attach_file(aclf);
+    }
+    
     // set the access log for the virtual server
     // TODO: don't use always the default
     vs->log = get_default_access_log();
@@ -644,3 +665,91 @@
     file->data = mimemap;
     return 0;
 }
+
+int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg) {
+    ACLFile *aclfile = load_acl_file(file->file.ptr);
+    
+    ACLData *acldata = acl_data_new();
+    UCX_FOREACH(UcxList*, aclfile->namedACLs, elm) {
+        ACLConfig *ac = elm->data;
+        ACLList *acl = acl_config_convert(cfg, ac);
+        ucx_map_sstr_put(acldata->namedACLs, ac->id, acl);
+    }
+    free_acl_file(aclfile);
+    
+    cfg->acls = acldata;
+    
+    struct stat s;
+    if(stat(file->file.ptr, &s) != 0) {
+        perror("object_conf_reload: stat");
+        return -1;
+    }
+    file->last_modified = s.st_mtim.tv_sec;
+    return 0;
+}
+
+ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl) {
+    ACLList *acllist = malloc(sizeof(ACLList));
+    acllist->authdb = NULL;
+    acllist->authprompt = NULL;
+    acllist->ace = NULL;
+    acllist->ece = NULL;
+    
+    size_t s = ucx_list_size(acl->entries);
+    ACLEntry **aces = calloc(s, sizeof(ACLEntry*));
+    ACLEntry **eces = calloc(s, sizeof(ACLEntry*));
+    int ai = 0;
+    int ei = 0;
+    
+    // convert entries
+    UCX_FOREACH(UcxList*, acl->entries, elm) {
+        ACEConfig *acecfg = elm->data;
+        
+        // copy data
+        ACLEntry *ace = malloc(sizeof(ACLEntry));
+        ace->access_mask = acecfg->access_mask;
+        ace->flags = acecfg->flags;
+        ace->type = acecfg->type;
+        ace->who = sstrdup(acecfg->who).ptr;
+        
+        // add the entry to the correct array
+        if(ace->type >= ACL_TYPE_AUDIT) {
+            eces[ei] = ace;
+            ei++;
+        } else {
+            aces[ai] = ace;
+            ai++;
+        }
+    }
+    
+    // create new entrie arrays with perfect fitting size
+    if(ai > 0) {
+        acllist->ace = calloc(ai, sizeof(ACLEntry*));
+    }
+    if(ei > 0) {
+        acllist->ece = calloc(ei, sizeof(ACLEntry*));
+    }
+    memcpy(acllist->ace, aces, ai*sizeof(ACLEntry*));
+    memcpy(acllist->ece, eces, ei*sizeof(ACLEntry*));
+    acllist->acenum = ai;
+    acllist->ecenum = ei;
+    
+    free(aces);
+    free(eces);
+    
+    // get authentication information
+    if(acl->authparam) {
+        sstr_t authdb_str = cfg_param_get(acl->authparam, sstr("authdb"));
+        sstr_t prompt_str = cfg_param_get(acl->authparam, sstr("prompt"));
+        
+        if(authdb_str.ptr) {
+            AuthDB *authdb = ucx_map_sstr_get(cfg->authdbs, authdb_str);
+            acllist->authdb = authdb;
+            if(authdb && prompt_str.ptr) {
+                acllist->authprompt = sstrdup(prompt_str).ptr;
+            }
+        }
+    }
+    
+    return acllist;
+}
--- a/src/server/daemon/config.h	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/daemon/config.h	Thu Feb 28 20:00:05 2013 +0100
@@ -37,6 +37,9 @@
 #include "../config/initconf.h"
 #include "../config/serverconf.h"
 #include "../config/mimeconf.h"
+#include "../config/acl.h"
+
+#include "acldata.h"
 
 #include "../ucx/list.h"
 #include "../ucx/dlist.h"
@@ -56,6 +59,7 @@
     UcxList         *logfiles;
     UcxMap          *authdbs;
     UcxMap          *mimetypes;
+    ACLData         *acls;
     sstr_t          tmp;
     sstr_t          user;
     uint32_t        ref;        // reference counter
@@ -98,11 +102,12 @@
 void cfg_ref(ServerConfiguration *cfg);
 void cfg_unref(ServerConfiguration *cfg);
 
+
 int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg);
-
 HTTPObjectConfig* load_obj_conf(char *file);
-
 int mime_conf_reload(ConfigFile *file, ServerConfiguration *cfg);
+int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg);
+ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl);
 
 
 
--- a/src/server/daemon/objs.mk	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/daemon/objs.mk	Thu Feb 28 20:00:05 2013 +0100
@@ -50,6 +50,8 @@
 DAEMONOBJ += authdb.o
 DAEMONOBJ += ldap_auth.o
 DAEMONOBJ += error.o
+DAEMONOBJ += acl.o
+DAEMONOBJ += acldata.o
 
 # add additional platform dependend objects
 # defined in generated config.mk
--- a/src/server/daemon/ws-fn.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/daemon/ws-fn.c	Thu Feb 28 20:00:05 2013 +0100
@@ -55,6 +55,8 @@
     { "auth-basic", auth_basic, NULL, 0 },
     { "auth-db", auth_db, NULL, 0 },
     { "require-auth", require_auth, NULL, 0},
+    { "append-acl", append_acl, NULL, 0},
+    { "check-acl", check_acl, NULL, 0},
     { "print-message", print_message, NULL, 0},
     { "common-log", common_log, NULL, 0},
     {NULL, NULL, NULL, 0}
--- a/src/server/safs/auth.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/safs/auth.c	Thu Feb 28 20:00:05 2013 +0100
@@ -42,7 +42,7 @@
 
 /* ------------------------------ _uudecode ------------------------------- */
 
-const unsigned char pr2six[256]={
+const unsigned char pr2six[256] = {
     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
     52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
@@ -56,8 +56,7 @@
     64,64,64,64,64,64,64,64,64,64,64,64,64
 };
 
-char *_uudecode(char *bufcoded)
-{
+char *_uudecode(pool_handle_t *pool, char *bufcoded) {
     register char *bufin = bufcoded;
     register unsigned char *bufout;
     register int nprbytes;
@@ -69,7 +68,7 @@
     nprbytes = bufin - bufcoded - 1;
     nbytesdecoded = ((nprbytes+3)/4) * 3;
 
-    bufout = (unsigned char *) malloc(nbytesdecoded + 1);
+    bufout = pool_malloc(pool, nbytesdecoded + 1);
     bufplain = bufout;
 
     bufin = bufcoded;
@@ -96,6 +95,61 @@
     return (char *)bufplain;
 }
 
+int basicauth_getuser(Session *sn, Request *rq, char **user, char **pw) {
+    char *auth = NULL;
+    *user = NULL;
+    *pw = NULL;
+    char *u;
+    char *p;
+    
+    if(request_header("authorization", &auth, sn, rq) == REQ_ABORTED) {
+        return REQ_ABORTED;
+    }
+    
+    if(!auth) {
+        return REQ_NOACTION;
+    }
+    
+    /* Skip leading whitespace */
+    while(*auth && (*auth == ' '))
+        ++auth;
+    if(!(*auth)) {
+        protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL);
+        return REQ_ABORTED;
+    }
+
+    /* Verify correct type */
+    if((strlen(auth) < 6) || strncasecmp(auth, "basic ", 6)) {
+        return REQ_NOACTION;
+    }
+
+    /* Skip whitespace */
+    auth += 6;
+    while(*auth && (*auth == ' ')) {
+        ++auth;
+    }
+
+    if(!*auth) {
+        return REQ_NOACTION;
+    }
+    
+    /* Uuencoded user:password now */
+    if(!(u = _uudecode(sn->pool, auth))) {
+        return REQ_NOACTION;
+    }
+
+    if(!(p = strchr(u, ':'))) {
+        pool_free(sn->pool, u);
+        return REQ_NOACTION;
+    }
+    *p++ = '\0';
+    
+    *user = u;
+    *pw = p;
+    
+    return REQ_PROCEED;
+}
+
 /* ------------------------------ auth_basic ------------------------------ */
 
 int auth_basic(pblock *param, Session *sn, Request *rq)
@@ -114,12 +168,6 @@
      */
     rq->directive_is_cacheable = 1;
 
-    if(request_header("authorization", &auth, sn, rq) == REQ_ABORTED)
-        return REQ_ABORTED;
-
-    if(!auth)
-        return REQ_NOACTION;
-
     type = pblock_findval("auth-type", param);
     pwfile = pblock_findval("userdb", param);
     grpfile = pblock_findval("groupdb", param);
@@ -134,36 +182,11 @@
         return REQ_ABORTED;
     }
 
-    /* Skip leading whitespace */
-    while(*auth && (*auth == ' '))
-        ++auth;
-    if(!(*auth)) {
-        protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL);
-        return REQ_ABORTED;
+    ret = basicauth_getuser(sn, rq, &user, &pw);
+    if(ret != REQ_PROCEED) {
+        return ret;
     }
 
-    /* Verify correct type */
-    if((strlen(auth) < 6) || strncasecmp(auth, "basic ", 6))
-        return REQ_NOACTION;
-
-    /* Skip whitespace */
-    auth += 6;
-    while(*auth && (*auth == ' '))
-        ++auth;
-
-    if(!*auth)
-        return REQ_NOACTION;
-
-    /* Uuencoded user:password now */
-    if(!(user = _uudecode(auth)))
-        return REQ_NOACTION;
-
-    if(!(pw = strchr(user, ':'))) {
-        free(user);
-        return REQ_NOACTION;
-    }
-    *pw++ = '\0';
-
     npb = pblock_create(4);
     pblock_nvinsert("user", user, npb);
     pblock_nvinsert("pw", pw, npb);
@@ -198,27 +221,13 @@
     ret = REQ_PROCEED;
   bye:
     pblock_free(npb);
-    free(user);
     return ret;
 }
 
 int auth_db(pblock *param, Session *sn, Request *rq) {
-    // TODO: reimplement this function and auth_basic to avoid code redundancy
-    
-    //pblock *npb;
-    //pb_param *pp;
-    //int ret;
-
-    char *auth;
     char *db;
     char *user;
-    char *pw;
-    
-    if(request_header("authorization", &auth, sn, rq) == REQ_ABORTED)
-        return REQ_ABORTED;
-
-    if(!auth)
-        return REQ_NOACTION;
+    char *pw; 
 
     db = pblock_findval("db", param);
 
@@ -230,36 +239,11 @@
         return REQ_ABORTED;
     }
 
-    /* Skip leading whitespace */
-    while(*auth && (*auth == ' '))
-        ++auth;
-    if(!(*auth)) {
-        protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL);
-        return REQ_ABORTED;
+    int ret = basicauth_getuser(sn, rq, &user, &pw);
+    if(ret != REQ_PROCEED) {
+        return ret;
     }
 
-    /* Verify correct type */
-    if((strlen(auth) < 6) || strncasecmp(auth, "basic ", 6))
-        return REQ_NOACTION;
-
-    /* Skip whitespace */
-    auth += 6;
-    while(*auth && (*auth == ' '))
-        ++auth;
-
-    if(!*auth)
-        return REQ_NOACTION;
-
-    /* Uuencoded user:password now */
-    if(!(user = _uudecode(auth)))
-        return REQ_NOACTION;
-
-    if(!(pw = strchr(user, ':'))) {
-        free(user);
-        return REQ_NOACTION;
-    }
-    *pw++ = '\0';
-
     // get auth db
     ServerConfiguration *config = session_get_config(sn);
     sstr_t dbname = sstr(db);
@@ -278,7 +262,6 @@
     pblock_nvinsert("auth-user", user, rq->vars);
     pblock_nvinsert("auth-db", db, rq->vars);
     
-    free(user);
     if(auth_user) {
         auth_user->free(auth_user);
     }
--- a/src/server/safs/auth.h	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/safs/auth.h	Thu Feb 28 20:00:05 2013 +0100
@@ -35,6 +35,8 @@
 extern "C" {
 #endif
 
+int basicauth_getuser(Session *sn, Request *rq, char **user, char **pw);
+    
 int auth_basic(pblock *param, Session *sn, Request *rq);
 
 int auth_db(pblock *param, Session *sn, Request *rq);
--- a/src/server/safs/pathcheck.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/safs/pathcheck.c	Thu Feb 28 20:00:05 2013 +0100
@@ -29,6 +29,10 @@
 #include "pathcheck.h"
 
 #include "../util/pblock.h"
+#include "../daemon/config.h"
+#include "../daemon/acl.h"
+#include "../daemon/acldata.h"
+#include "../daemon/session.h"
 
 int require_auth(pblock *pb, Session *sn, Request *rq) {
     char *user = pblock_findkeyval(pb_key_auth_user, rq->vars);
@@ -45,3 +49,34 @@
 
     return REQ_PROCEED;
 }
+
+int append_acl(pblock *pb, Session *sn, Request *rq) {
+    ServerConfiguration *config = session_get_config(sn);
+    
+    char *aclname = pblock_findval("acl", pb);
+    if(aclname) {
+        ACLList *acl = acl_get(config->acls, aclname);
+        if(!acl) {
+            // TODO: error
+            fprintf(stderr, "acl %s not found\n", aclname);
+            return REQ_ABORTED;
+        }
+        
+        acllist_append(sn, rq, acl);
+    }
+    
+    return REQ_NOACTION; // TODO: should return REQ_PROCEED, fix nsapi_pathcheck
+}
+
+
+int check_acl(pblock *pb, Session *sn, Request *rq) {
+    int access_mask = ACL_READ_DATA; // TODO: check method and path
+    
+    int ret = acl_evaluate(sn, rq, access_mask);
+    if(ret == REQ_ABORTED) {
+        // TODO: status, error, ...
+        return REQ_ABORTED;
+    }
+    
+    return REQ_PROCEED;
+}
--- a/src/server/safs/pathcheck.h	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/safs/pathcheck.h	Thu Feb 28 20:00:05 2013 +0100
@@ -37,6 +37,10 @@
 
 int require_auth(pblock *pb, Session *sn, Request *rq);
 
+int append_acl(pblock *pb, Session *sn, Request *rq);
+
+int check_acl(pblock *pb, Session *sn, Request *rq);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/src/server/ucx/map.h	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/ucx/map.h	Thu Feb 28 20:00:05 2013 +0100
@@ -66,9 +66,9 @@
 void* ucx_map_get(UcxMap *map, UcxKey key);
 
 #define ucx_map_sstr_put(m, s, d) ucx_map_put(m, ucx_key(s.ptr, s.length), d)
-#define ucx_map_cstr_put(m, s, d) ucx_map_put(m, ucx_key(s, 1+strlen(s)), d)
+#define ucx_map_cstr_put(m, s, d) ucx_map_put(m, ucx_key(s, strlen(s)), d)
 #define ucx_map_sstr_get(m, s) ucx_map_get(m, ucx_key(s.ptr, s.length))
-#define ucx_map_cstr_get(m, s) ucx_map_get(m, ucx_key(s, 1+strlen(s)))
+#define ucx_map_cstr_get(m, s) ucx_map_get(m, ucx_key(s, strlen(s)))
 
 UcxKey ucx_key(void *data, size_t len);
 
--- a/src/server/ucx/string.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/ucx/string.c	Thu Feb 28 20:00:05 2013 +0100
@@ -173,27 +173,37 @@
 }
 
 // webserver extension
+
+int sstr_startswith(sstr_t string, sstr_t cmp) {
+    sstr_t sub = sstrsubsl(string, 0, cmp.length);
+    if(!sstrcmp(sub, cmp)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
 sstr_t sstrtrim(sstr_t string) {
     sstr_t newstr = string;
-    int nsoff = 0;
-    int l = 1;
-    for(int i=0;i<string.length;i++) {
+    int i;
+    for(i=0;i<string.length;i++) {
         char c = string.ptr[i];
-        if(l) {
-            /* leading whitespace */
-            if(c > 32) {
-                l = 0;
-                nsoff = i;
-                newstr.ptr = &string.ptr[i];
-                newstr.length = string.length - nsoff;
-            }
-        } else {
-            /* trailing whitespace */
-            if(c > 32) {
-                newstr.length = (i - nsoff) + 1;
-            }
+        if(c > 32) {
+            break;
         }
     }
+    
+    newstr.ptr = &string.ptr[i];
+    newstr.length = string.length - i;
+    
+    for(i=newstr.length-1;i>=0;i--) {
+        char c = newstr.ptr[i];
+        if(c > 32) {
+            break;
+        }
+    }
+    newstr.length = i + 1;
+    
     return newstr;
 }
 
--- a/src/server/ucx/string.h	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/ucx/string.h	Thu Feb 28 20:00:05 2013 +0100
@@ -95,6 +95,7 @@
 sstr_t sstrdup(sstr_t s);
 
 // webserver extension
+int sstr_startswith(sstr_t string, sstr_t cmp);
 sstr_t sstrtrim(sstr_t string);
 sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s);
 sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s);
--- a/src/server/webdav/webdav.c	Sat Jan 19 21:52:21 2013 +0100
+++ b/src/server/webdav/webdav.c	Thu Feb 28 20:00:05 2013 +0100
@@ -318,7 +318,9 @@
     //pblock_nvinsert("connection", "close", rq->srvhdrs);
     http_start_response(sn, rq);
     
-    net_write(sn->csd, davrq->out->ptr, davrq->out->length);
+    //printf("%s\n", davrq->out->ptr);
+    ssize_t nr = net_write(sn->csd, davrq->out->ptr, davrq->out->length);
+    //printf("net_write returned: %d\n", r);
     
     
     dav_free_propfind(davrq);

mercurial