Add plugin constructor registration for all libraries that provide plugins
[strongswan.git] / src / libtnccs / tnc / tnc.c
1 /*
2 * Copyright (C) 2011 Andreas Steffen
3 * HSR 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 #define _GNU_SOURCE /* for stdndup() */
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <string.h>
23
24 #include "tnc.h"
25
26 #include <utils/lexparser.h>
27 #include <utils/debug.h>
28
29 #ifdef WIN32
30 # define DEFAULT_TNC_CONFIG "tnc_config"
31 #else
32 # define DEFAULT_TNC_CONFIG "/etc/tnc_config"
33 #endif
34
35 typedef struct private_tnc_t private_tnc_t;
36
37 typedef tnccs_manager_t *(*tnc_create_tnccs_manager_t)(void);
38 typedef imc_manager_t *(*tnc_create_imc_manager_t)(void);
39 typedef imv_manager_t *(*tnc_create_imv_manager_t)(void);
40
41 /**
42 * Private additions to tnc_t.
43 */
44 struct private_tnc_t {
45
46 /**
47 * Public members of tnc_t.
48 */
49 tnc_t public;
50
51 /**
52 * Number of times we have been initialized
53 */
54 refcount_t ref;
55 };
56
57 /**
58 * Register plugins if built statically
59 */
60 #ifdef STATIC_PLUGIN_CONSTRUCTORS
61 #include "plugin_constructors.c"
62 #endif
63
64 /**
65 * Single instance of tnc_t.
66 */
67 tnc_t *tnc;
68
69 /**
70 * Described in header.
71 */
72 void libtnccs_init(void)
73 {
74 private_tnc_t *this;
75
76 if (tnc)
77 { /* already initialized, increase refcount */
78 this = (private_tnc_t*)tnc;
79 ref_get(&this->ref);
80 return;
81 }
82
83 INIT(this,
84 .public = {
85 },
86 .ref = 1,
87 );
88 tnc = &this->public;
89 lib->settings->add_fallback(lib->settings, "%s.tnc", "libtnccs", lib->ns);
90 lib->settings->add_fallback(lib->settings, "%s.plugins", "libtnccs.plugins",
91 lib->ns);
92 }
93
94 /**
95 * Described in header.
96 */
97 void libtnccs_deinit(void)
98 {
99 private_tnc_t *this = (private_tnc_t*)tnc;
100
101 if (!this || !ref_put(&this->ref))
102 { /* have more users */
103 return;
104 }
105
106 free(this);
107 tnc = NULL;
108 }
109
110 static bool load_imcvs_from_config(char *filename, bool is_imc)
111 {
112 bool success = FALSE;
113 int line_nr = 0;
114 chunk_t *src, line;
115 char *label;
116
117 if (!filename || !*filename)
118 {
119 return TRUE;
120 }
121
122 label = is_imc ? "IMC" : "IMV";
123
124 DBG1(DBG_TNC, "loading %ss from '%s'", label, filename);
125 src = chunk_map(filename, FALSE);
126 if (!src)
127 {
128 DBG1(DBG_TNC, "opening configuration file '%s' failed: %s", filename,
129 strerror(errno));
130 return FALSE;
131 }
132
133 while (fetchline(src, &line))
134 {
135 char *name, *path;
136 chunk_t token;
137
138 line_nr++;
139
140 /* skip comments or empty lines */
141 if (*line.ptr == '#' || !eat_whitespace(&line))
142 {
143 continue;
144 }
145
146 /* determine keyword */
147 if (!extract_token(&token, ' ', &line))
148 {
149 DBG1(DBG_TNC, "line %d: keyword must be followed by a space",
150 line_nr);
151 break;
152 }
153
154 /* only interested in IMCs or IMVs depending on label */
155 if (!match(label, &token))
156 {
157 continue;
158 }
159
160 /* advance to the IMC/IMV name and extract it */
161 if (!extract_token(&token, '"', &line) ||
162 !extract_token(&token, '"', &line))
163 {
164 DBG1(DBG_TNC, "line %d: %s name must be set in double quotes",
165 line_nr, label);
166 break;
167 }
168
169 /* copy the IMC/IMV name */
170 name = strndup(token.ptr, token.len);
171
172 /* advance to the IMC/IMV path and extract it */
173 if (!eat_whitespace(&line))
174 {
175 DBG1(DBG_TNC, "line %d: %s path is missing", line_nr, label);
176 free(name);
177 break;
178 }
179 if (!extract_token(&token, ' ', &line))
180 {
181 token = line;
182 }
183
184 /* copy the IMC/IMV path */
185 path = strndup(token.ptr, token.len);
186
187 /* load and register an IMC/IMV instance */
188 if (is_imc)
189 {
190 success = tnc->imcs->load(tnc->imcs, name, path);
191 }
192 else
193 {
194 success = tnc->imvs->load(tnc->imvs, name, path);
195 }
196 free(name);
197 free(path);
198 if (!success)
199 {
200 break;
201 }
202 }
203 chunk_unmap(src);
204 return success;
205 }
206
207 /**
208 * Described in header.
209 */
210 bool tnc_manager_register(plugin_t *plugin, plugin_feature_t *feature,
211 bool reg, void *data)
212 {
213 bool load_imcvs = FALSE;
214 bool is_imc = FALSE;
215
216 if (feature->type == FEATURE_CUSTOM)
217 {
218 if (streq(feature->arg.custom, "tnccs-manager"))
219 {
220 if (reg)
221 {
222 tnc->tnccs = ((tnc_create_tnccs_manager_t)data)();
223 }
224 else
225 {
226 tnc->tnccs->destroy(tnc->tnccs);
227 tnc->tnccs = NULL;
228 }
229 }
230 else if (streq(feature->arg.custom, "imc-manager"))
231 {
232 if (reg)
233 {
234 tnc->imcs = ((tnc_create_imc_manager_t)data)();
235 is_imc = TRUE;
236 load_imcvs = TRUE;
237 }
238 else
239 {
240 tnc->imcs->destroy(tnc->imcs);
241 tnc->imcs = NULL;
242 }
243 }
244 else if (streq(feature->arg.custom, "imv-manager"))
245 {
246 if (reg)
247 {
248 tnc->imvs = ((tnc_create_imv_manager_t)data)();
249 is_imc = FALSE;
250 load_imcvs = TRUE;
251 }
252 else
253 {
254 tnc->imvs->destroy(tnc->imvs);
255 tnc->imvs = NULL;
256 }
257 }
258 else
259 {
260 return FALSE;
261 }
262
263 if (load_imcvs)
264 {
265 load_imcvs_from_config(
266 lib->settings->get_str(lib->settings,
267 "%s.tnc.tnc_config", DEFAULT_TNC_CONFIG, lib->ns),
268 is_imc);
269 }
270 }
271 return TRUE;
272 }