Branch data Line data Source code
1 : : /**
2 : : * \file lib/fko_message.c
3 : : *
4 : : * \brief Set/Get the spa message (access req/command/etc) based on the current spa data.
5 : : */
6 : :
7 : : /* Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
8 : : * Copyright (C) 2009-2015 fwknop developers and contributors. For a full
9 : : * list of contributors, see the file 'CREDITS'.
10 : : *
11 : : * License (GNU General Public License):
12 : : *
13 : : * This program is free software; you can redistribute it and/or
14 : : * modify it under the terms of the GNU General Public License
15 : : * as published by the Free Software Foundation; either version 2
16 : : * of the License, or (at your option) any later version.
17 : : *
18 : : * This program is distributed in the hope that it will be useful,
19 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : : * GNU General Public License for more details.
22 : : *
23 : : * You should have received a copy of the GNU General Public License
24 : : * along with this program; if not, write to the Free Software
25 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 : : * USA
27 : : *
28 : : *****************************************************************************
29 : : */
30 : : #include "fko_common.h"
31 : : #include "fko_message.h"
32 : : #include "fko.h"
33 : :
34 : : static int
35 : 493213 : have_allow_ip(const char *msg)
36 : : {
37 : 493213 : const char *ndx = msg;
38 : : char ip_str[MAX_IPV4_STR_LEN];
39 : 493213 : int dot_ctr = 0, char_ctr = 0;
40 : 493213 : int res = FKO_SUCCESS;
41 : :
42 [ + + ]: 3905707 : while(*ndx != ',' && *ndx != '\0')
43 : : {
44 : 3516570 : ip_str[char_ctr] = *ndx;
45 : 3516570 : char_ctr++;
46 [ + + ]: 3516570 : if(char_ctr >= MAX_IPV4_STR_LEN)
47 : : {
48 : : res = FKO_ERROR_INVALID_ALLOW_IP;
49 : : break;
50 : : }
51 [ + + ]: 3514363 : if(*ndx == '.')
52 : : dot_ctr++;
53 [ + + ]: 2335829 : else if(isdigit(*ndx) == 0)
54 : : {
55 : : res = FKO_ERROR_INVALID_ALLOW_IP;
56 : : break;
57 : : }
58 : 3412494 : ndx++;
59 : : }
60 : :
61 [ + + ]: 493213 : if(char_ctr < MAX_IPV4_STR_LEN)
62 : 491006 : ip_str[char_ctr] = '\0';
63 : : else
64 : : res = FKO_ERROR_INVALID_ALLOW_IP;
65 : :
66 [ + + ]: 493213 : if(res == FKO_SUCCESS)
67 [ + + ]: 389137 : if (! is_valid_ipv4_addr(ip_str, strlen(ip_str)))
68 : 14405 : res = FKO_ERROR_INVALID_ALLOW_IP;
69 : :
70 : 493213 : return(res);
71 : : }
72 : :
73 : : static int
74 : 489218 : have_port(const char *msg)
75 : : {
76 : 489218 : const char *ndx = msg;
77 : 489218 : char port_str[MAX_PORT_STR_LEN+1] = {0};
78 : 489218 : int startlen = strnlen(msg, MAX_SPA_MESSAGE_SIZE);
79 : 489218 : int port_str_len=0, i=0, is_err;
80 : :
81 [ + - ]: 489218 : if(startlen == MAX_SPA_MESSAGE_SIZE)
82 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_PORT_MISSING);
83 : :
84 : : /* Must have at least one digit for the port number
85 : : */
86 [ + + ]: 489218 : if(isdigit(*ndx) == 0)
87 : : return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
88 : :
89 [ + + ]: 1879253 : while(*ndx != '\0' && *ndx != ',')
90 : : {
91 : 1460361 : port_str_len++;
92 [ + + ][ + + ]: 1460361 : if((isdigit(*ndx) == 0) || (port_str_len > MAX_PORT_STR_LEN))
93 : : return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
94 : 1391585 : port_str[i] = *ndx;
95 : 1391585 : ndx++;
96 : 1391585 : i++;
97 : : }
98 : 418892 : port_str[i] = '\0';
99 : :
100 : 418892 : strtol_wrapper(port_str, 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
101 [ + + ]: 418892 : if(is_err != FKO_SUCCESS)
102 : : return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
103 : :
104 : 418871 : return FKO_SUCCESS;
105 : : }
106 : :
107 : : /* Set the SPA message type.
108 : : */
109 : : int
110 : 873278 : fko_set_spa_message_type(fko_ctx_t ctx, const short msg_type)
111 : : {
112 : : #if HAVE_LIBFIU
113 [ + + ]: 873278 : fiu_return_on("fko_set_spa_message_type_init",
114 : : FKO_ERROR_CTX_NOT_INITIALIZED);
115 : : #endif
116 : : /* Must be initialized
117 : : */
118 [ + + ][ + - ]: 873275 : if(!CTX_INITIALIZED(ctx))
119 : : return FKO_ERROR_CTX_NOT_INITIALIZED;
120 : :
121 : : #if HAVE_LIBFIU
122 [ + + ]: 872429 : fiu_return_on("fko_set_spa_message_type_val",
123 : : FKO_ERROR_INVALID_DATA_MESSAGE_TYPE_VALIDFAIL);
124 : : #endif
125 [ + + ]: 872426 : if(msg_type < 0 || msg_type >= FKO_LAST_MSG_TYPE)
126 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_TYPE_VALIDFAIL);
127 : :
128 : 868382 : ctx->message_type = msg_type;
129 : :
130 : 868382 : ctx->state |= FKO_SPA_MSG_TYPE_MODIFIED;
131 : :
132 : 868382 : return(FKO_SUCCESS);
133 : : }
134 : :
135 : : /* Return the SPA message type.
136 : : */
137 : : int
138 : 7129 : fko_get_spa_message_type(fko_ctx_t ctx, short *msg_type)
139 : : {
140 : :
141 : : #if HAVE_LIBFIU
142 [ + + ]: 7129 : fiu_return_on("fko_get_spa_message_type_init",
143 : : FKO_ERROR_CTX_NOT_INITIALIZED);
144 : : #endif
145 : :
146 : : /* Must be initialized
147 : : */
148 [ + + ][ + - ]: 7127 : if(!CTX_INITIALIZED(ctx))
149 : : return FKO_ERROR_CTX_NOT_INITIALIZED;
150 : :
151 [ + + ]: 6559 : if(msg_type == NULL)
152 : : return(FKO_ERROR_INVALID_DATA);
153 : :
154 : : #if HAVE_LIBFIU
155 [ + + ]: 6491 : fiu_return_on("fko_get_spa_message_type_val", FKO_ERROR_INVALID_DATA);
156 : : #endif
157 : :
158 : 6489 : *msg_type = ctx->message_type;
159 : :
160 : 6489 : return(FKO_SUCCESS);
161 : : }
162 : :
163 : : /* Set the SPA MESSAGE data
164 : : */
165 : : int
166 : 2590 : fko_set_spa_message(fko_ctx_t ctx, const char * const msg)
167 : : {
168 : 2590 : int res = FKO_ERROR_UNKNOWN;
169 : :
170 : : /* Context must be initialized.
171 : : */
172 [ + + ][ + - ]: 2590 : if(!CTX_INITIALIZED(ctx))
173 : : return FKO_ERROR_CTX_NOT_INITIALIZED;
174 : :
175 : : /* Gotta have a valid string.
176 : : */
177 [ + + ][ + + ]: 2560 : if(msg == NULL || strnlen(msg, MAX_SPA_MESSAGE_SIZE) == 0)
178 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_EMPTY);
179 : :
180 : : /* --DSS XXX: Bail out for now. But consider just
181 : : * truncating in the future...
182 : : */
183 [ + + ]: 2507 : if(strnlen(msg, MAX_SPA_MESSAGE_SIZE) == MAX_SPA_MESSAGE_SIZE)
184 : : return(FKO_ERROR_DATA_TOO_LARGE);
185 : :
186 : : /* Basic message type and format checking...
187 : : */
188 [ + + ]: 2498 : if(ctx->message_type == FKO_COMMAND_MSG)
189 : 56 : res = validate_cmd_msg(msg);
190 : : else
191 : 2442 : res = validate_access_msg(msg);
192 : :
193 [ + + ]: 2498 : if(res != FKO_SUCCESS)
194 : : return(res);
195 : :
196 : : /* Just in case this is a subsequent call to this function. We
197 : : * do not want to be leaking memory.
198 : : */
199 [ + + ]: 2416 : if(ctx->message != NULL)
200 : 186 : free(ctx->message);
201 : :
202 : 2416 : ctx->message = strdup(msg);
203 : :
204 : 2416 : ctx->state |= FKO_DATA_MODIFIED;
205 : :
206 [ + - ]: 2416 : if(ctx->message == NULL)
207 : : return(FKO_ERROR_MEMORY_ALLOCATION);
208 : :
209 : 2416 : return(FKO_SUCCESS);
210 : : }
211 : :
212 : : /* Return the SPA message data.
213 : : */
214 : : int
215 : 5545 : fko_get_spa_message(fko_ctx_t ctx, char **msg)
216 : : {
217 : :
218 : : #if HAVE_LIBFIU
219 [ + + ]: 5545 : fiu_return_on("fko_get_spa_message_init", FKO_ERROR_CTX_NOT_INITIALIZED);
220 : : #endif
221 : :
222 : : /* Must be initialized
223 : : */
224 [ + + ][ + - ]: 5543 : if(!CTX_INITIALIZED(ctx))
225 : : return(FKO_ERROR_CTX_NOT_INITIALIZED);
226 : :
227 [ + + ]: 5391 : if(msg == NULL)
228 : : return(FKO_ERROR_INVALID_DATA);
229 : :
230 : : #if HAVE_LIBFIU
231 [ + + ]: 5323 : fiu_return_on("fko_get_spa_message_val", FKO_ERROR_INVALID_DATA);
232 : : #endif
233 : :
234 : 5321 : *msg = ctx->message;
235 : :
236 : 5321 : return(FKO_SUCCESS);
237 : : }
238 : :
239 : : /* Validate a command message format.
240 : : */
241 : : int
242 : 38074 : validate_cmd_msg(const char *msg)
243 : : {
244 : : const char *ndx;
245 : 38074 : int res = FKO_SUCCESS;
246 : 38074 : int startlen = strnlen(msg, MAX_SPA_CMD_LEN);
247 : :
248 [ + - ]: 38074 : if(startlen == MAX_SPA_CMD_LEN)
249 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_CMD_MISSING);
250 : :
251 : : /* Should always have a valid allow IP regardless of message type
252 : : */
253 [ + + ]: 38074 : if((res = have_allow_ip(msg)) != FKO_SUCCESS)
254 : : return(FKO_ERROR_INVALID_SPA_COMMAND_MSG);
255 : :
256 : : /* Commands are fairly free-form so all we can really verify is
257 : : * there is something at all. Get past the IP and comma, and make
258 : : * sure we have some string leftover...
259 : : */
260 : 28960 : ndx = strchr(msg, ',');
261 [ + + ][ + + ]: 28960 : if(ndx == NULL || (1+(ndx - msg)) >= startlen)
262 : : return(FKO_ERROR_INVALID_SPA_COMMAND_MSG);
263 : :
264 : 28825 : return(FKO_SUCCESS);
265 : : }
266 : :
267 : : int
268 : 455139 : validate_access_msg(const char *msg)
269 : : {
270 : : const char *ndx;
271 : 455139 : int res = FKO_SUCCESS;
272 : 455139 : int startlen = strnlen(msg, MAX_SPA_MESSAGE_SIZE);
273 : :
274 [ + - ]: 455139 : if(startlen == MAX_SPA_MESSAGE_SIZE)
275 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_ACCESS_MISSING);
276 : :
277 : : /* Should always have a valid allow IP regardless of message type
278 : : */
279 [ + + ]: 455139 : if((res = have_allow_ip(msg)) != FKO_SUCCESS)
280 : : return(res);
281 : :
282 : : /* Position ourselves beyond the allow IP and make sure we are
283 : : * still good.
284 : : */
285 : 345772 : ndx = strchr(msg, ',');
286 [ + + ][ + + ]: 345772 : if(ndx == NULL || (1+(ndx - msg)) >= startlen)
287 : : return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
288 : :
289 : : /* Look for a comma to see if this is a multi-part access request.
290 : : */
291 : : do {
292 : 366401 : ndx++;
293 : 366401 : res = validate_proto_port_spec(ndx);
294 [ + + ]: 366401 : if(res != FKO_SUCCESS)
295 : : break;
296 [ + + ]: 301173 : } while((ndx = strchr(ndx, ',')));
297 : :
298 : 344411 : return(res);
299 : : }
300 : :
301 : : int
302 : 192494 : validate_nat_access_msg(const char *msg)
303 : : {
304 : : const char *ndx;
305 : : int host_len;
306 : 192494 : int res = FKO_SUCCESS;
307 : 192494 : int startlen = strnlen(msg, MAX_SPA_MESSAGE_SIZE);
308 : :
309 [ + - ]: 192494 : if(startlen == MAX_SPA_MESSAGE_SIZE)
310 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_NAT_MISSING);
311 : :
312 : : /* must have exactly one comma here
313 : : */
314 [ + + ]: 192494 : if(count_characters(msg, ',', startlen) != 1)
315 : : return(FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG);
316 : :
317 : : /* Must not be longer than the max hostname length
318 : : */
319 : 133393 : host_len = strcspn(msg, ",");
320 [ + + ]: 133393 : if(host_len > MAX_HOSTNAME_LEN)
321 : : return(FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG);
322 : :
323 : : /* Check for some invalid characters
324 : : */
325 [ + + ]: 131230 : if(strcspn(msg, " /?\"\'\\") < host_len)
326 : : return(FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG);
327 : :
328 : : /* Position ourselves beyond the allow IP and make sure we have
329 : : * a single port value
330 : : */
331 : 130471 : ndx = strchr(msg, ',');
332 [ + - ][ + + ]: 130471 : if(ndx == NULL || (1+(ndx - msg)) >= startlen)
333 : : return(FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG);
334 : :
335 : 129977 : ndx++;
336 : :
337 [ + + ]: 129977 : if((res = have_port(ndx)) != FKO_SUCCESS)
338 : : return(FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG);
339 : :
340 [ + - ]: 117698 : if(msg[startlen-1] == ',')
341 : : return(FKO_ERROR_INVALID_SPA_NAT_ACCESS_MSG);
342 : :
343 : 117698 : return(res);
344 : : }
345 : :
346 : : int
347 : 366401 : validate_proto_port_spec(const char *msg)
348 : : {
349 : 366401 : int startlen = strnlen(msg, MAX_SPA_MESSAGE_SIZE);
350 : 366401 : const char *ndx = msg;
351 : :
352 [ + - ]: 366401 : if(startlen == MAX_SPA_MESSAGE_SIZE)
353 : : return(FKO_ERROR_INVALID_DATA_MESSAGE_PORTPROTO_MISSING);
354 : :
355 : : /* Now check for proto/port string.
356 : : */
357 [ + + ]: 366401 : if(strncmp(ndx, "tcp", 3)
358 [ + + ]: 26105 : && strncmp(ndx, "udp", 3)
359 [ + + ]: 5659 : && strncmp(ndx, "icmp", 4)
360 [ + + ]: 5649 : && strncmp(ndx, "none", 4))
361 : : return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
362 : :
363 : 360753 : ndx = strchr(ndx, '/');
364 [ + + ][ + + ]: 360753 : if(ndx == NULL || ((1+(ndx - msg)) > MAX_PROTO_STR_LEN))
365 : : return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
366 : :
367 : : /* Skip over the '/' and make sure we only have digits.
368 : : */
369 : 359241 : ndx++;
370 : :
371 : 359241 : return have_port(ndx);
372 : : }
373 : :
374 : : /***EOF***/
|