You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules_s/permissions/parse_config.c

313 lines
7.0 KiB

/*
* $Id$
*
* PERMISSIONS module
*
* Copyright (C) 2003 Miklós Tirpák (mtirpak@sztaki.hu)
* Copyright (C) 2006 iptelorg GmbH
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* 2006-08-10: parse_config_file() can return error value (Miklos)
*/
#include <stdio.h>
#include <string.h>
#include "../../sr_module.h"
#include "rule.h"
#include "permissions.h"
#include "parse_config.h"
/*
* parse a comma separated expression list like a, b, c
* return 0 on success, -1 on error
* parsed expressions are returned in **e
*/
static int parse_expression_list(char *str, expression **e)
{
int start=0, i=-1, j=-1, apost=0;
char str2[EXPRESSION_LENGTH];
expression *e1=NULL, *e2;
if (!str || !e) return -1;
*e = NULL;
do {
i++;
switch(str[i]) {
case '"': apost = !apost;
break;
case ',': if (apost) break;
case '\0': /* word found */
while ((str[start] == ' ') || (str[start] == '\t')) start++;
if (str[start] == '"') start++;
j = i-1;
while ((0 < j) && ((str[j] == ' ') || (str[j] == '\t'))) j--;
if ((0 < j) && (str[j] == '"')) j--;
if (start<=j) {
/* valid word */
if (j-start+1 >= EXPRESSION_LENGTH) {
/* error */
LOG(L_ERR, "ERROR: parse_expression_list(): " \
"too long expression, increase EXPRESSION_LENGTH\n");
goto error;
}
strncpy(str2, str+start, j-start+1);
str2[j-start+1] = '\0';
e2 = new_expression(str2);
if (!e2) {
/* memory error */
LOG(L_ERR, "ERROR: parse_expression_list(): " \
"not enough memory\n");
goto error;
}
if (e1) {
/* it is not the first */
e1->next = e2;
e1 = e2;
} else {
/* it is the first */
*e = e1 = e2;
}
} else {
/* parsing error */
LOG(L_ERR, "ERROR: parse_expression_list(): " \
"expression parsing error\n");
goto error;
}
/* for the next word */
start = i+1;
}
} while (str[i] != '\0');
return 0;
error:
if (*e) {
free_expression(*e);
*e = NULL;
}
return -1;
}
/*
* parse a complex expression list like a, b, c EXCEPT d, e
* return 0 on success, -1 on error
* parsed expressions are returned in **e, and exceptions are returned in **e_exceptions
*/
static int parse_expression(char *str, expression **e, expression **e_exceptions)
{
char *except, str2[LINE_LENGTH];
int i=0, l;
if (!str || !e || !e_exceptions) return -1;
except = strstr(str, " EXCEPT ");
if (except) {
/* exception found */
l = except-str;
if (l >= LINE_LENGTH) {
/* error */
LOG(L_ERR, "ERROR: parse_expression(): too long config line, increase LINE_LENGTH\n");
goto error;
}
strncpy(str2, str, l);
str2[l] = '\0';
/* except+8 points to the exception */
if (parse_expression_list(except+8, e_exceptions)) {
/* error */
goto error;
}
} else {
/* no exception */
l = strlen(str);
if (l >= LINE_LENGTH) {
/* error */
LOG(L_ERR, "ERROR: parse_expression(): too long config line, increase LINE_LENGTH\n");
goto error;
}
strncpy(str2, str, l);
str2[l] = '\0';
*e_exceptions = NULL;
}
while ((str2[i] == ' ') || (str2[i] == '\t')) i++;
if (strncmp("ALL", str2+i, 3) == 0) {
*e = NULL;
} else {
if (parse_expression_list(str2+i, e)) {
/* error */
if (*e_exceptions) free_expression(*e_exceptions);
goto error;
}
}
return 0;
error:
*e = *e_exceptions = NULL;
return -1;
}
/*
* parse one line of the config file
* return the rule according to line
*/
static rule *parse_config_line(char *line, int *err)
{
rule *rule1;
expression *left, *left_exceptions, *right, *right_exceptions;
int i=-1, exit=0, apost=0, colon=-1, eval=0;
static char str1[LINE_LENGTH], str2[LINE_LENGTH+1];
*err = 0;
if (!line) return 0;
rule1 = 0;
left = left_exceptions = right = right_exceptions = 0;
while (!exit) {
i++;
switch(line[i]) {
case '"': apost = !apost;
eval = 1;
break;
case ':': if (!apost) colon = i;
eval = 1;
break;
case '#': if (apost) break;
case '\0':
case '\n':
exit = 1;
break;
case ' ': break;
case '\t': break;
default: eval = 1;
}
}
if (eval) {
if ((0<colon) && (colon+1<i)) {
/* valid line */
/* left expression */
strncpy(str1, line, colon);
str1[colon] = '\0';
if (parse_expression(str1, &left, &left_exceptions)) {
/* error */
LOG(L_ERR, "ERROR parsing line: %s\n", line);
goto error;
}
/* right expression */
strncpy(str2, line+colon+1, i-colon-1);
str2[i-colon-1] = '\0';
if (parse_expression(str2, &right, &right_exceptions)) {
/* error */
LOG(L_ERR, "ERROR parsing line: %s\n", line);
goto error;
}
rule1 = new_rule();
if (!rule1) {
LOG(L_ERR, "ERROR: Can't create new rule\n");
goto error;
}
rule1->left = left;
rule1->left_exceptions = left_exceptions;
rule1->right = right;
rule1->right_exceptions = right_exceptions;
return rule1;
} else {
/* error */
LOG(L_ERR, "ERROR parsing line: %s\n", line);
goto error;
}
}
return 0;
error:
if (left) free_expression(left);
if (left_exceptions) free_expression(left_exceptions);
if (right) free_expression(right);
if (right_exceptions) free_expression(right_exceptions);
*err = 1;
return 0;
}
/*
* parse a config file
* return a list of rules
*/
rule *parse_config_file(char *filename, int *err)
{
FILE *file;
char line[LINE_LENGTH+1];
rule *start_rule = NULL, *rule1 = NULL, *rule2 = NULL;
*err = 0;
file = fopen(filename,"r");
if (!file) {
if (safe_file_load) {
LOG(L_ERR, "ERROR: File not found: %s\n", filename);
*err = 1;
} else {
LOG(L_WARN, "WARNING: File not found: %s\n", filename);
}
return NULL;
}
while (fgets(line, LINE_LENGTH, file)) {
rule2 = parse_config_line(line, err);
if (*err) goto error;
if (rule2) {
if (rule1) {
/* it is not the first rule */
rule1->next = rule2;
} else {
/* it is the first rule */
start_rule = rule2;
}
rule1 = rule2;
}
}
error:
fclose(file);
return start_rule; /* returns the linked list */
}