2 * @file local_backend.c
4 * @brief Implementation of local_backend_t.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
25 #include "local_backend.h"
28 #include <utils/linked_list.h>
29 #include <crypto/ca.h>
32 typedef struct private_local_backend_t private_local_backend_t
;
35 * Private data of an local_backend_t object
37 struct private_local_backend_t
{
42 local_backend_t
public;
50 * Mutex to exclusivly access list
52 pthread_mutex_t mutex
;
56 * implements backen_t.get_ike_cfg.
58 static ike_cfg_t
*get_ike_cfg(private_local_backend_t
*this,
59 host_t
*my_host
, host_t
*other_host
)
62 ike_cfg_t
*current
, *found
= NULL
;
64 host_t
*my_candidate
, *other_candidate
;
70 } prio
, best
= MATCH_ANY
;
72 DBG2(DBG_CFG
, "looking for a config for %H...%H",
75 iterator
= this->cfgs
->create_iterator_locked(this->cfgs
, &this->mutex
);
76 while (iterator
->iterate(iterator
, (void**)&peer
))
79 current
= peer
->get_ike_cfg(peer
);
80 my_candidate
= current
->get_my_host(current
);
81 other_candidate
= current
->get_other_host(current
);
83 if (my_candidate
->ip_equals(my_candidate
, my_host
))
87 else if (my_candidate
->is_anyaddr(my_candidate
))
92 if (other_candidate
->ip_equals(other_candidate
, other_host
))
96 else if (other_candidate
->is_anyaddr(other_candidate
))
101 DBG2(DBG_CFG
, " candidate '%s': %H...%H, prio %d",
102 peer
->get_name(peer
), my_candidate
, other_candidate
, prio
);
104 /* we require at least two MATCH_ANY */
113 found
->get_ref(found
);
115 iterator
->destroy(iterator
);
119 #define PRIO_NO_MATCH_FOUND 256
122 * implements backend_t.get_peer.
124 static peer_cfg_t
*get_peer_cfg(private_local_backend_t
*this,
125 identification_t
*my_id
, identification_t
*other_id
,
126 ca_info_t
*other_ca_info
)
128 peer_cfg_t
*current
, *found
= NULL
;
129 iterator_t
*iterator
;
130 identification_t
*my_candidate
, *other_candidate
;
131 int best
= PRIO_NO_MATCH_FOUND
;
133 DBG2(DBG_CFG
, "looking for a config for %D...%D", my_id
, other_id
);
135 iterator
= this->cfgs
->create_iterator_locked(this->cfgs
, &this->mutex
);
136 while (iterator
->iterate(iterator
, (void**)¤t
))
140 my_candidate
= current
->get_my_id(current
);
141 other_candidate
= current
->get_other_id(current
);
143 if (my_candidate
->matches(my_candidate
, my_id
, &wc1
)
144 && other_id
->matches(other_id
, other_candidate
, &wc2
))
146 int prio
= (wc1
+ wc2
) * (MAX_CA_PATH_LEN
+ 1);
148 identification_t
*other_candidate_ca
= current
->get_other_ca(current
);
149 linked_list_t
*groups
= current
->get_groups(current
);
151 /* is a group membership required? */
152 if (groups
->get_count(groups
) > 0)
154 DBG1(DBG_CFG
, " group membership required");
157 /* are there any ca constraints? */
158 if (other_candidate_ca
->get_type(other_candidate_ca
) != ID_ANY
)
160 ca_info_t
*ca_info
= other_ca_info
;
162 for (pathlen
= 0; pathlen
< MAX_CA_PATH_LEN
; pathlen
++)
166 prio
= PRIO_NO_MATCH_FOUND
;
171 x509_t
*cacert
= ca_info
->get_certificate(ca_info
);
172 identification_t
*other_ca
= cacert
->get_subject(cacert
);
174 if (other_candidate_ca
->equals(other_candidate_ca
, other_ca
))
176 /* found a ca match */
179 if (cacert
->is_self_signed(cacert
))
181 /* reached the root ca without a match */
182 prio
= PRIO_NO_MATCH_FOUND
;
185 /* move a level upward in the trust path hierarchy */
186 ca_info
= charon
->credentials
->get_issuer(charon
->credentials
, cacert
);
189 if (pathlen
== MAX_CA_PATH_LEN
)
191 DBG1(DBG_CFG
, "maximum ca path length of %d levels reached", MAX_CA_PATH_LEN
);
192 prio
= PRIO_NO_MATCH_FOUND
;
195 if (prio
== PRIO_NO_MATCH_FOUND
)
197 DBG2(DBG_CFG
, " candidate '%s': %D...%D, no ca match",
198 current
->get_name(current
), my_candidate
, other_candidate
);
203 DBG2(DBG_CFG
, " candidate '%s': %D...%D, prio %d",
204 current
->get_name(current
), my_candidate
, other_candidate
, prio
);
216 DBG1(DBG_CFG
, "found matching config \"%s\": %D...%D, prio %d",
217 found
->get_name(found
),
218 found
->get_my_id(found
),
219 found
->get_other_id(found
),
221 found
->get_ref(found
);
223 iterator
->destroy(iterator
);
228 * implements backend_t.get_peer_cfg_by_name.
230 static peer_cfg_t
*get_peer_cfg_by_name(private_local_backend_t
*this, char *name
)
233 peer_cfg_t
*current
, *found
= NULL
;
236 i1
= this->cfgs
->create_iterator(this->cfgs
, TRUE
);
237 while (i1
->iterate(i1
, (void**)¤t
))
239 /* compare peer_cfgs name first */
240 if (streq(current
->get_name(current
), name
))
243 found
->get_ref(found
);
246 /* compare all child_cfg names otherwise */
247 i2
= current
->create_child_cfg_iterator(current
);
248 while (i2
->iterate(i2
, (void**)&child
))
250 if (streq(child
->get_name(child
), name
))
253 found
->get_ref(found
);
268 * Implementation of backend_t.is_writable.
270 static bool is_writeable(private_local_backend_t
*this)
276 * Implementation of writable_backend_t.create_iterator.
278 static iterator_t
* create_iterator(private_local_backend_t
*this)
280 return this->cfgs
->create_iterator_locked(this->cfgs
, &this->mutex
);
284 * Implementation of writable_backend_t.add_peer_cfg.
286 static void add_cfg(private_local_backend_t
*this, peer_cfg_t
*config
)
288 pthread_mutex_lock(&this->mutex
);
289 this->cfgs
->insert_last(this->cfgs
, config
);
290 pthread_mutex_unlock(&this->mutex
);
294 * Implementation of backend_t.destroy.
296 static void destroy(private_local_backend_t
*this)
298 this->cfgs
->destroy_offset(this->cfgs
, offsetof(peer_cfg_t
, destroy
));
303 * Described in header.
305 backend_t
*backend_create(void)
307 private_local_backend_t
*this = malloc_thing(private_local_backend_t
);
309 this->public.backend
.backend
.get_ike_cfg
= (ike_cfg_t
* (*)(backend_t
*, host_t
*, host_t
*))get_ike_cfg
;
310 this->public.backend
.backend
.get_peer_cfg
= (peer_cfg_t
* (*)(backend_t
*,identification_t
*,identification_t
*,ca_info_t
*))get_peer_cfg
;
311 this->public.backend
.backend
.get_peer_cfg_by_name
= (peer_cfg_t
* (*)(backend_t
*,char*))get_peer_cfg_by_name
;
312 this->public.backend
.backend
.is_writeable
= (bool(*) (backend_t
*))is_writeable
;
313 this->public.backend
.backend
.destroy
= (void (*)(backend_t
*))destroy
;
314 this->public.backend
.create_iterator
= (iterator_t
* (*)(writeable_backend_t
*))create_iterator
;
315 this->public.backend
.add_cfg
= (void (*)(writeable_backend_t
*,peer_cfg_t
*))add_cfg
;
317 /* private variables */
318 this->cfgs
= linked_list_create();
319 pthread_mutex_init(&this->mutex
, NULL
);
321 return &this->public.backend
.backend
;