src/server/daemon/acl.c

changeset 51
b28cf69f42e8
child 52
aced2245fb1c
--- /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;
+}

mercurial