Thu, 28 Feb 2013 20:00:05 +0100
added acls
--- /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);