dmq_usrloc: init vars earlier to avoid invalid value cleanup on error handling
[sip-router] / modules / permissions / parse_config.c
1 /*
2  * PERMISSIONS module
3  *
4  * Copyright (C) 2003 Miklós Tirpák (mtirpak@sztaki.hu)
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include "../../sr_module.h"
28 #include "rule.h"
29 #include "parse_config.h"
30
31
32 /*
33  * parse a comma separated expression list like a, b, c
34  * return 0 on success, -1 on error
35  * parsed expressions are returned in **e
36  */
37 static int parse_expression_list(char *str, expression **e)
38 {
39         int start=0, i=-1, j=-1, apost=0;
40         char str2[EXPRESSION_LENGTH];
41         expression *e1=NULL, *e2;
42
43         if (!str || !e) return -1;
44
45         *e = NULL;
46         do {
47                 i++;
48                 switch(str[i]) {
49                         case '"':       apost = !apost;
50                                         break;
51                         case ',':       if (apost) break;
52                         case '\0':      /* word found */
53                                         while ((str[start] == ' ') || (str[start] == '\t')) start++;
54                                         if (str[start] == '"') start++;
55                                         j = i-1;
56                                         while ((0 < j) && ((str[j] == ' ') || (str[j] == '\t'))) j--;
57                                         if ((0 < j) && (str[j] == '"')) j--;
58                                         if (start<=j) {
59                                                 /* valid word */
60                                                 if (j-start+1+1>EXPRESSION_LENGTH) {
61                                                         LM_ERR("expression too long "
62                                                                 "<%.*s>(%d)\n",j-start+1,str+start,j-start+1);
63                                                         goto error;
64                                                 }
65                                                 strncpy(str2, str+start, j-start+1);
66                                                 str2[j-start+1] = '\0';
67
68                                                 e2 = new_expression(str2);
69                                                 if (!e2)
70                                                         /* memory error */
71                                                         goto error;
72
73                                                 if (e1) {
74                                                         /* it is not the first */
75                                                         e1->next = e2;
76                                                         e1 = e2;
77                                                 } else {
78                                                         /* it is the first */
79                                                         *e = e1 = e2;
80                                                 }
81                                         } else {
82                                                 /* parsing error */
83                                                 goto error;
84                                         }
85                                         /* for the next word */
86                                         start = i+1;
87                 }
88         } while (str[i] != '\0');
89
90         return 0;
91 error:
92         if (*e) {
93                 free_expression(*e);
94                 *e = NULL;
95         }
96         return -1;
97 }
98
99
100 /*
101  * parse a complex expression list like a, b, c EXCEPT d, e
102  * return 0 on success, -1 on error
103  * parsed expressions are returned in **e, and exceptions are returned in **e_exceptions
104  */
105 static int parse_expression(char *str, expression **e, expression **e_exceptions)
106 {
107         char *except, str2[LINE_LENGTH+1];
108         int  i,j;
109
110         if (!str || !e || !e_exceptions) return -1;
111
112         except = strstr(str, " EXCEPT ");
113         if (except) {
114                 /* exception found */
115                 strncpy(str2, str, except-str);
116                 str2[except-str] = '\0';
117                 /* except+8 points to the exception */
118                 if (parse_expression_list(except+8, e_exceptions)) {
119                         /* error */
120                         *e = *e_exceptions = NULL;
121                         return -1;
122                 }
123         } else {
124                 /* no exception */
125                 strcpy(str2, str);
126                 *e_exceptions = NULL;
127         }
128
129         for( i=0; isspace((int)str2[i]) ; i++);
130         for( j=strlen(str2)-1 ; isspace((int)str2[j]) ; str2[j--]=0);
131
132         if (strcmp("ALL", str2+i) == 0) {
133                 *e = NULL;
134         } else {
135                 if (parse_expression_list(str2+i, e)) {
136                         /* error */
137                         if (*e_exceptions) free_expression(*e_exceptions);
138                         *e = *e_exceptions = NULL;
139                         return -1;
140                 }
141         }
142         return 0;
143 }
144
145
146 /*
147  * parse one line of the config file
148  * return the rule according to line
149  */
150 static rule *parse_config_line(char *line)
151 {
152         rule    *rule1;
153         expression *left, *left_exceptions, *right, *right_exceptions;
154         int     i=-1, exit=0, apost=0, colon=-1, eval=0;
155         static char     str1[LINE_LENGTH], str2[LINE_LENGTH+1];
156
157         if (!line) return 0;
158
159         rule1 = 0;
160         left = left_exceptions = right = right_exceptions = 0;
161
162         while (!exit) {
163                 i++;
164                 switch(line[i]) {
165                         case '"':       apost = !apost;
166                                         eval = 1;
167                                         break;
168
169                         case ':':       if (!apost) colon = i;
170                                         eval = 1;
171                                         break;
172
173                         case '#':       if (apost) break;
174                         case '\0':
175                         case '\n':
176                                         exit = 1;
177                                         break;
178                         case ' ':       break;
179                         case '\t':      break;
180
181                         default:        eval = 1;
182
183                 }
184         }
185
186         if (eval) {
187                 if ((0<colon) && (colon+1<i)) {
188                         /* valid line */
189
190                         /* left expression */
191                         strncpy(str1, line, colon);
192                         str1[colon] = '\0';
193                         if (parse_expression(str1, &left, &left_exceptions)) {
194                                 /* error */
195                                 LM_ERR("failed to parse line-left: %s\n", line);
196                                 goto error;
197                         }
198
199                         /* right expression */
200                         strncpy(str2, line+colon+1, i-colon-1);
201                         str2[i-colon-1] = '\0';
202                         if (parse_expression(str2, &right, &right_exceptions)) {
203                                 /* error */
204                                 LM_ERR("failed to parse line-right: %s\n", line);
205                                 goto error;
206                         }
207
208                         rule1 = new_rule();
209                         if (!rule1) {
210                                 LM_ERR("can't create new rule\n");
211                                 goto error;
212                         }
213
214                         rule1->left = left;
215                         rule1->left_exceptions = left_exceptions;
216                         rule1->right = right;
217                         rule1->right_exceptions = right_exceptions;
218                         return rule1;
219                 } else {
220                         /* error */
221                         LM_ERR("failed to parse line: %s\n", line);
222                 }
223         }
224         return 0;
225
226 error:
227         if (left) free_expression(left);
228         if (left_exceptions) free_expression(left_exceptions);
229
230         if (right) free_expression(right);
231         if (right_exceptions) free_expression(right_exceptions);
232
233         return 0;
234 }
235
236
237 /*
238  * parse a config file
239  * return a list of rules
240  */
241 rule *parse_config_file(char *filename)
242 {
243         FILE    *file;
244         char    line[LINE_LENGTH+1];
245         rule    *start_rule = NULL, *rule1 = NULL, *rule2 = NULL;
246
247         file = fopen(filename,"r");
248         if (!file) {
249                 LM_INFO("file not found: %s\n", filename);
250                 return NULL;
251         }
252
253         while (fgets(line, LINE_LENGTH, file)) {
254                 rule2 = parse_config_line(line);
255                 if (rule2) {
256                         if (rule1) {
257                                 /* it is not the first rule */
258                                 rule1->next = rule2;
259                         } else {
260                                 /* it is the first rule */
261                                 start_rule = rule2;
262                         }
263                         rule1 = rule2;
264                 }
265         }
266
267         fclose(file);
268         return start_rule;      /* returns the linked list */
269 }