handle zero size Base64 conversions
[strongswan.git] / src / manager / gateway.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "gateway.h"
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24
25 #include <xml.h>
26
27 typedef struct private_gateway_t private_gateway_t;
28
29 /**
30 * private data of gateway
31 */
32 struct private_gateway_t {
33
34 /**
35 * public functions
36 */
37 gateway_t public;
38
39 /**
40 * name of the gateway
41 */
42 char *name;
43
44 /**
45 * host to connect using tcp
46 */
47 host_t *host;
48
49 /**
50 * socket file descriptor, > 0 if connected
51 */
52 int fd;
53
54 /**
55 * unique id assigned to each xml message
56 */
57 int xmlid;
58 };
59
60 struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"};
61
62 /**
63 * establish connection to gateway
64 */
65 static bool connect_(private_gateway_t *this)
66 {
67 int family, len;
68 struct sockaddr *addr;
69
70 if (this->fd >= 0)
71 {
72 close(this->fd);
73 }
74 if (this->host)
75 {
76 family = AF_INET;
77 addr = this->host->get_sockaddr(this->host);
78 len = *this->host->get_sockaddr_len(this->host);
79 }
80 else
81 {
82 family = AF_UNIX;
83 addr = (struct sockaddr*)&unix_addr;
84 len = sizeof(unix_addr);
85 }
86
87 this->fd = socket(family, SOCK_STREAM, 0);
88 if (this->fd < 0)
89 {
90 return FALSE;
91 }
92 if (connect(this->fd, addr, len) != 0)
93 {
94 close(this->fd);
95 this->fd = -1;
96 return FALSE;
97 }
98 return TRUE;
99 }
100
101 /**
102 * Implementation of gateway_t.request.
103 */
104 static char* request(private_gateway_t *this, char *xml, ...)
105 {
106 if (this->fd < 0)
107 {
108 if (!connect_(this))
109 {
110 return NULL;
111 }
112 }
113 while (TRUE)
114 {
115 char buf[8096];
116 ssize_t len;
117 va_list args;
118
119 va_start(args, xml);
120 len = vsnprintf(buf, sizeof(buf), xml, args);
121 va_end(args);
122 if (len < 0 || len >= sizeof(buf))
123 {
124 return NULL;
125 }
126 if (send(this->fd, buf, len, 0) != len)
127 {
128 if (!connect_(this))
129 {
130 return NULL;
131 }
132 continue;
133 }
134 len = recv(this->fd, buf, sizeof(buf) - 1, 0);
135 if (len <= 0)
136 {
137 if (!connect_(this))
138 {
139 return NULL;
140 }
141 continue;
142 }
143 buf[len] = 0;
144 return strdup(buf);
145 }
146 }
147
148 /**
149 * Implementation of gateway_t.query_ikesalist.
150 */
151 static enumerator_t* query_ikesalist(private_gateway_t *this)
152 {
153 char *str, *name, *value;
154 xml_t *xml;
155 enumerator_t *e1, *e2, *e3, *e4 = NULL;
156
157 str = request(this, "<message type=\"request\" id=\"%d\">"
158 "<query>"
159 "<ikesalist/>"
160 "</query>"
161 "</message>", this->xmlid++);
162 if (str == NULL)
163 {
164 return NULL;
165 }
166 xml = xml_create(str);
167 if (xml == NULL)
168 {
169 return NULL;
170 }
171
172 e1 = xml->children(xml);
173 free(str);
174 while (e1->enumerate(e1, &xml, &name, &value))
175 {
176 if (streq(name, "message"))
177 {
178 e2 = xml->children(xml);
179 while (e2->enumerate(e2, &xml, &name, &value))
180 {
181 if (streq(name, "query"))
182 {
183 e3 = xml->children(xml);
184 while (e3->enumerate(e3, &xml, &name, &value))
185 {
186 if (streq(name, "ikesalist"))
187 {
188 e4 = xml->children(xml);
189 e1->destroy(e1);
190 e2->destroy(e2);
191 e3->destroy(e3);
192 return e4;
193 }
194 }
195 e3->destroy(e3);
196 }
197 }
198 e2->destroy(e2);
199 }
200 }
201 e1->destroy(e1);
202 return NULL;
203 }
204
205
206 /**
207 * Implementation of gateway_t.query_configlist.
208 */
209 static enumerator_t* query_configlist(private_gateway_t *this)
210 {
211 char *str, *name, *value;
212 xml_t *xml;
213 enumerator_t *e1, *e2, *e3, *e4 = NULL;
214
215 str = request(this, "<message type=\"request\" id=\"%d\">"
216 "<query>"
217 "<configlist/>"
218 "</query>"
219 "</message>", this->xmlid++);
220 if (str == NULL)
221 {
222 return NULL;
223 }
224 xml = xml_create(str);
225 if (xml == NULL)
226 {
227 return NULL;
228 }
229
230 e1 = xml->children(xml);
231 free(str);
232 while (e1->enumerate(e1, &xml, &name, &value))
233 {
234 if (streq(name, "message"))
235 {
236 e2 = xml->children(xml);
237 while (e2->enumerate(e2, &xml, &name, &value))
238 {
239 if (streq(name, "query"))
240 {
241 e3 = xml->children(xml);
242 while (e3->enumerate(e3, &xml, &name, &value))
243 {
244 if (streq(name, "configlist"))
245 {
246 e4 = xml->children(xml);
247 e1->destroy(e1);
248 e2->destroy(e2);
249 e3->destroy(e3);
250 return e4;
251 }
252 }
253 e3->destroy(e3);
254 }
255 }
256 e2->destroy(e2);
257 }
258 }
259 e1->destroy(e1);
260 return NULL;
261 }
262
263 /**
264 * create enumerator over control elements children of a control response
265 */
266 static enumerator_t* read_result(private_gateway_t *this, char *res)
267 {
268 char *name, *value;
269 xml_t *xml;
270 enumerator_t *e1, *e2, *e3;
271
272 if (res == NULL)
273 {
274 return NULL;
275 }
276 xml = xml_create(res);
277 if (xml == NULL)
278 {
279 return NULL;
280 }
281 e1 = xml->children(xml);
282 free(res);
283 while (e1->enumerate(e1, &xml, &name, &value))
284 {
285 if (streq(name, "message"))
286 {
287 e2 = xml->children(xml);
288 while (e2->enumerate(e2, &xml, &name, &value))
289 {
290 if (streq(name, "control"))
291 {
292 e3 = xml->children(xml);
293 e1->destroy(e1);
294 e2->destroy(e2);
295 return e3;
296 }
297 }
298 e2->destroy(e2);
299 }
300 }
301 e1->destroy(e1);
302 return NULL;
303 }
304
305 /**
306 * Implementation of gateway_t.initiate.
307 */
308 static enumerator_t* initiate(private_gateway_t *this, bool ike, char *name)
309 {
310 char *str, *kind;
311
312 if (ike)
313 {
314 kind = "ike";
315 }
316 else
317 {
318 kind = "child";
319 }
320 str = request(this, "<message type=\"request\" id=\"%d\">"
321 "<control>"
322 "<%ssainitiate>%s</%ssainitiate>"
323 "</control>"
324 "</message>", this->xmlid++, kind, name, kind);
325 return read_result(this, str);
326 }
327
328 /**
329 * Implementation of gateway_t.terminate.
330 */
331 static enumerator_t* terminate(private_gateway_t *this, bool ike, u_int32_t id)
332 {
333 char *str, *kind;
334
335 if (ike)
336 {
337 kind = "ike";
338 }
339 else
340 {
341 kind = "child";
342 }
343 str = request(this, "<message type=\"request\" id=\"%d\">"
344 "<control>"
345 "<%ssaterminate>%d</%ssaterminate>"
346 "</control>"
347 "</message>", this->xmlid++, kind, id, kind);
348 return read_result(this, str);
349 }
350
351 /**
352 * Implementation of gateway_t.destroy
353 */
354 static void destroy(private_gateway_t *this)
355 {
356 if (this->fd >= 0)
357 {
358 close(this->fd);
359 }
360 if (this->host) this->host->destroy(this->host);
361 free(this->name);
362 free(this);
363 }
364
365 /**
366 * generic constructor
367 */
368 static private_gateway_t *gateway_create(char *name)
369 {
370 private_gateway_t *this = malloc_thing(private_gateway_t);
371
372 this->public.request = (char*(*)(gateway_t*, char *xml))request;
373 this->public.query_ikesalist = (enumerator_t*(*)(gateway_t*))query_ikesalist;
374 this->public.query_configlist = (enumerator_t*(*)(gateway_t*))query_configlist;
375 this->public.initiate = (enumerator_t*(*)(gateway_t*, bool ike, char *name))initiate;
376 this->public.terminate = (enumerator_t*(*)(gateway_t*, bool ike, u_int32_t id))terminate;
377 this->public.destroy = (void(*)(gateway_t*))destroy;
378
379 this->name = strdup(name);
380 this->host = NULL;
381 this->fd = -1;
382 this->xmlid = 1;
383
384 return this;
385 }
386
387 /**
388 * see header
389 */
390 gateway_t *gateway_create_tcp(char *name, host_t *host)
391 {
392 private_gateway_t *this = gateway_create(name);
393
394 this->host = host;
395
396 return &this->public;
397 }
398
399 /**
400 * see header
401 */
402 gateway_t *gateway_create_unix(char *name)
403 {
404 private_gateway_t *this = gateway_create(name);
405
406 return &this->public;
407 }
408