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