ecf19096a352b6785fe7e765fb1ce8b4821a5c0c
[strongswan.git] / src / libcharon / plugins / vici / vici_control.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
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 "vici_control.h"
17 #include "vici_builder.h"
18
19 #include <inttypes.h>
20
21 #include <daemon.h>
22
23 typedef struct private_vici_control_t private_vici_control_t;
24
25 /**
26 * Private data of an vici_control_t object.
27 */
28 struct private_vici_control_t {
29
30 /**
31 * Public vici_control_t interface.
32 */
33 vici_control_t public;
34
35 /**
36 * Dispatcher
37 */
38 vici_dispatcher_t *dispatcher;
39 };
40
41 /**
42 * Log callback helper data
43 */
44 typedef struct {
45 /** dispatcher to send log messages over */
46 vici_dispatcher_t *dispatcher;
47 /** connection ID to send messages to */
48 u_int id;
49 /** loglevel */
50 level_t level;
51 } log_info_t;
52
53 /**
54 * Log using vici event messages
55 */
56 static bool log_vici(log_info_t *info, debug_t group, level_t level,
57 ike_sa_t *ike_sa, char *text)
58 {
59 if (level <= info->level)
60 {
61 vici_message_t *message;
62 vici_builder_t *builder;
63
64 builder = vici_builder_create();
65 builder->add_kv(builder, "group", "%N", debug_names, group);
66 builder->add_kv(builder, "level", "%d", level);
67 if (ike_sa)
68 {
69 builder->add_kv(builder, "ikesa-name", "%s",
70 ike_sa->get_name(ike_sa));
71 builder->add_kv(builder, "ikesa-uniqueid", "%u",
72 ike_sa->get_unique_id(ike_sa));
73 }
74 builder->add_kv(builder, "msg", "%s", text);
75
76 message = builder->finalize(builder);
77 if (message)
78 {
79 info->dispatcher->raise_event(info->dispatcher, "control-log",
80 info->id, message);
81 }
82 }
83 return TRUE;
84 }
85
86 /**
87 * Send a (error) reply message
88 */
89 static vici_message_t* send_reply(private_vici_control_t *this, char *fmt, ...)
90 {
91 vici_builder_t *builder;
92 va_list args;
93
94 builder = vici_builder_create();
95 builder->add_kv(builder, "success", fmt ? "no" : "yes");
96 if (fmt)
97 {
98 va_start(args, fmt);
99 builder->vadd_kv(builder, "errmsg", fmt, args);
100 va_end(args);
101 }
102 return builder->finalize(builder);
103 }
104
105 /**
106 * Get the child_cfg having name from peer_cfg
107 */
108 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
109 {
110 child_cfg_t *current, *found = NULL;
111 enumerator_t *enumerator;
112
113 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
114 while (enumerator->enumerate(enumerator, &current))
115 {
116 if (streq(current->get_name(current), name))
117 {
118 found = current;
119 found->get_ref(found);
120 break;
121 }
122 }
123 enumerator->destroy(enumerator);
124 return found;
125 }
126
127 CALLBACK(initiate, vici_message_t*,
128 private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
129 {
130 child_cfg_t *child_cfg = NULL;
131 peer_cfg_t *peer_cfg;
132 enumerator_t *enumerator;
133 char *child;
134 u_int timeout;
135 log_info_t log = {
136 .dispatcher = this->dispatcher,
137 .id = id,
138 };
139
140 child = request->get_str(request, NULL, "child");
141 timeout = request->get_int(request, 0, "timeout");
142 log.level = request->get_int(request, 1, "loglevel");
143
144 if (!child)
145 {
146 return send_reply(this, "missing configuration name");
147 }
148 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
149 NULL, NULL, NULL, NULL, IKE_ANY);
150 while (enumerator->enumerate(enumerator, &peer_cfg))
151 {
152 child_cfg = get_child_from_peer(peer_cfg, child);
153 if (child_cfg)
154 {
155 peer_cfg->get_ref(peer_cfg);
156 break;
157 }
158 }
159 enumerator->destroy(enumerator);
160
161 if (!child_cfg)
162 {
163 return send_reply(this, "CHILD_SA config '%s' not found", child);
164 }
165 switch (charon->controller->initiate(charon->controller,
166 peer_cfg, child_cfg, (controller_cb_t)log_vici, &log, timeout))
167 {
168 case SUCCESS:
169 return send_reply(this, NULL);
170 case OUT_OF_RES:
171 return send_reply(this, "CHILD_SA '%s' not established after %dms",
172 child, timeout);
173 case FAILED:
174 default:
175 return send_reply(this, "establishing CHILD_SA '%s' failed", child);
176 }
177 }
178
179 static void manage_command(private_vici_control_t *this,
180 char *name, vici_command_cb_t cb, bool reg)
181 {
182 this->dispatcher->manage_command(this->dispatcher, name,
183 reg ? cb : NULL, this);
184 }
185
186 /**
187 * (Un-)register dispatcher functions
188 */
189 static void manage_commands(private_vici_control_t *this, bool reg)
190 {
191 manage_command(this, "initiate", initiate, reg);
192 this->dispatcher->manage_event(this->dispatcher, "control-log", reg);
193 }
194
195 METHOD(vici_control_t, destroy, void,
196 private_vici_control_t *this)
197 {
198 manage_commands(this, FALSE);
199 free(this);
200 }
201
202 /**
203 * See header
204 */
205 vici_control_t *vici_control_create(vici_dispatcher_t *dispatcher)
206 {
207 private_vici_control_t *this;
208
209 INIT(this,
210 .public = {
211 .destroy = _destroy,
212 },
213 .dispatcher = dispatcher,
214 );
215
216 manage_commands(this, TRUE);
217
218 return &this->public;
219 }