3228dfad90232600f4303c0417ea912f22f1bb6a
[fwknop.git] / lib / fko_message.c
1 /*
2  *****************************************************************************
3  *
4  * File:    fko_message.c
5  *
6  * Author:  Damien S. Stuart
7  *
8  * Purpose: Set/Get the spa message (access req/command/etc) based
9  *          on the current spa data.
10  *
11  * Copyright 2009-2010 Damien Stuart (dstuart@dstuart.org)
12  *
13  *  License (GNU 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.h"
34
35 /* Set the SPA message type.
36 */
37 int
38 fko_set_spa_message_type(fko_ctx_t ctx, const short msg_type)
39 {
40     /* Must be initialized
41     */
42     if(!CTX_INITIALIZED(ctx))
43         return FKO_ERROR_CTX_NOT_INITIALIZED;
44
45     if(msg_type < 0 || msg_type >= FKO_LAST_MSG_TYPE)
46         return(FKO_ERROR_INVALID_DATA);
47
48     ctx->message_type = msg_type;
49
50     ctx->state |= FKO_SPA_MSG_TYPE_MODIFIED;
51
52     return(FKO_SUCCESS);
53 }
54
55 /* Return the SPA message type.
56 */
57 int
58 fko_get_spa_message_type(fko_ctx_t ctx, short *msg_type)
59 {
60     /* Must be initialized
61     */
62     if(!CTX_INITIALIZED(ctx))
63         return FKO_ERROR_CTX_NOT_INITIALIZED;
64
65     *msg_type = ctx->message_type;
66
67     return(FKO_SUCCESS);
68 }
69
70 /* Set the SPA MESSAGE data
71 */
72 int
73 fko_set_spa_message(fko_ctx_t ctx, const char *msg)
74 {
75     int res = FKO_ERROR_UNKNOWN;
76
77     /* Context must be initialized.
78     */
79     if(!CTX_INITIALIZED(ctx))
80         return FKO_ERROR_CTX_NOT_INITIALIZED;
81
82     /* Gotta have a valid string.
83     */
84     if(msg == NULL || strnlen(msg, MAX_SPA_MESSAGE_SIZE) == 0)
85         return(FKO_ERROR_INVALID_DATA);
86
87     /* --DSS XXX: Bail out for now.  But consider just
88      *            truncating in the future...
89     */
90     if(strnlen(msg, MAX_SPA_MESSAGE_SIZE) == MAX_SPA_MESSAGE_SIZE)
91         return(FKO_ERROR_DATA_TOO_LARGE);
92
93     /* Basic message type and format checking...
94     */
95     switch(ctx->message_type)
96     {
97         case FKO_COMMAND_MSG:
98             res = validate_cmd_msg(msg);
99             break;
100
101         case FKO_ACCESS_MSG:
102         case FKO_CLIENT_TIMEOUT_ACCESS_MSG:
103             res = validate_access_msg(msg);
104             break;
105
106         case FKO_NAT_ACCESS_MSG:
107         case FKO_LOCAL_NAT_ACCESS_MSG:
108         case FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG:
109         case FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG:
110             res = validate_nat_access_msg(msg);
111             break;
112     }
113
114     if(res != FKO_SUCCESS)
115         return(res);
116
117     /* Just in case this is a subsquent call to this function.  We
118      * do not want to be leaking memory.
119     */
120     if(ctx->message != NULL)
121         free(ctx->message);
122
123     ctx->message = strdup(msg);
124
125     ctx->state |= FKO_DATA_MODIFIED;
126
127     if(ctx->message == NULL)
128         return(FKO_ERROR_MEMORY_ALLOCATION);
129
130     return(FKO_SUCCESS);
131 }
132
133 /* Return the SPA message data.
134 */
135 int
136 fko_get_spa_message(fko_ctx_t ctx, char **msg)
137 {
138     /* Must be initialized
139     */
140     if(!CTX_INITIALIZED(ctx))
141         return(FKO_ERROR_CTX_NOT_INITIALIZED);
142
143     *msg = ctx->message;
144
145     return(FKO_SUCCESS);
146 }
147
148 /* Validate a command message format.
149 */
150 int
151 validate_cmd_msg(const char *msg)
152 {
153     const char   *ndx;
154     int     res         = FKO_SUCCESS;
155     int     startlen    = strnlen(msg, MAX_SPA_CMD_LEN);
156
157     if(startlen == MAX_SPA_CMD_LEN)
158         return(FKO_ERROR_INVALID_DATA);
159
160     /* Should have a valid allow IP.
161     */
162     if((res = got_allow_ip(msg)) != FKO_SUCCESS)
163         return(res);
164
165     /* Commands are fairly free-form so all we can really verify is
166      * there is something at all. Get past the IP and comma, and make
167      * sure we have some string leftover...
168     */
169     ndx = strchr(msg, ',');
170     if(ndx == NULL || (1+(ndx - msg)) >= startlen)
171         return(FKO_ERROR_INVALID_SPA_COMMAND_MSG);
172
173     return(FKO_SUCCESS);
174 }
175
176 int
177 validate_access_msg(const char *msg)
178 {
179     const char   *ndx;
180     int     res         = FKO_SUCCESS;
181     int     startlen    = strnlen(msg, MAX_SPA_MESSAGE_SIZE);
182
183     if(startlen == MAX_SPA_MESSAGE_SIZE)
184         return(FKO_ERROR_INVALID_DATA);
185
186     /* Should have a valid allow IP.
187     */
188     if((res = got_allow_ip(msg)) != FKO_SUCCESS)
189         return(res);
190
191     /* Position ourselves beyond the allow IP and make sure we are
192      * still good.
193     */
194     ndx = strchr(msg, ',');
195     if(ndx == NULL || (1+(ndx - msg)) >= startlen)
196         return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
197
198     /* Look for a comma to see if this is a multi-part access request.
199     */
200     do {
201         ndx++;
202         res = validate_proto_port_spec(ndx);
203         if(res != FKO_SUCCESS)
204             break;
205     } while((ndx = strchr(ndx, ',')));
206
207     return(res);
208 }
209
210 int
211 validate_proto_port_spec(const char *msg)
212 {
213     int     startlen    = strnlen(msg, MAX_SPA_MESSAGE_SIZE), port_str_len = 0;
214     const char   *ndx   = msg;
215
216     if(startlen == MAX_SPA_MESSAGE_SIZE)
217         return(FKO_ERROR_INVALID_DATA);
218
219     /* Now check for proto/port string.
220     */
221     if(strncmp(ndx, "tcp", 3)
222       && strncmp(ndx, "udp", 3)
223       && strncmp(ndx, "icmp", 4)
224       && strncmp(ndx, "none", 4))
225         return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
226
227     ndx = strchr(ndx, '/');
228     if(ndx == NULL || ((1+(ndx - msg)) > MAX_PROTO_STR_LEN))
229         return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
230
231     /* Skip over the '/' and make sure we only have digits.
232     */
233     ndx++;
234
235     /* Must have at least one digit for the port number
236     */
237     if(isdigit(*ndx) == 0)
238         return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
239
240     while(*ndx != '\0' && *ndx != ',')
241     {
242         port_str_len++;
243         if((isdigit(*ndx) == 0) || (port_str_len > MAX_PORT_STR_LEN))
244             return(FKO_ERROR_INVALID_SPA_ACCESS_MSG);
245         ndx++;
246     }
247     return(FKO_SUCCESS);
248 }
249
250 int
251 validate_nat_access_msg(const char *msg)
252 {
253     int res = FKO_SUCCESS;
254
255     /* Should have a valid access message.
256     */
257     if((res = validate_access_msg(msg)) != FKO_SUCCESS)
258         return(res);
259
260     // --DSS TODO: XXX: Put nat_access validation code here
261
262     return(FKO_SUCCESS);
263 }
264
265 int
266 got_allow_ip(const char *msg)
267 {
268     const char *ndx     = msg;
269     int         dot_ctr = 0, char_ctr = 0;
270     int         res     = FKO_SUCCESS;
271
272     while(*ndx != ',' && *ndx != '\0')
273     {
274         char_ctr++;
275         if(char_ctr >= MAX_IPV4_STR_LEN)
276         {
277             res = FKO_ERROR_INVALID_ALLOW_IP;
278             break;
279         }
280         if(*ndx == '.')
281             dot_ctr++;
282         else if(isdigit(*ndx) == 0)
283         {
284             res = FKO_ERROR_INVALID_ALLOW_IP;
285             break;
286         }
287         ndx++;
288     }
289
290     if (char_ctr < MIN_IPV4_STR_LEN)
291         res = FKO_ERROR_INVALID_ALLOW_IP;
292
293     if(dot_ctr != 3)
294         res = FKO_ERROR_INVALID_ALLOW_IP;
295
296     return(res);
297 }
298
299 /***EOF***/