fixed usage typo
[strongswan.git] / src / charon / plugins / uci / uci_control.c
1 /*
2 * Copyright (C) 2008 Thomas Kallenberg
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * $Id$
17 */
18
19 #define _GNU_SOURCE
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <pthread.h>
27
28 #include "uci_control.h"
29
30 #include <daemon.h>
31 #include <processing/jobs/callback_job.h>
32
33 #define FIFO_FILE "/var/run/charon.fifo"
34
35
36 typedef struct private_uci_control_t private_uci_control_t;
37
38 /**
39 * private data of uci_control_t
40 */
41 struct private_uci_control_t {
42
43 /**
44 * Public part
45 */
46 uci_control_t public;
47
48 /**
49 * Job
50 */
51 callback_job_t *job;
52 };
53
54 /**
55 * write answer to fifo
56 */
57 static void write_fifo(private_uci_control_t *this, char *format, ...)
58 {
59 va_list args;
60 FILE *out;
61
62 out = fopen(FIFO_FILE, "w");
63 if (out)
64 {
65 va_start(args, format);
66 vfprintf(out, format, args);
67 va_end(args);
68 fclose(out);
69 }
70 else
71 {
72 DBG1(DBG_CFG, "writing to UCI fifo failed: %s", strerror(errno));
73 }
74 }
75
76 /**
77 * print IKE_SA status information
78 */
79 static void status(private_uci_control_t *this, char *name)
80 {
81 enumerator_t *configs, *sas;
82 iterator_t *children;
83 ike_sa_t *ike_sa;
84 child_sa_t *child_sa;
85 peer_cfg_t *peer_cfg;
86 char buf[2048];
87 FILE *out = NULL;
88
89 configs = charon->backends->create_peer_cfg_enumerator(charon->backends);
90 while (configs->enumerate(configs, &peer_cfg))
91 {
92 if (name && !streq(name, peer_cfg->get_name(peer_cfg)))
93 {
94 continue;
95 }
96 sas = charon->controller->create_ike_sa_enumerator(charon->controller);
97 while (sas->enumerate(sas, &ike_sa))
98 {
99 if (!streq(ike_sa->get_name(ike_sa), peer_cfg->get_name(peer_cfg)))
100 {
101 continue;
102 }
103 if (!out)
104 {
105 out = fmemopen(buf, sizeof(buf), "w");
106 if (!out)
107 {
108 continue;
109 }
110 }
111 fprintf(out, "%-8s %-20D %-16H ", ike_sa->get_name(ike_sa),
112 ike_sa->get_other_id(ike_sa), ike_sa->get_other_host(ike_sa));
113
114 children = ike_sa->create_child_sa_iterator(ike_sa);
115 while (children->iterate(children, (void**)&child_sa))
116 {
117 fprintf(out, "%#R",
118 child_sa->get_traffic_selectors(child_sa, FALSE));
119 }
120 children->destroy(children);
121 fprintf(out, "\n");
122 }
123 sas->destroy(sas);
124 }
125 configs->destroy(configs);
126 if (out)
127 {
128 fclose(out);
129 write_fifo(this, "%s", buf);
130 }
131 else
132 {
133 write_fifo(this, "");
134 }
135 }
136
137 /**
138 * Initiate an IKE_SA
139 */
140 static void initiate(private_uci_control_t *this, char *name)
141 {
142 peer_cfg_t *peer_cfg;
143 child_cfg_t *child_cfg;
144 enumerator_t *enumerator;
145
146 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name);
147 if (peer_cfg)
148 {
149 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
150 if (enumerator->enumerate(enumerator, &child_cfg) &&
151 charon->controller->initiate(charon->controller, peer_cfg,
152 child_cfg->get_ref(child_cfg),
153 controller_cb_empty, NULL) == SUCCESS)
154 {
155 write_fifo(this, "connection '%s' established\n", name);
156 }
157 else
158 {
159 write_fifo(this, "establishing connection '%s' failed\n", name);
160 }
161 enumerator->destroy(enumerator);
162 }
163 else
164 {
165 write_fifo(this, "no connection named '%s' found\n", name);
166 }
167 }
168
169 /**
170 * terminate an IKE_SA
171 */
172 static void terminate(private_uci_control_t *this, char *name)
173 {
174 enumerator_t *enumerator;
175 ike_sa_t *ike_sa;
176 u_int id;
177
178 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
179 while (enumerator->enumerate(enumerator, &ike_sa))
180 {
181 if (streq(name, ike_sa->get_name(ike_sa)))
182 {
183 id = ike_sa->get_unique_id(ike_sa);
184 enumerator->destroy(enumerator);
185 charon->controller->terminate_ike(charon->controller, id,
186 controller_cb_empty, NULL);
187 write_fifo(this, "connection '%s' terminated\n", name);
188 return;
189 }
190 }
191 enumerator->destroy(enumerator);
192 write_fifo(this, "no active connection named '%s'\n", name);
193 }
194
195 /**
196 * dispatch control request
197 */
198 static void process(private_uci_control_t *this, char *message)
199 {
200 enumerator_t* enumerator;
201
202 enumerator = enumerator_create_token(message, " \n", "");
203 if (enumerator->enumerate(enumerator, &message))
204 {
205 if (streq(message, "status"))
206 {
207 if (enumerator->enumerate(enumerator, &message))
208 {
209 status(this, message);
210 }
211 else
212 {
213 status(this, NULL);
214 }
215 }
216 else if (streq(message, "up") &&
217 enumerator->enumerate(enumerator, &message))
218 {
219 initiate(this, message);
220 }
221 else if (streq(message, "down") &&
222 enumerator->enumerate(enumerator, &message))
223 {
224 terminate(this, message);
225 }
226 else
227 {
228 write_fifo(this, "usage: status [<name>] | up <name> | down <name>\n"
229 " status format: name peer-id peer-addr tunnel(s)\n");
230 }
231 }
232 enumerator->destroy(enumerator);
233 }
234
235 /**
236 * read from fifo
237 */
238 static job_requeue_t receive(private_uci_control_t *this)
239 {
240 char message[128];
241 int oldstate, len;
242 FILE *in;
243
244 memset(message, 0, sizeof(message));
245 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
246 in = fopen(FIFO_FILE, "r");
247 pthread_setcancelstate(oldstate, NULL);
248 if (in)
249 {
250 len = fread(message, 1, sizeof(message) - 1, in);
251 fclose(in);
252 if (len > 0)
253 {
254 process(this, message);
255 }
256 else
257 {
258 DBG1(DBG_DMN, "reading from UCI fifo failed: %s", strerror(errno));
259 }
260 }
261 else
262 {
263 DBG1(DBG_DMN, "opening UCI fifo failed: %s", strerror(errno));
264 }
265 return JOB_REQUEUE_FAIR;
266 }
267
268 /**
269 * Implementation of uci_control_t.destroy
270 */
271 static void destroy(private_uci_control_t *this)
272 {
273 this->job->cancel(this->job);
274 unlink(FIFO_FILE);
275 free(this);
276 }
277
278 /**
279 * Described in header.
280 */
281 uci_control_t *uci_control_create()
282 {
283 private_uci_control_t *this = malloc_thing(private_uci_control_t);
284
285 this->public.destroy = (void(*)(uci_control_t*))destroy;
286
287 if (access(FIFO_FILE, F_OK) != 0 &&
288 mkfifo(FIFO_FILE, S_IRUSR|S_IWUSR) != 0)
289 {
290 DBG1(DBG_CFG, "creating UCI control fifo '%s' failed: %s",
291 FIFO_FILE, strerror(errno));
292 }
293 else
294 {
295 this->job = callback_job_create((callback_job_cb_t)receive,
296 this, NULL, NULL);
297 charon->processor->queue_job(charon->processor, (job_t*)this->job);
298 }
299 return &this->public;
300 }
301