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