Wed, 27 Nov 2024 23:00:07 +0100
add TODO to use a future ucx feature
/* * 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 <string.h> #include "acl.h" #include "logging.h" ACLFile* load_acl_file(const char *file) { FILE *in = fopen(file, "r"); if(in == NULL) { return NULL; } ACLFile *conf = malloc(sizeof(ACLFile)); conf->parser.parse = acl_parse; conf->namedACLs = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); conf->uriACLs = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); conf->pathACLs = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); int r = cfg_parse_basic_file((ConfigParser*)conf, in); if(r != 0) { free_acl_file(conf); return NULL; } fclose(in); return conf; } void free_acl_file(ACLFile *conf) { cxListDestroy(conf->namedACLs); cxListDestroy(conf->uriACLs); cxListDestroy(conf->pathACLs); cxMempoolDestroy(conf->parser.mp->data); // TODO: is there a better way to access the mempool? free(conf); } int acl_parse(void *p, ConfigLine *begin, ConfigLine *end, cxmutstr line) { ACLFile *aclf = p; CxAllocator *mp = aclf->parser.mp; if(cx_strprefix(cx_strcast(line), cx_str("ACL "))) { cxmutstr param = cx_strsubs_m(line, 4); ConfigParam *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; cxmutstr type = cfg_param_get(plist, cx_str("type")); cxmutstr name = cfg_param_get(plist, cx_str("name")); cxmutstr path = cfg_param_get(plist, cx_str("path")); cxmutstr uri = cfg_param_get(plist, cx_str("uri")); if(name.ptr) { acl->id = name; cxListAdd(aclf->namedACLs, acl); } else if(path.ptr) { acl->id = path; cxListAdd(aclf->pathACLs, acl); } else if(uri.ptr) { acl->id = uri; cxListAdd(aclf->uriACLs, acl); } if(type.ptr) { acl->type = type; } } else if(cx_strprefix(cx_strcast(line), cx_str("Authenticate "))) { cxmutstr param = cx_strsubs_m(line, 13); ConfigParam *plist = cfg_param_list(param, mp); aclf->cur->authparam = plist; } else { if(parse_ace(aclf, line)) { // TODO: error return 1; } } return 0; } #define ACE_MAX_TOKENS 2048 int parse_ace(ACLFile *f, cxmutstr line) { ACLConfig *cur = f->cur; CxAllocator *mp = f->parser.mp; cxstring *tk = NULL; ssize_t tkn = cx_strsplit_a(mp, cx_strcast(line), cx_str(":"), ACE_MAX_TOKENS, &tk); if(!tk || tkn < 3) { ws_cfg_log(LOG_FAILURE, "parse_ace: to few tokens: %.*s", (int)line.length, line.ptr); 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; cxstring s = tk[0]; if(!cx_strcmp(s, cx_str("user"))) { // next token is the user name s = tk[1]; n++; ace->who = cx_strdup_a(mp, s); } else if(!cx_strcmp(s, cx_str("group"))) { // next token is the group name s = tk[1]; n++; ace->who = cx_strdup_a(mp, s); ace->flags = ACLCFG_IDENTIFIER_GROUP; } else if(!cx_strcmp(s, cx_str("owner@"))) { ace->flags = ACLCFG_OWNER; } else if(!cx_strcmp(s, cx_str("group@"))) { ace->flags = ACLCFG_GROUP; } else if(!cx_strcmp(s, cx_str("everyone@"))) { ace->flags = ACLCFG_EVERYONE; } else { // you can specify only the user name in the ace ace->who = cx_strdup_a(mp, s); } n++; //next token /* * get the access mask */ if(n >= tkn) { // to few tokens ws_cfg_log(LOG_FAILURE, "parse_ace: ace incomplete"); return 1; } s = tk[n]; cxstring *accessmask = NULL; ssize_t maskn = cx_strsplit_a(mp, s, cx_str(","), ACE_MAX_TOKENS, &accessmask); for(int i=0;i<maskn;i++) { cxstring access = accessmask[i]; ace->access_mask = ace->access_mask | accstr2int(access); } cxFree(mp, accessmask); n++; // next token /* * get flags (optional) and ace type */ int complete = 0; while(n < tkn) { s = tk[n]; if(!cx_strcmp(s, cx_str("allow"))) { ace->type = ACLCFG_TYPE_ALLOWED; complete = 1; break; } else if(!cx_strcmp(s, cx_str("deny"))) { ace->type = ACLCFG_TYPE_DENIED; complete = 1; break; } else if(!cx_strcmp(s, cx_str("audit"))) { ace->type = ACLCFG_TYPE_AUDIT; complete = 1; break; } else if(!cx_strcmp(s, cx_str("alarm"))) { ace->type = ACLCFG_TYPE_ALARM; complete = 1; break; } else { // set flags cxstring *flags = NULL; ssize_t fln = cx_strsplit_a(mp, s, cx_str(","), ACE_MAX_TOKENS, &flags); for(int i=0;i<fln;i++) { cxstring flag = flags[i]; if(!cx_strcmp(flag, cx_str("successful_access_flag"))) { ace->flags = ace->flags | ACLCFG_SUCCESSFUL_ACCESS_FLAG; } else if(!cx_strcmp(flag, cx_str("failed_access_flag"))) { ace->flags = ace->flags | ACLCFG_FAILED_ACCESS_ACE_FLAG; } // TODO: other flags } free(flags); } n++; } if(!complete) { ws_cfg_log(LOG_FAILURE, "parse_ace: ace incomplete"); return 1; } CFG_ACE_ADD(&cur->entries, ace); return 0; } uint32_t accstr2int(cxstring access) { uint32_t val = 0; if(!cx_strcmp(access, cx_str("read"))) { val = ACLCFG_READ; } else if(!cx_strcmp(access, cx_str("write"))) { val = ACLCFG_WRITE; } else if(!cx_strcmp(access, cx_str("read_data"))) { val = ACLCFG_READ_DATA; } else if(!cx_strcmp(access, cx_str("write_data"))) { val = ACLCFG_WRITE_DATA; } else if(!cx_strcmp(access, cx_str("append"))) { val = ACLCFG_APPEND; } else if(!cx_strcmp(access, cx_str("add"))) { val = ACLCFG_ADD_FILE; } else if(!cx_strcmp(access, cx_str("add_file"))) { val = ACLCFG_ADD_FILE; } else if(!cx_strcmp(access, cx_str("add_subdirectory"))) { val = ACLCFG_ADD_SUBDIRECTORY; } else if(!cx_strcmp(access, cx_str("read_xattr"))) { val = ACLCFG_READ_XATTR; } else if(!cx_strcmp(access, cx_str("write_xattr"))) { val = ACLCFG_WRITE_XATTR; } else if(!cx_strcmp(access, cx_str("execute"))) { val = ACLCFG_EXECUTE; } else if(!cx_strcmp(access, cx_str("delete_child"))) { val = ACLCFG_DELETE_CHILD; } else if(!cx_strcmp(access, cx_str("delete"))) { val = ACLCFG_DELETE; } else if(!cx_strcmp(access, cx_str("read_attributes"))) { val = ACLCFG_READ_ATTRIBUTES; } else if(!cx_strcmp(access, cx_str("write_attributes"))) { val = ACLCFG_WRITE_ATTRIBUTES; } else if(!cx_strcmp(access, cx_str("list"))) { val = ACLCFG_LIST; } else if(!cx_strcmp(access, cx_str("read_acl"))) { val = ACLCFG_READ_ACL; } else if(!cx_strcmp(access, cx_str("write_acl"))) { val = ACLCFG_WRITE_ACL; } else if(!cx_strcmp(access, cx_str("write_owner"))) { val = ACLCFG_WRITE_OWNER; } else if(!cx_strcmp(access, cx_str("synchronize"))) { val = ACLCFG_SYNCHRONIZE; } return val; }