2 * Copyright (C) 2007-2009 Martin Willi
3 * Copyright (C) 2008 Tobias Brunner
4 * Hochschule fuer Technik Rapperswil
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>.
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
21 #include <utils/linked_list.h>
22 #include <utils/identification.h>
24 #include <credentials/certificates/certificate.h>
26 ENUM(auth_class_names
, AUTH_CLASS_ANY
, AUTH_CLASS_EAP
,
33 typedef struct private_auth_cfg_t private_auth_cfg_t
;
36 * private data of item_set
38 struct private_auth_cfg_t
{
48 linked_list_t
*entries
;
51 typedef struct entry_t entry_t
;
56 /** associated value */
61 * enumerator for auth_cfg_t.create_enumerator()
64 /** implements enumerator_t */
66 /** inner enumerator from linked_list_t */
73 * enumerate function for item_enumerator_t
75 static bool enumerate(entry_enumerator_t
*this, auth_rule_t
*type
, void **value
)
79 if (this->inner
->enumerate(this->inner
, &entry
))
81 this->current
= entry
;
83 *value
= entry
->value
;
90 * destroy function for item_enumerator_t
92 static void entry_enumerator_destroy(entry_enumerator_t
*this)
94 this->inner
->destroy(this->inner
);
99 * Implementation of auth_cfg_t.create_enumerator.
101 static enumerator_t
* create_enumerator(private_auth_cfg_t
*this)
103 entry_enumerator_t
*enumerator
;
105 enumerator
= malloc_thing(entry_enumerator_t
);
106 enumerator
->inner
= this->entries
->create_enumerator(this->entries
);
107 enumerator
->public.enumerate
= (void*)enumerate
;
108 enumerator
->public.destroy
= (void*)entry_enumerator_destroy
;
109 enumerator
->current
= NULL
;
110 return &enumerator
->public;
114 * Destroy the value associated with an entry
116 static void destroy_entry_value(entry_t
*entry
)
120 case AUTH_RULE_IDENTITY
:
121 case AUTH_RULE_EAP_IDENTITY
:
122 case AUTH_RULE_GROUP
:
124 identification_t
*id
= (identification_t
*)entry
->value
;
128 case AUTH_RULE_CA_CERT
:
129 case AUTH_RULE_IM_CERT
:
130 case AUTH_RULE_SUBJECT_CERT
:
131 case AUTH_HELPER_IM_CERT
:
132 case AUTH_HELPER_SUBJECT_CERT
:
134 certificate_t
*cert
= (certificate_t
*)entry
->value
;
138 case AUTH_HELPER_IM_HASH_URL
:
139 case AUTH_HELPER_SUBJECT_HASH_URL
:
144 case AUTH_RULE_AUTH_CLASS
:
145 case AUTH_RULE_EAP_TYPE
:
146 case AUTH_RULE_EAP_VENDOR
:
147 case AUTH_RULE_CRL_VALIDATION
:
148 case AUTH_RULE_OCSP_VALIDATION
:
154 * Implementation of auth_cfg_t.replace.
156 static void replace(auth_cfg_t
*this, entry_enumerator_t
*enumerator
,
157 auth_rule_t type
, ...)
159 if (enumerator
->current
)
163 va_start(args
, type
);
165 destroy_entry_value(enumerator
->current
);
166 enumerator
->current
->type
= type
;
169 case AUTH_RULE_AUTH_CLASS
:
170 case AUTH_RULE_EAP_TYPE
:
171 case AUTH_RULE_EAP_VENDOR
:
172 case AUTH_RULE_CRL_VALIDATION
:
173 case AUTH_RULE_OCSP_VALIDATION
:
175 enumerator
->current
->value
= (void*)(uintptr_t)va_arg(args
, u_int
);
177 case AUTH_RULE_IDENTITY
:
178 case AUTH_RULE_EAP_IDENTITY
:
179 case AUTH_RULE_GROUP
:
180 case AUTH_RULE_CA_CERT
:
181 case AUTH_RULE_IM_CERT
:
182 case AUTH_RULE_SUBJECT_CERT
:
183 case AUTH_HELPER_IM_CERT
:
184 case AUTH_HELPER_SUBJECT_CERT
:
185 case AUTH_HELPER_IM_HASH_URL
:
186 case AUTH_HELPER_SUBJECT_HASH_URL
:
188 enumerator
->current
->value
= va_arg(args
, void*);
196 * Implementation of auth_cfg_t.get.
198 static void* get(private_auth_cfg_t
*this, auth_rule_t type
)
200 enumerator_t
*enumerator
;
201 void *current_value
, *best_value
= NULL
;
202 auth_rule_t current_type
;
205 enumerator
= create_enumerator(this);
206 while (enumerator
->enumerate(enumerator
, ¤t_type
, ¤t_value
))
208 if (type
== current_type
)
210 if (type
== AUTH_RULE_CRL_VALIDATION
||
211 type
== AUTH_RULE_OCSP_VALIDATION
)
212 { /* for CRL/OCSP validation, always get() the highest value */
213 if (!found
|| current_value
> best_value
)
215 best_value
= current_value
;
220 best_value
= current_value
;
225 enumerator
->destroy(enumerator
);
232 /* use some sane defaults if we don't find an entry */
233 case AUTH_RULE_AUTH_CLASS
:
234 return (void*)AUTH_CLASS_ANY
;
235 case AUTH_RULE_EAP_TYPE
:
236 return (void*)EAP_NAK
;
237 case AUTH_RULE_EAP_VENDOR
:
239 case AUTH_RULE_CRL_VALIDATION
:
240 case AUTH_RULE_OCSP_VALIDATION
:
241 return (void*)VALIDATION_FAILED
;
242 case AUTH_RULE_IDENTITY
:
243 case AUTH_RULE_EAP_IDENTITY
:
244 case AUTH_RULE_GROUP
:
245 case AUTH_RULE_CA_CERT
:
246 case AUTH_RULE_IM_CERT
:
247 case AUTH_RULE_SUBJECT_CERT
:
248 case AUTH_HELPER_IM_CERT
:
249 case AUTH_HELPER_SUBJECT_CERT
:
250 case AUTH_HELPER_IM_HASH_URL
:
251 case AUTH_HELPER_SUBJECT_HASH_URL
:
258 * Implementation of auth_cfg_t.add.
260 static void add(private_auth_cfg_t
*this, auth_rule_t type
, ...)
262 entry_t
*entry
= malloc_thing(entry_t
);
265 va_start(args
, type
);
269 case AUTH_RULE_AUTH_CLASS
:
270 case AUTH_RULE_EAP_TYPE
:
271 case AUTH_RULE_EAP_VENDOR
:
272 case AUTH_RULE_CRL_VALIDATION
:
273 case AUTH_RULE_OCSP_VALIDATION
:
275 entry
->value
= (void*)(uintptr_t)va_arg(args
, u_int
);
277 case AUTH_RULE_IDENTITY
:
278 case AUTH_RULE_EAP_IDENTITY
:
279 case AUTH_RULE_GROUP
:
280 case AUTH_RULE_CA_CERT
:
281 case AUTH_RULE_IM_CERT
:
282 case AUTH_RULE_SUBJECT_CERT
:
283 case AUTH_HELPER_IM_CERT
:
284 case AUTH_HELPER_SUBJECT_CERT
:
285 case AUTH_HELPER_IM_HASH_URL
:
286 case AUTH_HELPER_SUBJECT_HASH_URL
:
288 entry
->value
= va_arg(args
, void*);
292 this->entries
->insert_last(this->entries
, entry
);
296 * Implementation of auth_cfg_t.complies.
298 static bool complies(private_auth_cfg_t
*this, auth_cfg_t
*constraints
,
301 enumerator_t
*e1
, *e2
;
302 bool success
= TRUE
, has_group
= FALSE
, group_match
= FALSE
;
306 e1
= constraints
->create_enumerator(constraints
);
307 while (e1
->enumerate(e1
, &t1
, &value
))
311 case AUTH_RULE_CA_CERT
:
312 case AUTH_RULE_IM_CERT
:
314 certificate_t
*c1
, *c2
;
316 c1
= (certificate_t
*)value
;
319 e2
= create_enumerator(this);
320 while (e2
->enumerate(e2
, &t2
, &c2
))
322 if ((t2
== AUTH_RULE_CA_CERT
|| t2
== AUTH_RULE_IM_CERT
) &&
329 if (!success
&& log_error
)
331 DBG1(DBG_CFG
, "constraint check failed: peer not "
332 "authenticated by CA '%Y'.", c1
->get_subject(c1
));
336 case AUTH_RULE_SUBJECT_CERT
:
338 certificate_t
*c1
, *c2
;
340 c1
= (certificate_t
*)value
;
341 c2
= get(this, AUTH_RULE_SUBJECT_CERT
);
342 if (!c2
|| !c1
->equals(c1
, c2
))
347 DBG1(DBG_CFG
, "constraint check failed: peer not "
348 "authenticated with peer cert '%Y'.",
349 c1
->get_subject(c1
));
354 case AUTH_RULE_CRL_VALIDATION
:
355 case AUTH_RULE_OCSP_VALIDATION
:
357 cert_validation_t validated
, required
;
359 required
= (uintptr_t)value
;
360 validated
= (uintptr_t)get(this, t1
);
363 case VALIDATION_FAILED
:
366 case VALIDATION_SKIPPED
:
367 if (validated
== VALIDATION_SKIPPED
)
372 case VALIDATION_GOOD
:
373 if (validated
== VALIDATION_GOOD
)
382 DBG1(DBG_CFG
, "constraint check failed: %N is %N, "
383 "but requires at least %N", auth_rule_names
,
384 t1
, cert_validation_names
, validated
,
385 cert_validation_names
, required
);
391 case AUTH_RULE_IDENTITY
:
392 case AUTH_RULE_EAP_IDENTITY
:
394 identification_t
*id1
, *id2
;
396 id1
= (identification_t
*)value
;
398 if (!id2
|| !id2
->matches(id2
, id1
))
403 DBG1(DBG_CFG
, "constraint check failed: %sidentity '%Y'"
404 " required ", t1
== AUTH_RULE_IDENTITY ?
"" :
410 case AUTH_RULE_AUTH_CLASS
:
412 if ((uintptr_t)value
!= AUTH_CLASS_ANY
&&
413 (uintptr_t)value
!= (uintptr_t)get(this, t1
))
418 DBG1(DBG_CFG
, "constraint requires %N authentication, "
419 "but %N was used", auth_class_names
, (uintptr_t)value
,
420 auth_class_names
, (uintptr_t)get(this, t1
));
425 case AUTH_RULE_EAP_TYPE
:
427 if ((uintptr_t)value
!= (uintptr_t)get(this, t1
))
432 DBG1(DBG_CFG
, "constraint requires %N, "
433 "but %N was used", eap_type_names
, (uintptr_t)value
,
434 eap_type_names
, (uintptr_t)get(this, t1
));
439 case AUTH_RULE_EAP_VENDOR
:
441 if ((uintptr_t)value
!= (uintptr_t)get(this, t1
))
446 DBG1(DBG_CFG
, "constraint requires EAP vendor %d, "
447 "but %d was used", (uintptr_t)value
,
448 (uintptr_t)get(this, t1
));
453 case AUTH_RULE_GROUP
:
455 identification_t
*id1
, *id2
;
457 /* for groups, a match of a single group is sufficient */
459 id1
= (identification_t
*)value
;
460 e2
= create_enumerator(this);
461 while (e2
->enumerate(e2
, &t2
, &id2
))
463 if (t2
== AUTH_RULE_GROUP
&& id2
->matches(id2
, id1
))
471 case AUTH_HELPER_IM_CERT
:
472 case AUTH_HELPER_SUBJECT_CERT
:
473 case AUTH_HELPER_IM_HASH_URL
:
474 case AUTH_HELPER_SUBJECT_HASH_URL
:
485 if (has_group
&& !group_match
)
489 DBG1(DBG_CFG
, "constraint check failed: group membership required");
497 * Implementation of auth_cfg_t.merge.
499 static void merge(private_auth_cfg_t
*this, private_auth_cfg_t
*other
, bool copy
)
502 { /* nothing to merge */
507 enumerator_t
*enumerator
;
511 enumerator
= create_enumerator(other
);
512 while (enumerator
->enumerate(enumerator
, &type
, &value
))
516 case AUTH_RULE_CA_CERT
:
517 case AUTH_RULE_IM_CERT
:
518 case AUTH_RULE_SUBJECT_CERT
:
519 case AUTH_HELPER_IM_CERT
:
520 case AUTH_HELPER_SUBJECT_CERT
:
522 certificate_t
*cert
= (certificate_t
*)value
;
524 add(this, type
, cert
->get_ref(cert
));
527 case AUTH_RULE_CRL_VALIDATION
:
528 case AUTH_RULE_OCSP_VALIDATION
:
529 case AUTH_RULE_AUTH_CLASS
:
530 case AUTH_RULE_EAP_TYPE
:
531 case AUTH_RULE_EAP_VENDOR
:
533 add(this, type
, (uintptr_t)value
);
536 case AUTH_RULE_IDENTITY
:
537 case AUTH_RULE_EAP_IDENTITY
:
538 case AUTH_RULE_GROUP
:
540 identification_t
*id
= (identification_t
*)value
;
542 add(this, type
, id
->clone(id
));
545 case AUTH_HELPER_IM_HASH_URL
:
546 case AUTH_HELPER_SUBJECT_HASH_URL
:
548 add(this, type
, strdup((char*)value
));
553 enumerator
->destroy(enumerator
);
559 while (other
->entries
->remove_first(other
->entries
,
560 (void**)&entry
) == SUCCESS
)
562 this->entries
->insert_last(this->entries
, entry
);
568 * Implementation of auth_cfg_t.equals.
570 static bool equals(private_auth_cfg_t
*this, private_auth_cfg_t
*other
)
572 enumerator_t
*e1
, *e2
;
574 bool equal
= TRUE
, found
;
576 if (this->entries
->get_count(this->entries
) !=
577 other
->entries
->get_count(other
->entries
))
581 e1
= this->entries
->create_enumerator(this->entries
);
582 while (e1
->enumerate(e1
, &i1
))
585 e2
= other
->entries
->create_enumerator(other
->entries
);
586 while (e2
->enumerate(e2
, &i2
))
588 if (i1
->type
== i2
->type
)
592 case AUTH_RULE_AUTH_CLASS
:
593 case AUTH_RULE_EAP_TYPE
:
594 case AUTH_RULE_EAP_VENDOR
:
595 case AUTH_RULE_CRL_VALIDATION
:
596 case AUTH_RULE_OCSP_VALIDATION
:
598 if (i1
->value
== i2
->value
)
605 case AUTH_RULE_CA_CERT
:
606 case AUTH_RULE_IM_CERT
:
607 case AUTH_RULE_SUBJECT_CERT
:
608 case AUTH_HELPER_IM_CERT
:
609 case AUTH_HELPER_SUBJECT_CERT
:
611 certificate_t
*c1
, *c2
;
613 c1
= (certificate_t
*)i1
->value
;
614 c2
= (certificate_t
*)i2
->value
;
616 if (c1
->equals(c1
, c2
))
623 case AUTH_RULE_IDENTITY
:
624 case AUTH_RULE_EAP_IDENTITY
:
625 case AUTH_RULE_GROUP
:
627 identification_t
*id1
, *id2
;
629 id1
= (identification_t
*)i1
->value
;
630 id2
= (identification_t
*)i2
->value
;
632 if (id1
->equals(id1
, id2
))
639 case AUTH_HELPER_IM_HASH_URL
:
640 case AUTH_HELPER_SUBJECT_HASH_URL
:
642 if (streq(i1
->value
, i2
->value
))
665 * Implementation of auth_cfg_t.purge
667 static void purge(private_auth_cfg_t
*this, bool keep_ca
)
672 cas
= linked_list_create();
673 while (this->entries
->remove_last(this->entries
, (void**)&entry
) == SUCCESS
)
675 if (keep_ca
&& entry
->type
== AUTH_RULE_CA_CERT
)
677 cas
->insert_first(cas
, entry
);
681 destroy_entry_value(entry
);
685 while (cas
->remove_last(cas
, (void**)&entry
) == SUCCESS
)
687 this->entries
->insert_first(this->entries
, entry
);
693 * Implementation of auth_cfg_t.clone
695 static auth_cfg_t
* clone_(private_auth_cfg_t
*this)
697 enumerator_t
*enumerator
;
701 clone
= auth_cfg_create();
702 enumerator
= this->entries
->create_enumerator(this->entries
);
703 while (enumerator
->enumerate(enumerator
, &entry
))
707 case AUTH_RULE_IDENTITY
:
708 case AUTH_RULE_EAP_IDENTITY
:
709 case AUTH_RULE_GROUP
:
711 identification_t
*id
= (identification_t
*)entry
->value
;
712 clone
->add(clone
, entry
->type
, id
->clone(id
));
715 case AUTH_RULE_CA_CERT
:
716 case AUTH_RULE_IM_CERT
:
717 case AUTH_RULE_SUBJECT_CERT
:
718 case AUTH_HELPER_IM_CERT
:
719 case AUTH_HELPER_SUBJECT_CERT
:
721 certificate_t
*cert
= (certificate_t
*)entry
->value
;
722 clone
->add(clone
, entry
->type
, cert
->get_ref(cert
));
725 case AUTH_HELPER_IM_HASH_URL
:
726 case AUTH_HELPER_SUBJECT_HASH_URL
:
728 clone
->add(clone
, entry
->type
, strdup(entry
->value
));
731 case AUTH_RULE_AUTH_CLASS
:
732 case AUTH_RULE_EAP_TYPE
:
733 case AUTH_RULE_EAP_VENDOR
:
734 case AUTH_RULE_CRL_VALIDATION
:
735 case AUTH_RULE_OCSP_VALIDATION
:
736 clone
->add(clone
, entry
->type
, (uintptr_t)entry
->value
);
740 enumerator
->destroy(enumerator
);
745 * Implementation of auth_cfg_t.destroy
747 static void destroy(private_auth_cfg_t
*this)
750 this->entries
->destroy(this->entries
);
757 auth_cfg_t
*auth_cfg_create()
759 private_auth_cfg_t
*this = malloc_thing(private_auth_cfg_t
);
761 this->public.add
= (void(*)(auth_cfg_t
*, auth_rule_t type
, ...))add
;
762 this->public.get
= (void*(*)(auth_cfg_t
*, auth_rule_t type
))get
;
763 this->public.create_enumerator
= (enumerator_t
*(*)(auth_cfg_t
*))create_enumerator
;
764 this->public.replace
= (void(*)(auth_cfg_t
*,enumerator_t
*,auth_rule_t
,...))replace
;
765 this->public.complies
= (bool(*)(auth_cfg_t
*, auth_cfg_t
*,bool))complies
;
766 this->public.merge
= (void(*)(auth_cfg_t
*, auth_cfg_t
*other
,bool))merge
;
767 this->public.purge
= (void(*)(auth_cfg_t
*,bool))purge
;
768 this->public.equals
= (bool(*)(auth_cfg_t
*, auth_cfg_t
*other
))equals
;
769 this->public.clone
= (auth_cfg_t
*(*)(auth_cfg_t
*))clone_
;
770 this->public.destroy
= (void(*)(auth_cfg_t
*))destroy
;
772 this->entries
= linked_list_create();
774 return &this->public;