UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "acl.h" 34 #include "logging.h" 35 36 ACLFile* load_acl_file(const char *file) { 37 FILE *in = fopen(file, "r"); 38 if(in == NULL) { 39 return NULL; 40 } 41 42 ACLFile *conf = malloc(sizeof(ACLFile)); 43 conf->parser.parse = acl_parse; 44 conf->namedACLs = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); 45 conf->uriACLs = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); 46 conf->pathACLs = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS); 47 48 int r = cfg_parse_basic_file((ConfigParser*)conf, in); 49 if(r != 0) { 50 free_acl_file(conf); 51 return NULL; 52 } 53 54 fclose(in); 55 56 return conf; 57 } 58 59 void free_acl_file(ACLFile *conf) { 60 cxListDestroy(conf->namedACLs); 61 cxListDestroy(conf->uriACLs); 62 cxListDestroy(conf->pathACLs); 63 cxMempoolDestroy(conf->parser.mp->data); // TODO: is there a better way to access the mempool? 64 free(conf); 65 } 66 67 int acl_parse(void *p, ConfigLine *begin, ConfigLine *end, cxmutstr line) { 68 ACLFile *aclf = p; 69 CxAllocator *mp = aclf->parser.mp; 70 71 if(cx_strprefix(cx_strcast(line), cx_str("ACL "))) { 72 cxmutstr param = cx_strsubs_m(line, 4); 73 ConfigParam *plist = cfg_param_list(param, mp); 74 ACLConfig *acl = OBJ_NEW(mp, ACLConfig); 75 acl->type.ptr = NULL; 76 acl->authparam = NULL; 77 acl->entries = NULL; 78 aclf->cur = acl; 79 80 cxmutstr type = cfg_param_get(plist, cx_str("type")); 81 cxmutstr name = cfg_param_get(plist, cx_str("name")); 82 cxmutstr path = cfg_param_get(plist, cx_str("path")); 83 cxmutstr uri = cfg_param_get(plist, cx_str("uri")); 84 85 if(name.ptr) { 86 acl->id = name; 87 cxListAdd(aclf->namedACLs, acl); 88 } else if(path.ptr) { 89 acl->id = path; 90 cxListAdd(aclf->pathACLs, acl); 91 } else if(uri.ptr) { 92 acl->id = uri; 93 cxListAdd(aclf->uriACLs, acl); 94 } 95 96 if(type.ptr) { 97 acl->type = type; 98 } 99 } else if(cx_strprefix(cx_strcast(line), cx_str("Authenticate "))) { 100 cxmutstr param = cx_strsubs_m(line, 13); 101 ConfigParam *plist = cfg_param_list(param, mp); 102 aclf->cur->authparam = plist; 103 } else { 104 if(parse_ace(aclf, line)) { 105 // TODO: error 106 return 1; 107 } 108 } 109 110 return 0; 111 } 112 113 #define ACE_MAX_TOKENS 2048 114 115 int parse_ace(ACLFile *f, cxmutstr line) { 116 ACLConfig *cur = f->cur; 117 CxAllocator *mp = f->parser.mp; 118 119 cxstring *tk = NULL; 120 ssize_t tkn = cx_strsplit_a(mp, cx_strcast(line), cx_str(":"), ACE_MAX_TOKENS, &tk); 121 if(!tk || tkn < 3) { 122 ws_cfg_log(LOG_FAILURE, "parse_ace: to few tokens: %.*s", (int)line.length, line.ptr); 123 return 1; 124 } 125 126 ACEConfig *ace = OBJ_NEW(mp, ACEConfig); 127 memset(ace, 0, sizeof(ACEConfig)); 128 129 /* 130 * first step: determine who is affected by this ace 131 */ 132 int n = 0; 133 cxstring s = tk[0]; 134 135 if(!cx_strcmp(s, cx_str("user"))) { 136 // next token is the user name 137 s = tk[1]; 138 n++; 139 ace->who = cx_strdup_a(mp, s); 140 } else if(!cx_strcmp(s, cx_str("group"))) { 141 // next token is the group name 142 s = tk[1]; 143 n++; 144 ace->who = cx_strdup_a(mp, s); 145 ace->flags = ACLCFG_IDENTIFIER_GROUP; 146 } else if(!cx_strcmp(s, cx_str("owner@"))) { 147 ace->flags = ACLCFG_OWNER; 148 } else if(!cx_strcmp(s, cx_str("group@"))) { 149 ace->flags = ACLCFG_GROUP; 150 } else if(!cx_strcmp(s, cx_str("everyone@"))) { 151 ace->flags = ACLCFG_EVERYONE; 152 } else { 153 // you can specify only the user name in the ace 154 ace->who = cx_strdup_a(mp, s); 155 } 156 157 n++; //next token 158 159 /* 160 * get the access mask 161 */ 162 163 if(n >= tkn) { 164 // to few tokens 165 ws_cfg_log(LOG_FAILURE, "parse_ace: ace incomplete"); 166 return 1; 167 } 168 s = tk[n]; 169 170 cxstring *accessmask = NULL; 171 ssize_t maskn = cx_strsplit_a(mp, s, cx_str(","), ACE_MAX_TOKENS, &accessmask); 172 for(int i=0;i<maskn;i++) { 173 cxstring access = accessmask[i]; 174 ace->access_mask = ace->access_mask | accstr2int(access); 175 } 176 cxFree(mp, accessmask); 177 n++; // next token 178 179 /* 180 * get flags (optional) and ace type 181 */ 182 183 int complete = 0; 184 while(n < tkn) { 185 s = tk[n]; 186 if(!cx_strcmp(s, cx_str("allow"))) { 187 ace->type = ACLCFG_TYPE_ALLOWED; 188 complete = 1; 189 break; 190 } else if(!cx_strcmp(s, cx_str("deny"))) { 191 ace->type = ACLCFG_TYPE_DENIED; 192 complete = 1; 193 break; 194 } else if(!cx_strcmp(s, cx_str("audit"))) { 195 ace->type = ACLCFG_TYPE_AUDIT; 196 complete = 1; 197 break; 198 } else if(!cx_strcmp(s, cx_str("alarm"))) { 199 ace->type = ACLCFG_TYPE_ALARM; 200 complete = 1; 201 break; 202 } else { 203 // set flags 204 cxstring *flags = NULL; 205 ssize_t fln = cx_strsplit_a(mp, s, cx_str(","), ACE_MAX_TOKENS, &flags); 206 for(int i=0;i<fln;i++) { 207 cxstring flag = flags[i]; 208 if(!cx_strcmp(flag, cx_str("successful_access_flag"))) { 209 ace->flags = ace->flags | ACLCFG_SUCCESSFUL_ACCESS_FLAG; 210 } else if(!cx_strcmp(flag, cx_str("failed_access_flag"))) { 211 ace->flags = ace->flags | ACLCFG_FAILED_ACCESS_ACE_FLAG; 212 } 213 // TODO: other flags 214 } 215 free(flags); 216 } 217 n++; 218 } 219 220 if(!complete) { 221 ws_cfg_log(LOG_FAILURE, "parse_ace: ace incomplete"); 222 return 1; 223 } 224 225 CFG_ACE_ADD(&cur->entries, ace); 226 227 return 0; 228 } 229 230 uint32_t accstr2int(cxstring access) { 231 uint32_t val = 0; 232 if(!cx_strcmp(access, cx_str("read"))) { 233 val = ACLCFG_READ; 234 } else if(!cx_strcmp(access, cx_str("write"))) { 235 val = ACLCFG_WRITE; 236 } else if(!cx_strcmp(access, cx_str("read_data"))) { 237 val = ACLCFG_READ_DATA; 238 } else if(!cx_strcmp(access, cx_str("write_data"))) { 239 val = ACLCFG_WRITE_DATA; 240 } else if(!cx_strcmp(access, cx_str("append"))) { 241 val = ACLCFG_APPEND; 242 } else if(!cx_strcmp(access, cx_str("add"))) { 243 val = ACLCFG_ADD_FILE; 244 } else if(!cx_strcmp(access, cx_str("add_file"))) { 245 val = ACLCFG_ADD_FILE; 246 } else if(!cx_strcmp(access, cx_str("add_subdirectory"))) { 247 val = ACLCFG_ADD_SUBDIRECTORY; 248 } else if(!cx_strcmp(access, cx_str("read_xattr"))) { 249 val = ACLCFG_READ_XATTR; 250 } else if(!cx_strcmp(access, cx_str("write_xattr"))) { 251 val = ACLCFG_WRITE_XATTR; 252 } else if(!cx_strcmp(access, cx_str("execute"))) { 253 val = ACLCFG_EXECUTE; 254 } else if(!cx_strcmp(access, cx_str("delete_child"))) { 255 val = ACLCFG_DELETE_CHILD; 256 } else if(!cx_strcmp(access, cx_str("delete"))) { 257 val = ACLCFG_DELETE; 258 } else if(!cx_strcmp(access, cx_str("read_attributes"))) { 259 val = ACLCFG_READ_ATTRIBUTES; 260 } else if(!cx_strcmp(access, cx_str("write_attributes"))) { 261 val = ACLCFG_WRITE_ATTRIBUTES; 262 } else if(!cx_strcmp(access, cx_str("list"))) { 263 val = ACLCFG_LIST; 264 } else if(!cx_strcmp(access, cx_str("read_acl"))) { 265 val = ACLCFG_READ_ACL; 266 } else if(!cx_strcmp(access, cx_str("write_acl"))) { 267 val = ACLCFG_WRITE_ACL; 268 } else if(!cx_strcmp(access, cx_str("write_owner"))) { 269 val = ACLCFG_WRITE_OWNER; 270 } else if(!cx_strcmp(access, cx_str("synchronize"))) { 271 val = ACLCFG_SYNCHRONIZE; 272 } 273 return val; 274 } 275