Annotation of embedaddon/strongswan/src/libcharon/config/backend_manager.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2018 Tobias Brunner
3: * Copyright (C) 2007-2009 Martin Willi
4: * HSR 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:
17: #include "backend_manager.h"
18:
19: #include <sys/types.h>
20:
21: #include <daemon.h>
22: #include <collections/linked_list.h>
23: #include <threading/rwlock.h>
24:
25:
26: typedef struct private_backend_manager_t private_backend_manager_t;
27:
28: /**
29: * Private data of an backend_manager_t object.
30: */
31: struct private_backend_manager_t {
32:
33: /**
34: * Public part of backend_manager_t object.
35: */
36: backend_manager_t public;
37:
38: /**
39: * list of registered backends
40: */
41: linked_list_t *backends;
42:
43: /**
44: * rwlock for backends
45: */
46: rwlock_t *lock;
47: };
48:
49: /**
50: * match of an ike_cfg
51: */
52: typedef enum ike_cfg_match_t {
53: /* doesn't match at all */
54: MATCH_NONE = 0x00,
55: /* match for a %any host. For both hosts, hence skip 0x02 */
56: MATCH_ANY = 0x01,
57: /* IKE version matches exactly (config is not for any version) */
58: MATCH_VERSION = 0x04,
59: /* local identity matches */
60: MATCH_ME = 0x08,
61: /* remote identity matches */
62: MATCH_OTHER = 0x10,
63: } ike_cfg_match_t;
64:
65: /**
66: * data to pass nested IKE enumerator
67: */
68: typedef struct {
69: private_backend_manager_t *this;
70: host_t *me;
71: host_t *other;
72: } ike_data_t;
73:
74: /**
75: * inner enumerator constructor for IKE cfgs
76: */
77: static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
78: {
79: return backend->create_ike_cfg_enumerator(backend, data->me, data->other);
80: }
81:
82: /**
83: * get a match of a candidate ike_cfg for two hosts
84: */
85: static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other,
86: ike_version_t version)
87: {
88: ike_cfg_match_t match = MATCH_NONE;
89: int quality;
90:
91: if (cand->get_version(cand) != IKE_ANY &&
92: version != cand->get_version(cand))
93: {
94: return MATCH_NONE;
95: }
96:
97: if (me)
98: {
99: quality = cand->match_me(cand, me);
100: if (!quality)
101: {
102: return MATCH_NONE;
103: }
104: match += quality * MATCH_ME;
105: }
106: else
107: {
108: match += MATCH_ANY;
109: }
110:
111: if (other)
112: {
113: quality = cand->match_other(cand, other);
114: if (!quality)
115: {
116: return MATCH_NONE;
117: }
118: match += quality * MATCH_OTHER;
119: }
120: else
121: {
122: match += MATCH_ANY;
123: }
124:
125: if (match != MATCH_NONE &&
126: cand->get_version(cand) != IKE_ANY)
127: { /* if we have a match, improve it if candidate version specified */
128: match += MATCH_VERSION;
129: }
130: return match;
131: }
132:
133: /**
134: * list element to help sorting
135: */
136: typedef struct {
137: ike_cfg_match_t match;
138: ike_cfg_t *cfg;
139: } ike_match_entry_t;
140:
141: CALLBACK(ike_enum_filter, bool,
142: linked_list_t *configs, enumerator_t *orig, va_list args)
143: {
144: ike_match_entry_t *entry;
145: ike_cfg_t **out;
146:
147: VA_ARGS_VGET(args, out);
148:
149: if (orig->enumerate(orig, &entry))
150: {
151: *out = entry->cfg;
152: return TRUE;
153: }
154: return FALSE;
155: }
156:
157: CALLBACK(ike_match_entry_list_destroy, void,
158: linked_list_t *configs)
159: {
160: ike_match_entry_t *entry;
161:
162: while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
163: {
164: entry->cfg->destroy(entry->cfg);
165: free(entry);
166: }
167: configs->destroy(configs);
168: }
169:
170: /**
171: * Insert entry into match-sorted list
172: */
173: static void insert_sorted_ike(ike_match_entry_t *entry, linked_list_t *list)
174: {
175: enumerator_t *enumerator;
176: ike_match_entry_t *current;
177:
178: enumerator = list->create_enumerator(list);
179: while (enumerator->enumerate(enumerator, ¤t))
180: {
181: if (entry->match > current->match)
182: {
183: break;
184: }
185: }
186: list->insert_before(list, enumerator, entry);
187: enumerator->destroy(enumerator);
188: }
189:
190: /**
191: * Create a sorted list of all matching IKE configs
192: */
193: static linked_list_t *get_matching_ike_cfgs(private_backend_manager_t *this,
194: host_t *me, host_t *other,
195: ike_version_t version)
196: {
197: ike_cfg_t *current;
198: char *my_addr, *other_addr;
199: enumerator_t *enumerator;
200: ike_data_t *data;
201: linked_list_t *configs;
202: ike_cfg_match_t match;
203: ike_match_entry_t *entry;
204:
205: INIT(data,
206: .this = this,
207: .me = me,
208: .other = other,
209: );
210:
211: configs = linked_list_create();
212:
213: this->lock->read_lock(this->lock);
214: enumerator = enumerator_create_nested(
215: this->backends->create_enumerator(this->backends),
216: (void*)ike_enum_create, data, (void*)free);
217:
218: while (enumerator->enumerate(enumerator, ¤t))
219: {
220: my_addr = current->get_my_addr(current);
221: other_addr = current->get_other_addr(current);
222: match = get_ike_match(current, me, other, version);
223: DBG3(DBG_CFG, "ike config match: %d (%s...%s %N)", match, my_addr,
224: other_addr, ike_version_names, current->get_version(current));
225:
226: if (match)
227: {
228: DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
229: my_addr, other_addr, match);
230:
231: INIT(entry,
232: .match = match,
233: .cfg = current->get_ref(current),
234: );
235: insert_sorted_ike(entry, configs);
236: }
237: }
238: enumerator->destroy(enumerator);
239: this->lock->unlock(this->lock);
240:
241: return configs;
242: }
243:
244: METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
245: private_backend_manager_t *this, host_t *me, host_t *other,
246: ike_version_t version)
247: {
248: linked_list_t *configs;
249: ike_match_entry_t *entry;
250: ike_cfg_t *found = NULL;
251: char *my_addr, *other_addr;
252:
253: DBG2(DBG_CFG, "looking for an %N config for %H...%H", ike_version_names,
254: version, me, other);
255:
256: configs = get_matching_ike_cfgs(this, me, other, version);
257: if (configs->get_first(configs, (void**)&entry) == SUCCESS)
258: {
259: found = entry->cfg->get_ref(entry->cfg);
260:
261: my_addr = found->get_my_addr(found);
262: other_addr = found->get_other_addr(found);
263: DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
264: my_addr, other_addr, entry->match);
265: }
266: ike_match_entry_list_destroy(configs);
267:
268: return found;
269: }
270:
271: METHOD(backend_manager_t, create_ike_cfg_enumerator, enumerator_t*,
272: private_backend_manager_t *this, host_t *me, host_t *other,
273: ike_version_t version)
274: {
275: linked_list_t *configs;
276:
277: DBG2(DBG_CFG, "looking for %N configs for %H...%H", ike_version_names,
278: version, me, other);
279:
280: configs = get_matching_ike_cfgs(this, me, other, version);
281:
282: return enumerator_create_filter(configs->create_enumerator(configs),
283: ike_enum_filter, configs,
284: ike_match_entry_list_destroy);
285: }
286:
287: /**
288: * Get the best ID match in one of the configs auth_cfg
289: */
290: static id_match_t get_peer_match(identification_t *id,
291: peer_cfg_t *cfg, bool local)
292: {
293: enumerator_t *enumerator;
294: auth_cfg_t *auth;
295: identification_t *candidate;
296: id_match_t match = ID_MATCH_NONE;
297: char *where = local ? "local" : "remote";
298: chunk_t data;
299:
300: if (!id)
301: {
302: DBG3(DBG_CFG, " %s id match: %d (%N)",
303: where, ID_MATCH_ANY, id_type_names, ID_ANY);
304: return ID_MATCH_ANY;
305: }
306:
307: /* compare first auth config only */
308: enumerator = cfg->create_auth_cfg_enumerator(cfg, local);
309: if (enumerator->enumerate(enumerator, &auth))
310: {
311: candidate = auth->get(auth, AUTH_RULE_IDENTITY);
312: if (candidate)
313: {
314: match = id->matches(id, candidate);
315: /* match vice-versa, as the proposed IDr might be ANY */
316: if (!match)
317: {
318: match = candidate->matches(candidate, id);
319: }
320: }
321: else
322: {
323: match = ID_MATCH_ANY;
324: }
325: }
326: enumerator->destroy(enumerator);
327:
328: data = id->get_encoding(id);
329: DBG3(DBG_CFG, " %s id match: %d (%N: %#B)",
330: where, match, id_type_names, id->get_type(id), &data);
331: return match;
332: }
333:
334: /**
335: * data to pass nested peer enumerator
336: */
337: typedef struct {
338: rwlock_t *lock;
339: identification_t *me;
340: identification_t *other;
341: } peer_data_t;
342:
343: /**
344: * list element to help sorting
345: */
346: typedef struct {
347: id_match_t match_peer;
348: ike_cfg_match_t match_ike;
349: peer_cfg_t *cfg;
350: } match_entry_t;
351:
352: /**
353: * inner enumerator constructor for peer cfgs
354: */
355: static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data)
356: {
357: return backend->create_peer_cfg_enumerator(backend, data->me, data->other);
358: }
359:
360: /**
361: * unlock/cleanup peer enumerator
362: */
363: static void peer_enum_destroy(peer_data_t *data)
364: {
365: data->lock->unlock(data->lock);
366: free(data);
367: }
368:
369: CALLBACK(peer_enum_filter, bool,
370: linked_list_t *configs, enumerator_t *orig, va_list args)
371: {
372: match_entry_t *entry;
373: peer_cfg_t **out;
374:
375: VA_ARGS_VGET(args, out);
376:
377: if (orig->enumerate(orig, &entry))
378: {
379: *out = entry->cfg;
380: return TRUE;
381: }
382: return FALSE;
383: }
384:
385: CALLBACK(peer_enum_filter_destroy, void,
386: linked_list_t *configs)
387: {
388: match_entry_t *entry;
389:
390: while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
391: {
392: entry->cfg->destroy(entry->cfg);
393: free(entry);
394: }
395: configs->destroy(configs);
396: }
397:
398: /**
399: * Insert entry into match-sorted list
400: */
401: static void insert_sorted(match_entry_t *entry, linked_list_t *list)
402: {
403: enumerator_t *enumerator;
404: match_entry_t *current;
405:
406: enumerator = list->create_enumerator(list);
407: while (enumerator->enumerate(enumerator, ¤t))
408: {
409: if ((entry->match_ike > current->match_ike &&
410: entry->match_peer >= current->match_peer) ||
411: (entry->match_ike >= current->match_ike &&
412: entry->match_peer > current->match_peer))
413: {
414: break;
415: }
416: }
417: list->insert_before(list, enumerator, entry);
418: enumerator->destroy(enumerator);
419: }
420:
421: METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
422: private_backend_manager_t *this, host_t *me, host_t *other,
423: identification_t *my_id, identification_t *other_id, ike_version_t version)
424: {
425: enumerator_t *enumerator;
426: peer_data_t *data;
427: peer_cfg_t *cfg;
428: linked_list_t *configs;
429:
430: INIT(data,
431: .lock = this->lock,
432: .me = my_id,
433: .other = other_id,
434: );
435:
436: /* create a sorted list with all matches */
437: this->lock->read_lock(this->lock);
438: enumerator = enumerator_create_nested(
439: this->backends->create_enumerator(this->backends),
440: (void*)peer_enum_create, data, (void*)peer_enum_destroy);
441:
442: if (!me && !other && !my_id && !other_id)
443: { /* shortcut if we are doing a "listall" */
444: return enumerator;
445: }
446:
447: configs = linked_list_create();
448: while (enumerator->enumerate(enumerator, &cfg))
449: {
450: ike_cfg_t *ike_cfg = cfg->get_ike_cfg(cfg);
451: ike_cfg_match_t match_ike;
452: id_match_t match_peer_me, match_peer_other;
453: match_entry_t *entry;
454: char *my_addr, *other_addr;
455:
456: match_ike = get_ike_match(ike_cfg, me, other, version);
457: my_addr = ike_cfg->get_my_addr(ike_cfg);
458: other_addr = ike_cfg->get_other_addr(ike_cfg);
459: DBG3(DBG_CFG, "peer config \"%s\", ike match: %d (%s...%s %N)",
460: cfg->get_name(cfg), match_ike, my_addr, other_addr,
461: ike_version_names, ike_cfg->get_version(ike_cfg));
462:
463: if (!match_ike)
464: {
465: continue;
466: }
467:
468: match_peer_me = get_peer_match(my_id, cfg, TRUE);
469: if (!match_peer_me)
470: {
471: continue;
472: }
473: match_peer_other = get_peer_match(other_id, cfg, FALSE);
474:
475: if (match_peer_other)
476: {
477: DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)",
478: cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike);
479: INIT(entry,
480: .match_peer = match_peer_me + match_peer_other,
481: .match_ike = match_ike,
482: .cfg = cfg->get_ref(cfg),
483: );
484: insert_sorted(entry, configs);
485: }
486: }
487: enumerator->destroy(enumerator);
488:
489: return enumerator_create_filter(configs->create_enumerator(configs),
490: peer_enum_filter, configs,
491: peer_enum_filter_destroy);
492: }
493:
494: METHOD(backend_manager_t, get_peer_cfg_by_name, peer_cfg_t*,
495: private_backend_manager_t *this, char *name)
496: {
497: backend_t *backend;
498: peer_cfg_t *config = NULL;
499: enumerator_t *enumerator;
500:
501: this->lock->read_lock(this->lock);
502: enumerator = this->backends->create_enumerator(this->backends);
503: while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend))
504: {
505: config = backend->get_peer_cfg_by_name(backend, name);
506: }
507: enumerator->destroy(enumerator);
508: this->lock->unlock(this->lock);
509: return config;
510: }
511:
512: METHOD(backend_manager_t, remove_backend, void,
513: private_backend_manager_t *this, backend_t *backend)
514: {
515: this->lock->write_lock(this->lock);
516: this->backends->remove(this->backends, backend, NULL);
517: this->lock->unlock(this->lock);
518: }
519:
520: METHOD(backend_manager_t, add_backend, void,
521: private_backend_manager_t *this, backend_t *backend)
522: {
523: this->lock->write_lock(this->lock);
524: this->backends->insert_last(this->backends, backend);
525: this->lock->unlock(this->lock);
526: }
527:
528: METHOD(backend_manager_t, destroy, void,
529: private_backend_manager_t *this)
530: {
531: this->backends->destroy(this->backends);
532: this->lock->destroy(this->lock);
533: free(this);
534: }
535:
536: /*
537: * Described in header
538: */
539: backend_manager_t *backend_manager_create()
540: {
541: private_backend_manager_t *this;
542:
543: INIT(this,
544: .public = {
545: .get_ike_cfg = _get_ike_cfg,
546: .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
547: .get_peer_cfg_by_name = _get_peer_cfg_by_name,
548: .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
549: .add_backend = _add_backend,
550: .remove_backend = _remove_backend,
551: .destroy = _destroy,
552: },
553: .backends = linked_list_create(),
554: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
555: );
556:
557: return &this->public;
558: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>