#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);
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)) {
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));
int n =
0;
cxstring s = tk[
0];
if(!cx_strcmp(s, cx_str(
"user"))) {
s = tk[
1];
n++;
ace->who = cx_strdup_a(mp, s);
}
else if(!cx_strcmp(s, cx_str(
"group"))) {
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 {
ace->who = cx_strdup_a(mp, s);
}
n++;
if(n >= tkn) {
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++;
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 {
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;
}
}
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;
}