Remove memory allocation in olsr_timer_add()
[oonf.git] / src / core / olsr_netaddr_acl.c
1 /*
2  * olsr_netaddr_acl.c
3  *
4  *  Created on: Sep 7, 2011
5  *      Author: rogge
6  */
7
8 #include "common/common_types.h"
9 #include "common/netaddr.h"
10
11 #include "config/cfg_db.h"
12 #include "config/cfg_schema.h"
13 #include "config/cfg.h"
14
15 #include "olsr_netaddr_acl.h"
16
17 static int _handle_control_cmd(struct olsr_netaddr_acl *, const char *);
18 static bool _is_in_array(struct netaddr *, size_t, struct netaddr *);
19
20 static const char *_FIRST_REJECT = "first_reject";
21 static const char *_FIRST_ACCEPT = "first_accept";
22 static const char *_DEFAULT_ACCEPT = "default_accept";
23 static const char *_DEFAULT_REJECT = "default_reject";
24
25 /**
26  * Initialize an ACL object. It will contain no addresses on both
27  * accept and reject list and will be "accept first", "reject default".
28  * @param acl pointer to ACL
29  */
30 void
31 olsr_acl_add(struct olsr_netaddr_acl *acl) {
32   memset(acl, 0, sizeof(acl));
33 }
34
35 void
36 olsr_acl_remove(struct olsr_netaddr_acl *acl) {
37   free(acl->accept);
38   free(acl->reject);
39
40   memset(acl, 0, sizeof(*acl));
41 }
42
43 /**
44  * Initialize an ACL with a list of string parameters.
45  * @param acl pointer to uninitialized ACL
46  * @param array pointer to array of text arguments for ACL
47  * @return -1 if an error happened, 0 otherwise
48  */
49 int
50 olsr_acl_from_strarray(struct olsr_netaddr_acl *acl, const struct const_strarray *value) {
51   size_t accept_count, reject_count;
52   const char *ptr;
53   accept_count = 0;
54   reject_count = 0;
55
56   /* clear acl struct */
57   memset(acl, 0, sizeof(acl));
58
59   /* count number of address entries */
60   FOR_ALL_STRINGS(value, ptr) {
61     if (_handle_control_cmd(acl, ptr) == 0) {
62       continue;
63     }
64
65     if (ptr[0] == '-') {
66       reject_count++;
67     }
68     else {
69       accept_count++;
70     }
71   }
72
73   /* allocate memory */
74   if (accept_count > 0) {
75     acl->accept = calloc(accept_count, sizeof(struct netaddr));
76     if (acl->accept == NULL) {
77       goto from_entry_error;
78     }
79   }
80   if (reject_count > 0) {
81     acl->reject = calloc(reject_count, sizeof(struct netaddr));
82     if (acl->reject == NULL) {
83       goto from_entry_error;
84     }
85   }
86
87   /* read netaddr strings into buffers */
88   FOR_ALL_STRINGS(value, ptr) {
89     const char *addr;
90     if (_handle_control_cmd(acl, ptr) == 0) {
91       continue;
92     }
93
94     addr = ptr;
95     if (*ptr == '-' || *ptr == '+') {
96       addr++;
97     }
98
99     if (*ptr == '-') {
100       if (netaddr_from_string(&acl->reject[acl->reject_count], addr)) {
101         goto from_entry_error;
102       }
103       acl->reject_count++;
104     }
105     else {
106       if (netaddr_from_string(&acl->accept[acl->accept_count], addr)) {
107          goto from_entry_error;
108       }
109       acl->accept_count++;
110     }
111   }
112   return 0;
113
114 from_entry_error:
115   olsr_acl_remove(acl);
116   return -1;
117 }
118
119 /**
120  * Copy one ACL to another one.
121  * @param to pointer to destination ACL
122  * @param from pointer to source ACL
123  * @return -1 if an error happened, 0 otherwise
124  */
125 int
126 olsr_acl_copy(struct olsr_netaddr_acl *to, struct olsr_netaddr_acl *from) {
127   olsr_acl_remove(to);
128   memcpy(to, from, sizeof(*to));
129
130   if (to->accept_count) {
131     to->accept = calloc(to->accept_count, sizeof(struct netaddr));
132     if (to->accept == NULL) {
133       return -1;
134     }
135     memcpy(to->accept, from->accept, to->accept_count * sizeof(struct netaddr));
136   }
137
138   if (to->reject_count) {
139     to->reject = calloc(to->reject_count, sizeof(struct netaddr));
140     if (to->reject == NULL) {
141       return -1;
142     }
143     memcpy(to->reject, from->reject, to->reject_count * sizeof(struct netaddr));
144   }
145   return 0;
146 }
147
148 /**
149  * Check if an address is accepted by an ACL
150  * @param acl pointer to ACL
151  * @param addr pointer to address
152  * @return true if accepted, false otherwise
153  */
154 bool
155 olsr_acl_check_accept(struct olsr_netaddr_acl *acl, struct netaddr *addr) {
156   if (acl->reject_first) {
157     if (_is_in_array(acl->reject, acl->reject_count, addr)) {
158       return false;
159     }
160   }
161
162   if (_is_in_array(acl->accept, acl->accept_count, addr)) {
163     return true;
164   }
165
166   if (!acl->reject_first) {
167     if (_is_in_array(acl->reject, acl->reject_count, addr)) {
168       return false;
169     }
170   }
171
172   return acl->accept_default;
173 }
174
175 /**
176  * Schema entry validator for access control lists.
177  * See CFG_VALIDATE_ACL_*() macros.
178  * @param entry pointer to schema entry
179  * @param section_name name of section type and name
180  * @param value value of schema entry
181  * @param out pointer to autobuffer for validator output
182  * @return 0 if validation found no problems, -1 otherwise
183  */
184 int
185 olsr_acl_validate(const struct cfg_schema_entry *entry,
186     const char *section_name, const char *value, struct autobuf *out) {
187   struct olsr_netaddr_acl dummy;
188
189   if (value == NULL) {
190     cfg_schema_validate_netaddr(entry, section_name, value, out);
191     cfg_append_printable_line(out, "    Additional keywords are %s, %s, %s and %s",
192         _FIRST_ACCEPT, _FIRST_REJECT, _DEFAULT_ACCEPT, _DEFAULT_REJECT);
193     return 0;
194   }
195
196   if (_handle_control_cmd(&dummy, value) == 0) {
197     return 0;
198   }
199
200   if (*value == '+' || *value == '-') {
201     return cfg_schema_validate_netaddr(entry, section_name, value+1, out);
202   }
203   return cfg_schema_validate_netaddr(entry, section_name, value, out);
204 }
205
206 /**
207  * Schema entry binary converter for ACL entries.
208  * See CFG_MAP_ACL_*() macros.
209  * @param s_entry pointer to schema entry.
210  * @param value pointer to value to configuration entry
211  * @param reference pointer to binary target
212  * @return -1 if an error happened, 0 otherwise
213  */
214 int
215 olsr_acl_tobin(const struct cfg_schema_entry *s_entry __attribute__((unused)),
216     const struct const_strarray *value, void *reference) {
217   struct olsr_netaddr_acl *ptr;
218
219   ptr = (struct olsr_netaddr_acl *)reference;
220
221   free(ptr->accept);
222   free(ptr->reject);
223
224   return olsr_acl_from_strarray(ptr, value);
225 }
226
227 /**
228  * Handle the four control text blocks for ACL initialization.
229  * @param acl pointer to ACL
230  * @param cmd pointer to control word
231  * @return -1 if not a control word, 0 if control world was applied
232  */
233 static int
234 _handle_control_cmd(struct olsr_netaddr_acl *acl, const char *cmd) {
235   if (strcasecmp(cmd, _DEFAULT_ACCEPT) == 0) {
236     acl->accept_default = true;
237   }
238   else if (strcasecmp(cmd, _DEFAULT_REJECT) == 0) {
239     acl->accept_default = false;
240   }
241   else if (strcasecmp(cmd, _FIRST_ACCEPT) == 0) {
242     acl->reject_first = false;
243   }
244   else if (strcasecmp(cmd, _FIRST_REJECT) == 0) {
245     acl->reject_first = true;
246   }
247   else {
248     /* no control command, must be an address */
249     return -1;
250   }
251
252   /* was one of the four valid control commands */
253   return 0;
254 }
255
256 /**
257  * @param array pointer to array of addresses and networks
258  * @param length length of array
259  * @param addr pointer of address to be checked
260  * @return true if address is inside list of addresses and networks
261  */
262 static bool
263 _is_in_array(struct netaddr *array, size_t length, struct netaddr *addr) {
264   size_t i;
265
266   for (i=0; i<length; i++) {
267     if (netaddr_is_in_subnet(&array[i], addr)) {
268       return true;
269     }
270   }
271   return false;
272 }