diff -r 4d39adda7a38 -r b28cf69f42e8 src/server/daemon/acl.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 +#include + +#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;iacenum;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; +}