/src/strongswan/src/libstrongswan/utils/identification.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2016 Andreas Steffen |
3 | | * Copyright (C) 2009-2025 Tobias Brunner |
4 | | * Copyright (C) 2005-2009 Martin Willi |
5 | | * Copyright (C) 2005 Jan Hutter |
6 | | * |
7 | | * Copyright (C) secunet Security Networks AG |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify it |
10 | | * under the terms of the GNU General Public License as published by the |
11 | | * Free Software Foundation; either version 2 of the License, or (at your |
12 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, but |
15 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
16 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
17 | | * for more details. |
18 | | */ |
19 | | |
20 | | #include <string.h> |
21 | | #include <stdio.h> |
22 | | #include <errno.h> |
23 | | |
24 | | #ifdef HAVE_REGEX |
25 | | #include <regex.h> |
26 | | #else |
27 | | /* usually, POSIX regular expressions are supported. for the rare case they are |
28 | | * not, e.g. when cross-compiling for Windows, we define some stubs to simplify |
29 | | * the implementation below */ |
30 | | typedef void regex_t; |
31 | | static int regexec(const regex_t *restrict preg, const char *restrict string, |
32 | | size_t nmatch, void *pmatch, int eflags) |
33 | | { |
34 | | return -1; |
35 | | } |
36 | | |
37 | | static void regfree(regex_t *preg) |
38 | | { |
39 | | } |
40 | | #endif /* HAVE_REGEX */ |
41 | | |
42 | | #include "identification.h" |
43 | | |
44 | | #include <utils/utils.h> |
45 | | #include <asn1/oid.h> |
46 | | #include <asn1/asn1.h> |
47 | | #include <crypto/hashers/hasher.h> |
48 | | #include <collections/array.h> |
49 | | |
50 | | ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS, |
51 | | "MATCH_NONE", |
52 | | "MATCH_ANY", |
53 | | "MATCH_MAX_WILDCARDS"); |
54 | | ENUM_NEXT(id_match_names, ID_MATCH_PERFECT, ID_MATCH_PERFECT, ID_MATCH_MAX_WILDCARDS, |
55 | | "MATCH_PERFECT"); |
56 | | ENUM_END(id_match_names, ID_MATCH_PERFECT); |
57 | | |
58 | | ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID, |
59 | | "ID_ANY", |
60 | | "ID_IPV4_ADDR", |
61 | | "ID_FQDN", |
62 | | "ID_RFC822_ADDR", |
63 | | "ID_IPV4_ADDR_SUBNET", |
64 | | "ID_IPV6_ADDR", |
65 | | "ID_IPV6_ADDR_SUBNET", |
66 | | "ID_IPV4_ADDR_RANGE", |
67 | | "ID_IPV6_ADDR_RANGE", |
68 | | "ID_DER_ASN1_DN", |
69 | | "ID_DER_ASN1_GN", |
70 | | "ID_KEY_ID"); |
71 | | ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_DER_ASN1_GN_URI, ID_KEY_ID, |
72 | | "ID_DER_ASN1_GN_URI"); |
73 | | ENUM_END(id_type_names, ID_DER_ASN1_GN_URI); |
74 | | |
75 | | /** |
76 | | * coding of X.501 distinguished name |
77 | | */ |
78 | | typedef struct { |
79 | | const u_char *name; |
80 | | int oid; |
81 | | u_char type; |
82 | | } x501rdn_t; |
83 | | |
84 | | static const x501rdn_t x501rdns[] = { |
85 | | {"ND", OID_NAME_DISTINGUISHER, ASN1_PRINTABLESTRING}, |
86 | | {"UID", OID_PILOT_USERID, ASN1_PRINTABLESTRING}, |
87 | | {"DC", OID_PILOT_DOMAIN_COMPONENT, ASN1_PRINTABLESTRING}, |
88 | | {"CN", OID_COMMON_NAME, ASN1_PRINTABLESTRING}, |
89 | | {"SN", OID_SURNAME, ASN1_PRINTABLESTRING}, |
90 | | {"serialNumber", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING}, |
91 | | {"C", OID_COUNTRY, ASN1_PRINTABLESTRING}, |
92 | | {"L", OID_LOCALITY, ASN1_PRINTABLESTRING}, |
93 | | {"ST", OID_STATE_OR_PROVINCE, ASN1_PRINTABLESTRING}, |
94 | | {"STREET", OID_STREET_ADDRESS, ASN1_PRINTABLESTRING}, |
95 | | {"O", OID_ORGANIZATION, ASN1_PRINTABLESTRING}, |
96 | | {"OU", OID_ORGANIZATION_UNIT, ASN1_PRINTABLESTRING}, |
97 | | {"organizationIdentifier", OID_ORGANIZATION_ID, ASN1_PRINTABLESTRING}, |
98 | | {"T", OID_TITLE, ASN1_PRINTABLESTRING}, |
99 | | {"D", OID_DESCRIPTION, ASN1_PRINTABLESTRING}, |
100 | | {"postalAddress", OID_POSTAL_ADDRESS, ASN1_PRINTABLESTRING}, |
101 | | {"postalCode", OID_POSTAL_CODE, ASN1_PRINTABLESTRING}, |
102 | | {"N", OID_NAME, ASN1_PRINTABLESTRING}, |
103 | | {"G", OID_GIVEN_NAME, ASN1_PRINTABLESTRING}, |
104 | | {"I", OID_INITIALS, ASN1_PRINTABLESTRING}, |
105 | | {"dnQualifier", OID_DN_QUALIFIER, ASN1_PRINTABLESTRING}, |
106 | | {"dmdName", OID_DMD_NAME, ASN1_PRINTABLESTRING}, |
107 | | {"pseudonym", OID_PSEUDONYM, ASN1_PRINTABLESTRING}, |
108 | | {"ID", OID_UNIQUE_IDENTIFIER, ASN1_PRINTABLESTRING}, |
109 | | {"EN", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING}, |
110 | | {"employeeNumber", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING}, |
111 | | {"E", OID_EMAIL_ADDRESS, ASN1_IA5STRING}, |
112 | | {"Email", OID_EMAIL_ADDRESS, ASN1_IA5STRING}, |
113 | | {"emailAddress", OID_EMAIL_ADDRESS, ASN1_IA5STRING}, |
114 | | {"UN", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING}, |
115 | | {"unstructuredName", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING}, |
116 | | {"UA", OID_UNSTRUCTURED_ADDRESS, ASN1_PRINTABLESTRING}, |
117 | | {"unstructuredAddress", OID_UNSTRUCTURED_ADDRESS, ASN1_PRINTABLESTRING}, |
118 | | {"TCGID", OID_TCGID, ASN1_PRINTABLESTRING}, |
119 | | }; |
120 | | |
121 | | /** |
122 | | * maximum number of RDNs in atodn() |
123 | | */ |
124 | 0 | #define RDN_MAX 20 |
125 | | |
126 | | typedef struct private_identification_t private_identification_t; |
127 | | |
128 | | /** |
129 | | * Private data of an identification_t object. |
130 | | */ |
131 | | struct private_identification_t { |
132 | | /** |
133 | | * Public interface. |
134 | | */ |
135 | | identification_t public; |
136 | | |
137 | | /** |
138 | | * Encoded representation of this ID. |
139 | | */ |
140 | | chunk_t encoded; |
141 | | |
142 | | /** |
143 | | * Type of this ID. |
144 | | */ |
145 | | id_type_t type; |
146 | | |
147 | | /** |
148 | | * Pointer if we use regex comparison. |
149 | | */ |
150 | | regex_t *regex; |
151 | | }; |
152 | | |
153 | | /** |
154 | | * Check that neither object uses a regex. |
155 | | */ |
156 | | static inline bool neither_is_regex(private_identification_t *this, |
157 | | identification_t *other) |
158 | 0 | { |
159 | 0 | private_identification_t *other_priv = (private_identification_t*)other; |
160 | 0 | return !this->regex && !other_priv->regex; |
161 | 0 | } |
162 | | |
163 | | /** |
164 | | * Enumerator over RDNs |
165 | | */ |
166 | | typedef struct { |
167 | | /* implements enumerator interface */ |
168 | | enumerator_t public; |
169 | | /* next set to parse, if any */ |
170 | | chunk_t sets; |
171 | | /* next sequence in set, if any */ |
172 | | chunk_t seqs; |
173 | | } rdn_enumerator_t; |
174 | | |
175 | | METHOD(enumerator_t, rdn_enumerate, bool, |
176 | | rdn_enumerator_t *this, va_list args) |
177 | 0 | { |
178 | 0 | chunk_t rdn, *oid, *data; |
179 | 0 | u_char *type; |
180 | |
|
181 | 0 | VA_ARGS_VGET(args, oid, type, data); |
182 | | |
183 | | /* a DN contains one or more SET, each containing one or more SEQUENCES, |
184 | | * each containing a OID/value RDN */ |
185 | 0 | if (!this->seqs.len) |
186 | 0 | { |
187 | | /* no SEQUENCEs in current SET, parse next SET */ |
188 | 0 | if (asn1_unwrap(&this->sets, &this->seqs) != ASN1_SET) |
189 | 0 | { |
190 | 0 | return FALSE; |
191 | 0 | } |
192 | 0 | } |
193 | 0 | if (asn1_unwrap(&this->seqs, &rdn) == ASN1_SEQUENCE && |
194 | 0 | asn1_unwrap(&rdn, oid) == ASN1_OID) |
195 | 0 | { |
196 | 0 | int t = asn1_unwrap(&rdn, data); |
197 | |
|
198 | 0 | if (t != ASN1_INVALID) |
199 | 0 | { |
200 | 0 | *type = t; |
201 | 0 | return TRUE; |
202 | 0 | } |
203 | 0 | } |
204 | 0 | return FALSE; |
205 | 0 | } |
206 | | |
207 | | /** |
208 | | * Create an enumerator over all RDNs (oid, string type, data) of a DN |
209 | | */ |
210 | | static enumerator_t *create_rdn_enumerator(chunk_t dn) |
211 | 0 | { |
212 | 0 | rdn_enumerator_t *e; |
213 | |
|
214 | 0 | INIT(e, |
215 | 0 | .public = { |
216 | 0 | .enumerate = enumerator_enumerate_default, |
217 | 0 | .venumerate = _rdn_enumerate, |
218 | 0 | .destroy = (void*)free, |
219 | 0 | }, |
220 | 0 | ); |
221 | | |
222 | | /* a DN is a SEQUENCE, get the first SET of it */ |
223 | 0 | if (asn1_unwrap(&dn, &e->sets) == ASN1_SEQUENCE) |
224 | 0 | { |
225 | 0 | e->seqs = chunk_empty; |
226 | 0 | return &e->public; |
227 | 0 | } |
228 | 0 | free(e); |
229 | 0 | return enumerator_create_empty(); |
230 | 0 | } |
231 | | |
232 | | /** |
233 | | * Part enumerator over RDNs |
234 | | */ |
235 | | typedef struct { |
236 | | /* implements enumerator interface */ |
237 | | enumerator_t public; |
238 | | /* inner RDN enumerator */ |
239 | | enumerator_t *inner; |
240 | | } rdn_part_enumerator_t; |
241 | | |
242 | | METHOD(enumerator_t, rdn_part_enumerate, bool, |
243 | | rdn_part_enumerator_t *this, va_list args) |
244 | 0 | { |
245 | 0 | int i, known_oid, strtype; |
246 | 0 | chunk_t oid, inner_data, *data; |
247 | 0 | id_part_t *type; |
248 | 0 | static const struct { |
249 | 0 | int oid; |
250 | 0 | id_part_t type; |
251 | 0 | } oid2part[] = { |
252 | 0 | {OID_COMMON_NAME, ID_PART_RDN_CN}, |
253 | 0 | {OID_SURNAME, ID_PART_RDN_SN}, |
254 | 0 | {OID_SERIAL_NUMBER, ID_PART_RDN_SERIAL_NUMBER}, |
255 | 0 | {OID_COUNTRY, ID_PART_RDN_C}, |
256 | 0 | {OID_LOCALITY, ID_PART_RDN_L}, |
257 | 0 | {OID_STATE_OR_PROVINCE, ID_PART_RDN_ST}, |
258 | 0 | {OID_ORGANIZATION, ID_PART_RDN_O}, |
259 | 0 | {OID_ORGANIZATION_UNIT, ID_PART_RDN_OU}, |
260 | 0 | {OID_TITLE, ID_PART_RDN_T}, |
261 | 0 | {OID_DESCRIPTION, ID_PART_RDN_D}, |
262 | 0 | {OID_NAME, ID_PART_RDN_N}, |
263 | 0 | {OID_GIVEN_NAME, ID_PART_RDN_G}, |
264 | 0 | {OID_INITIALS, ID_PART_RDN_I}, |
265 | 0 | {OID_DN_QUALIFIER, ID_PART_RDN_DNQ}, |
266 | 0 | {OID_DMD_NAME, ID_PART_RDN_DMDN}, |
267 | 0 | {OID_PSEUDONYM, ID_PART_RDN_PN}, |
268 | 0 | {OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID}, |
269 | 0 | {OID_EMAIL_ADDRESS, ID_PART_RDN_E}, |
270 | 0 | {OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN}, |
271 | 0 | }; |
272 | |
|
273 | 0 | VA_ARGS_VGET(args, type, data); |
274 | |
|
275 | 0 | while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data)) |
276 | 0 | { |
277 | 0 | known_oid = asn1_known_oid(oid); |
278 | 0 | for (i = 0; i < countof(oid2part); i++) |
279 | 0 | { |
280 | 0 | if (oid2part[i].oid == known_oid) |
281 | 0 | { |
282 | 0 | *type = oid2part[i].type; |
283 | 0 | *data = inner_data; |
284 | 0 | return TRUE; |
285 | 0 | } |
286 | 0 | } |
287 | 0 | } |
288 | 0 | return FALSE; |
289 | 0 | } |
290 | | |
291 | | METHOD(enumerator_t, rdn_part_enumerator_destroy, void, |
292 | | rdn_part_enumerator_t *this) |
293 | 0 | { |
294 | 0 | this->inner->destroy(this->inner); |
295 | 0 | free(this); |
296 | 0 | } |
297 | | |
298 | | METHOD(identification_t, create_part_enumerator, enumerator_t*, |
299 | | private_identification_t *this) |
300 | 0 | { |
301 | 0 | switch (this->type) |
302 | 0 | { |
303 | 0 | case ID_DER_ASN1_DN: |
304 | 0 | { |
305 | 0 | rdn_part_enumerator_t *e; |
306 | |
|
307 | 0 | INIT(e, |
308 | 0 | .inner = create_rdn_enumerator(this->encoded), |
309 | 0 | .public = { |
310 | 0 | .enumerate = enumerator_enumerate_default, |
311 | 0 | .venumerate = _rdn_part_enumerate, |
312 | 0 | .destroy = _rdn_part_enumerator_destroy, |
313 | 0 | }, |
314 | 0 | ); |
315 | 0 | return &e->public; |
316 | 0 | } |
317 | 0 | case ID_RFC822_ADDR: |
318 | | /* TODO */ |
319 | 0 | case ID_FQDN: |
320 | | /* TODO */ |
321 | 0 | default: |
322 | 0 | return enumerator_create_empty(); |
323 | 0 | } |
324 | 0 | } |
325 | | |
326 | | /** |
327 | | * Print a separator between two RDNs |
328 | | */ |
329 | | static inline bool print_separator(char **buf, size_t *len) |
330 | 0 | { |
331 | 0 | int written; |
332 | |
|
333 | 0 | written = snprintf(*buf, *len, ", "); |
334 | 0 | if (written < 0 || written >= *len) |
335 | 0 | { |
336 | 0 | return FALSE; |
337 | 0 | } |
338 | 0 | *buf += written; |
339 | 0 | *len -= written; |
340 | 0 | return TRUE; |
341 | 0 | } |
342 | | |
343 | | /** |
344 | | * Print a DN with all its RDN in a buffer to present it to the user |
345 | | */ |
346 | | static void dntoa(chunk_t dn, char *buf, size_t len) |
347 | 0 | { |
348 | 0 | enumerator_t *e; |
349 | 0 | chunk_t oid_data, data, printable; |
350 | 0 | u_char type; |
351 | 0 | int oid, written; |
352 | 0 | bool finished = FALSE, empty = TRUE; |
353 | |
|
354 | 0 | e = create_rdn_enumerator(dn); |
355 | 0 | while (e->enumerate(e, &oid_data, &type, &data)) |
356 | 0 | { |
357 | 0 | empty = FALSE; |
358 | | |
359 | | /* previous RDN was empty but it wasn't the last one */ |
360 | 0 | if (finished && !print_separator(&buf, &len)) |
361 | 0 | { |
362 | 0 | break; |
363 | 0 | } |
364 | 0 | finished = FALSE; |
365 | |
|
366 | 0 | oid = asn1_known_oid(oid_data); |
367 | 0 | if (oid == OID_UNKNOWN) |
368 | 0 | { |
369 | 0 | written = snprintf(buf, len, "%#B=", &oid_data); |
370 | 0 | } |
371 | 0 | else |
372 | 0 | { |
373 | 0 | written = snprintf(buf, len,"%s=", oid_names[oid].name); |
374 | 0 | } |
375 | 0 | if (written < 0 || written >= len) |
376 | 0 | { |
377 | 0 | break; |
378 | 0 | } |
379 | 0 | buf += written; |
380 | 0 | len -= written; |
381 | |
|
382 | 0 | written = 0; |
383 | 0 | chunk_printable(data, &printable, '?'); |
384 | 0 | if (printable.ptr) |
385 | 0 | { |
386 | 0 | written = snprintf(buf, len, "%.*s", (int)printable.len, |
387 | 0 | printable.ptr); |
388 | 0 | } |
389 | 0 | chunk_free(&printable); |
390 | 0 | if (written < 0 || written >= len) |
391 | 0 | { |
392 | 0 | break; |
393 | 0 | } |
394 | 0 | buf += written; |
395 | 0 | len -= written; |
396 | |
|
397 | 0 | if (!data.ptr) |
398 | 0 | { /* we can't calculate if we're finished, assume we are */ |
399 | 0 | finished = TRUE; |
400 | 0 | } |
401 | 0 | else if (data.ptr + data.len == dn.ptr + dn.len) |
402 | 0 | { |
403 | 0 | finished = TRUE; |
404 | 0 | break; |
405 | 0 | } |
406 | 0 | else if (!print_separator(&buf, &len)) |
407 | 0 | { |
408 | 0 | break; |
409 | 0 | } |
410 | 0 | } |
411 | 0 | if (empty) |
412 | 0 | { |
413 | 0 | snprintf(buf, len, ""); |
414 | 0 | } |
415 | 0 | else if (!finished) |
416 | 0 | { |
417 | 0 | snprintf(buf, len, "(invalid ID_DER_ASN1_DN)"); |
418 | 0 | } |
419 | 0 | e->destroy(e); |
420 | 0 | } |
421 | | |
422 | | /** |
423 | | * Converts an LDAP-style human-readable ASCII-encoded |
424 | | * ASN.1 distinguished name into binary DER-encoded format |
425 | | */ |
426 | | static status_t atodn(char *src, chunk_t *dn) |
427 | 0 | { |
428 | | /* finite state machine for atodn */ |
429 | 0 | typedef enum { |
430 | 0 | SEARCH_OID = 0, |
431 | 0 | READ_OID = 1, |
432 | 0 | SEARCH_NAME = 2, |
433 | 0 | READ_NAME = 3, |
434 | 0 | UNKNOWN_OID = 4 |
435 | 0 | } state_t; |
436 | |
|
437 | 0 | chunk_t oid = chunk_empty; |
438 | 0 | chunk_t name = chunk_empty; |
439 | 0 | chunk_t rdns[RDN_MAX]; |
440 | 0 | int rdn_count = 0; |
441 | 0 | int dn_len = 0; |
442 | 0 | int whitespace = 0; |
443 | 0 | int i = 0; |
444 | 0 | asn1_t rdn_type; |
445 | 0 | state_t state = SEARCH_OID; |
446 | 0 | status_t status = SUCCESS; |
447 | 0 | char sep = '\0'; |
448 | |
|
449 | 0 | do |
450 | 0 | { |
451 | 0 | switch (state) |
452 | 0 | { |
453 | 0 | case SEARCH_OID: |
454 | 0 | if (!sep && *src == '/') |
455 | 0 | { /* use / as separator if the string starts with a slash */ |
456 | 0 | sep = '/'; |
457 | 0 | break; |
458 | 0 | } |
459 | 0 | if (*src != ' ' && *src != '\0') |
460 | 0 | { |
461 | 0 | if (!sep) |
462 | 0 | { /* use , as separator by default */ |
463 | 0 | sep = ','; |
464 | 0 | } |
465 | 0 | oid.ptr = src; |
466 | 0 | oid.len = 1; |
467 | 0 | state = READ_OID; |
468 | 0 | } |
469 | 0 | break; |
470 | 0 | case READ_OID: |
471 | 0 | if (*src != ' ' && *src != '=') |
472 | 0 | { |
473 | 0 | oid.len++; |
474 | 0 | } |
475 | 0 | else |
476 | 0 | { |
477 | 0 | bool found = FALSE; |
478 | |
|
479 | 0 | for (i = 0; i < countof(x501rdns); i++) |
480 | 0 | { |
481 | 0 | if (strlen(x501rdns[i].name) == oid.len && |
482 | 0 | strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0) |
483 | 0 | { |
484 | 0 | found = TRUE; |
485 | 0 | break; |
486 | 0 | } |
487 | 0 | } |
488 | 0 | if (!found) |
489 | 0 | { |
490 | 0 | status = NOT_SUPPORTED; |
491 | 0 | state = UNKNOWN_OID; |
492 | 0 | break; |
493 | 0 | } |
494 | | /* reset oid and change state */ |
495 | 0 | oid = chunk_empty; |
496 | 0 | state = SEARCH_NAME; |
497 | 0 | } |
498 | 0 | break; |
499 | 0 | case SEARCH_NAME: |
500 | 0 | if (*src == ' ' || *src == '=') |
501 | 0 | { |
502 | 0 | break; |
503 | 0 | } |
504 | 0 | else if (*src != sep && *src != '\0') |
505 | 0 | { |
506 | 0 | name.ptr = src; |
507 | 0 | name.len = 1; |
508 | 0 | whitespace = 0; |
509 | 0 | state = READ_NAME; |
510 | 0 | break; |
511 | 0 | } |
512 | 0 | name = chunk_empty; |
513 | 0 | whitespace = 0; |
514 | 0 | state = READ_NAME; |
515 | | /* fall-through */ |
516 | 0 | case READ_NAME: |
517 | 0 | if (*src != sep && *src != '\0') |
518 | 0 | { |
519 | 0 | name.len++; |
520 | 0 | if (*src == ' ') |
521 | 0 | whitespace++; |
522 | 0 | else |
523 | 0 | whitespace = 0; |
524 | 0 | } |
525 | 0 | else |
526 | 0 | { |
527 | 0 | name.len -= whitespace; |
528 | 0 | rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING |
529 | 0 | && !asn1_is_printablestring(name)) |
530 | 0 | ? ASN1_UTF8STRING : x501rdns[i].type; |
531 | |
|
532 | 0 | if (rdn_count < RDN_MAX) |
533 | 0 | { |
534 | 0 | chunk_t rdn_oid; |
535 | |
|
536 | 0 | rdn_oid = asn1_build_known_oid(x501rdns[i].oid); |
537 | 0 | if (rdn_oid.len) |
538 | 0 | { |
539 | 0 | rdns[rdn_count] = |
540 | 0 | asn1_wrap(ASN1_SET, "m", |
541 | 0 | asn1_wrap(ASN1_SEQUENCE, "mm", |
542 | 0 | rdn_oid, |
543 | 0 | asn1_wrap(rdn_type, "c", name) |
544 | 0 | ) |
545 | 0 | ); |
546 | 0 | dn_len += rdns[rdn_count++].len; |
547 | 0 | } |
548 | 0 | else |
549 | 0 | { |
550 | 0 | status = INVALID_ARG; |
551 | 0 | } |
552 | 0 | } |
553 | 0 | else |
554 | 0 | { |
555 | 0 | status = OUT_OF_RES; |
556 | 0 | } |
557 | | /* reset name and change state */ |
558 | 0 | name = chunk_empty; |
559 | 0 | state = SEARCH_OID; |
560 | 0 | } |
561 | 0 | break; |
562 | 0 | case UNKNOWN_OID: |
563 | 0 | break; |
564 | 0 | } |
565 | 0 | } while (*src++ != '\0'); |
566 | | |
567 | 0 | if (state == READ_OID) |
568 | 0 | { /* unterminated OID */ |
569 | 0 | status = INVALID_ARG; |
570 | 0 | } |
571 | | |
572 | | /* build the distinguished name sequence */ |
573 | 0 | { |
574 | 0 | int i; |
575 | 0 | u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len); |
576 | |
|
577 | 0 | for (i = 0; i < rdn_count; i++) |
578 | 0 | { |
579 | 0 | memcpy(pos, rdns[i].ptr, rdns[i].len); |
580 | 0 | pos += rdns[i].len; |
581 | 0 | free(rdns[i].ptr); |
582 | 0 | } |
583 | 0 | } |
584 | 0 | if (status != SUCCESS) |
585 | 0 | { |
586 | 0 | free(dn->ptr); |
587 | 0 | *dn = chunk_empty; |
588 | 0 | } |
589 | 0 | return status; |
590 | 0 | } |
591 | | |
592 | | METHOD(identification_t, get_encoding, chunk_t, |
593 | | private_identification_t *this) |
594 | 0 | { |
595 | 0 | return this->encoded; |
596 | 0 | } |
597 | | |
598 | | METHOD(identification_t, get_type, id_type_t, |
599 | | private_identification_t *this) |
600 | 0 | { |
601 | 0 | return this->type; |
602 | 0 | } |
603 | | |
604 | | /** |
605 | | * Check if this is a wildcard value |
606 | | */ |
607 | | static inline bool is_wildcard(chunk_t data) |
608 | 0 | { |
609 | 0 | return data.len == 1 && data.ptr[0] == '*'; |
610 | 0 | } |
611 | | |
612 | | METHOD(identification_t, contains_wildcards_dn, bool, |
613 | | private_identification_t *this) |
614 | 0 | { |
615 | 0 | enumerator_t *enumerator; |
616 | 0 | bool contains = FALSE; |
617 | 0 | id_part_t type; |
618 | 0 | chunk_t data; |
619 | |
|
620 | 0 | enumerator = create_part_enumerator(this); |
621 | 0 | while (enumerator->enumerate(enumerator, &type, &data)) |
622 | 0 | { |
623 | 0 | if (is_wildcard(data)) |
624 | 0 | { |
625 | 0 | contains = TRUE; |
626 | 0 | break; |
627 | 0 | } |
628 | 0 | } |
629 | 0 | enumerator->destroy(enumerator); |
630 | 0 | return contains; |
631 | 0 | } |
632 | | |
633 | | METHOD(identification_t, contains_wildcards_memchr, bool, |
634 | | private_identification_t *this) |
635 | 0 | { |
636 | 0 | return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL; |
637 | 0 | } |
638 | | |
639 | | METHOD(identification_t, hash_binary, u_int, |
640 | | private_identification_t *this, u_int inc) |
641 | 0 | { |
642 | 0 | u_int hash; |
643 | |
|
644 | 0 | hash = chunk_hash_inc(chunk_from_thing(this->type), inc); |
645 | 0 | if (this->type != ID_ANY) |
646 | 0 | { |
647 | 0 | hash = chunk_hash_inc(this->encoded, hash); |
648 | 0 | } |
649 | 0 | if (this->regex) |
650 | 0 | { /* ensure regexes have different hashes even if type/encoding is equal */ |
651 | 0 | hash = chunk_hash_inc(chunk_from_chars(0x01), hash); |
652 | 0 | } |
653 | 0 | return hash; |
654 | 0 | } |
655 | | |
656 | | METHOD(identification_t, equals_binary, bool, |
657 | | private_identification_t *this, identification_t *other) |
658 | 0 | { |
659 | 0 | private_identification_t *other_priv = (private_identification_t*)other; |
660 | |
|
661 | 0 | if (this->type == other_priv->type && |
662 | 0 | (neither_is_regex(this, other) || (this->regex && other_priv->regex))) |
663 | 0 | { |
664 | 0 | if (this->type == ID_ANY) |
665 | 0 | { |
666 | 0 | return TRUE; |
667 | 0 | } |
668 | 0 | return chunk_equals(this->encoded, other_priv->encoded); |
669 | 0 | } |
670 | 0 | return FALSE; |
671 | 0 | } |
672 | | |
673 | | /** |
674 | | * Compare two RDNs for equality, comparing some string types case insensitive |
675 | | */ |
676 | | static bool rdn_equals(chunk_t oid, u_char a_type, chunk_t a, u_char b_type, |
677 | | chunk_t b) |
678 | 0 | { |
679 | 0 | if (a_type == b_type && |
680 | 0 | (a_type == ASN1_PRINTABLESTRING || |
681 | 0 | (a_type == ASN1_IA5STRING && |
682 | 0 | asn1_known_oid(oid) == OID_EMAIL_ADDRESS))) |
683 | 0 | { /* ignore case for printableStrings and email RDNs */ |
684 | 0 | return strncaseeq(a.ptr, b.ptr, a.len); |
685 | 0 | } |
686 | 0 | else |
687 | 0 | { /* respect case and length for everything else */ |
688 | 0 | return memeq(a.ptr, b.ptr, a.len); |
689 | 0 | } |
690 | 0 | } |
691 | | |
692 | | /** |
693 | | * RDNs when matching DNs |
694 | | */ |
695 | | typedef struct { |
696 | | chunk_t oid; |
697 | | u_char type; |
698 | | chunk_t data; |
699 | | bool matched; |
700 | | } rdn_t; |
701 | | |
702 | | /** |
703 | | * Match DNs (o_dn may contain wildcards and RDNs in a different order, if |
704 | | * allow_unmatched is TRUE, t_dn may contain unmatched RDNs) |
705 | | */ |
706 | | static bool match_dn(chunk_t t_dn, chunk_t o_dn, int *wc, bool allow_unmatched) |
707 | 0 | { |
708 | 0 | enumerator_t *enumerator; |
709 | 0 | array_t *rdns; |
710 | 0 | rdn_t *rdn, *found; |
711 | 0 | chunk_t oid, data; |
712 | 0 | u_char type; |
713 | 0 | bool finished = FALSE; |
714 | 0 | int i, regular = 0; |
715 | |
|
716 | 0 | *wc = 0; |
717 | | |
718 | | /* try a binary compare */ |
719 | 0 | if (chunk_equals(t_dn, o_dn)) |
720 | 0 | { |
721 | 0 | return TRUE; |
722 | 0 | } |
723 | | |
724 | 0 | rdns = array_create(0, 8); |
725 | |
|
726 | 0 | enumerator = create_rdn_enumerator(o_dn); |
727 | 0 | while (TRUE) |
728 | 0 | { |
729 | 0 | if (!enumerator->enumerate(enumerator, &oid, &type, &data)) |
730 | 0 | { |
731 | 0 | break; |
732 | 0 | } |
733 | 0 | INIT(rdn, |
734 | 0 | .oid = oid, |
735 | 0 | .type = type, |
736 | 0 | .data = data, |
737 | 0 | ); |
738 | 0 | if (is_wildcard(data)) |
739 | 0 | { |
740 | | /* insert wildcards at the end, to perform exact matches first */ |
741 | 0 | array_insert(rdns, ARRAY_TAIL, rdn); |
742 | 0 | } |
743 | 0 | else |
744 | 0 | { |
745 | 0 | array_insert(rdns, regular++, rdn); |
746 | 0 | } |
747 | | /* the enumerator returns FALSE on parse error, we are finished |
748 | | * if we have reached the end of the DN only */ |
749 | 0 | if ((data.ptr + data.len == o_dn.ptr + o_dn.len)) |
750 | 0 | { |
751 | 0 | finished = TRUE; |
752 | 0 | } |
753 | 0 | } |
754 | 0 | enumerator->destroy(enumerator); |
755 | |
|
756 | 0 | if (!finished) |
757 | 0 | { /* invalid DN */ |
758 | 0 | array_destroy_function(rdns, (void*)free, NULL); |
759 | 0 | return FALSE; |
760 | 0 | } |
761 | 0 | finished = FALSE; |
762 | |
|
763 | 0 | enumerator = create_rdn_enumerator(t_dn); |
764 | 0 | while (TRUE) |
765 | 0 | { |
766 | 0 | if (!enumerator->enumerate(enumerator, &oid, &type, &data)) |
767 | 0 | { |
768 | 0 | break; |
769 | 0 | } |
770 | 0 | for (i = 0, found = NULL; i < array_count(rdns); i++) |
771 | 0 | { |
772 | 0 | array_get(rdns, i, &rdn); |
773 | 0 | if (!rdn->matched && chunk_equals(rdn->oid, oid)) |
774 | 0 | { |
775 | 0 | if (is_wildcard(rdn->data)) |
776 | 0 | { |
777 | 0 | (*wc)++; |
778 | 0 | } |
779 | 0 | else if (data.len != rdn->data.len || |
780 | 0 | !rdn_equals(oid, type, data, rdn->type, rdn->data)) |
781 | 0 | { |
782 | 0 | continue; |
783 | 0 | } |
784 | 0 | rdn->matched = TRUE; |
785 | 0 | found = rdn; |
786 | 0 | break; |
787 | 0 | } |
788 | 0 | } |
789 | 0 | if (!found) |
790 | 0 | { |
791 | | /* treat unmatched RDNs like wildcards if allowed */ |
792 | 0 | if (!allow_unmatched) |
793 | 0 | { |
794 | 0 | break; |
795 | 0 | } |
796 | 0 | (*wc)++; |
797 | 0 | } |
798 | | /* the enumerator returns FALSE on parse error, we are finished |
799 | | * if we have reached the end of the DN only */ |
800 | 0 | if ((data.ptr + data.len == t_dn.ptr + t_dn.len)) |
801 | 0 | { |
802 | 0 | finished = TRUE; |
803 | 0 | } |
804 | 0 | } |
805 | 0 | enumerator->destroy(enumerator); |
806 | |
|
807 | 0 | if (finished) |
808 | 0 | { |
809 | 0 | for (i = 0; i < array_count(rdns); i++) |
810 | 0 | { |
811 | 0 | array_get(rdns, i, &rdn); |
812 | 0 | if (!rdn->matched) |
813 | 0 | { |
814 | 0 | finished = FALSE; |
815 | 0 | } |
816 | 0 | } |
817 | 0 | } |
818 | 0 | array_destroy_function(rdns, (void*)free, NULL); |
819 | 0 | return finished; |
820 | 0 | } |
821 | | |
822 | | /** |
823 | | * Reordered RDNs are fine, but match all |
824 | | */ |
825 | | static bool match_dn_reordered(chunk_t t_dn, chunk_t o_dn, int *wc) |
826 | 0 | { |
827 | 0 | return match_dn(t_dn, o_dn, wc, FALSE); |
828 | 0 | } |
829 | | |
830 | | /** |
831 | | * t_dn may contain more RDNs than o_dn |
832 | | */ |
833 | | static bool match_dn_relaxed(chunk_t t_dn, chunk_t o_dn, int *wc) |
834 | 0 | { |
835 | 0 | return match_dn(t_dn, o_dn, wc, TRUE); |
836 | 0 | } |
837 | | |
838 | | /** |
839 | | * Compare two DNs, for equality if wc == NULL, with wildcard matching otherwise |
840 | | */ |
841 | | static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) |
842 | 0 | { |
843 | 0 | enumerator_t *t, *o; |
844 | 0 | chunk_t t_oid, o_oid, t_data, o_data; |
845 | 0 | u_char t_type, o_type; |
846 | 0 | bool t_next, o_next, finished = FALSE; |
847 | |
|
848 | 0 | if (wc) |
849 | 0 | { |
850 | 0 | *wc = 0; |
851 | 0 | } |
852 | 0 | else if (t_dn.len != o_dn.len) |
853 | 0 | { |
854 | 0 | return FALSE; |
855 | 0 | } |
856 | | |
857 | 0 | if (chunk_equals(t_dn, o_dn)) |
858 | 0 | { |
859 | 0 | return TRUE; |
860 | 0 | } |
861 | | |
862 | 0 | t = create_rdn_enumerator(t_dn); |
863 | 0 | o = create_rdn_enumerator(o_dn); |
864 | 0 | while (TRUE) |
865 | 0 | { |
866 | 0 | t_next = t->enumerate(t, &t_oid, &t_type, &t_data); |
867 | 0 | o_next = o->enumerate(o, &o_oid, &o_type, &o_data); |
868 | |
|
869 | 0 | if (!o_next && !t_next) |
870 | 0 | { |
871 | 0 | break; |
872 | 0 | } |
873 | 0 | finished = FALSE; |
874 | 0 | if (o_next != t_next) |
875 | 0 | { |
876 | 0 | break; |
877 | 0 | } |
878 | 0 | if (!chunk_equals(t_oid, o_oid)) |
879 | 0 | { |
880 | 0 | break; |
881 | 0 | } |
882 | 0 | if (wc && is_wildcard(o_data)) |
883 | 0 | { |
884 | 0 | (*wc)++; |
885 | 0 | } |
886 | 0 | else |
887 | 0 | { |
888 | 0 | if (t_data.len != o_data.len) |
889 | 0 | { |
890 | 0 | break; |
891 | 0 | } |
892 | 0 | if (!rdn_equals(t_oid, t_type, t_data, o_type, o_data)) |
893 | 0 | { |
894 | 0 | break; |
895 | 0 | } |
896 | 0 | } |
897 | | /* the enumerator returns FALSE on parse error, we are finished |
898 | | * if we have reached the end of the DN only */ |
899 | 0 | if ((t_data.ptr + t_data.len == t_dn.ptr + t_dn.len) && |
900 | 0 | (o_data.ptr + o_data.len == o_dn.ptr + o_dn.len)) |
901 | 0 | { |
902 | 0 | finished = TRUE; |
903 | 0 | } |
904 | 0 | } |
905 | 0 | t->destroy(t); |
906 | 0 | o->destroy(o); |
907 | 0 | return finished; |
908 | 0 | } |
909 | | |
910 | | /** |
911 | | * Check if the data in the given chunk represents a valid DN. |
912 | | */ |
913 | | static bool is_valid_dn(chunk_t dn) |
914 | 0 | { |
915 | 0 | enumerator_t *enumerator; |
916 | 0 | chunk_t oid, data; |
917 | 0 | u_char type; |
918 | 0 | bool finished = FALSE; |
919 | |
|
920 | 0 | enumerator = create_rdn_enumerator(dn); |
921 | 0 | while (enumerator->enumerate(enumerator, &oid, &type, &data)) |
922 | 0 | { |
923 | | /* the enumerator returns FALSE on parse error, we are finished |
924 | | * if we have reached the end of the DN only */ |
925 | 0 | if ((data.ptr + data.len == dn.ptr + dn.len)) |
926 | 0 | { |
927 | 0 | finished = TRUE; |
928 | 0 | } |
929 | 0 | } |
930 | 0 | enumerator->destroy(enumerator); |
931 | |
|
932 | 0 | return finished; |
933 | 0 | } |
934 | | |
935 | | METHOD(identification_t, equals_dn, bool, |
936 | | private_identification_t *this, identification_t *other) |
937 | 0 | { |
938 | 0 | return neither_is_regex(this, other) && |
939 | 0 | compare_dn(this->encoded, other->get_encoding(other), NULL); |
940 | 0 | } |
941 | | |
942 | | METHOD(identification_t, hash_dn, u_int, |
943 | | private_identification_t *this, u_int inc) |
944 | 0 | { |
945 | 0 | enumerator_t *rdns; |
946 | 0 | chunk_t oid, data; |
947 | 0 | u_char type; |
948 | 0 | u_int hash; |
949 | |
|
950 | 0 | hash = chunk_hash_inc(chunk_from_thing(this->type), inc); |
951 | 0 | rdns = create_rdn_enumerator(this->encoded); |
952 | 0 | while (rdns->enumerate(rdns, &oid, &type, &data)) |
953 | 0 | { |
954 | 0 | hash = chunk_hash_inc(data, chunk_hash_inc(oid, hash)); |
955 | 0 | } |
956 | 0 | rdns->destroy(rdns); |
957 | 0 | return hash; |
958 | 0 | } |
959 | | |
960 | | METHOD(identification_t, equals_strcasecmp, bool, |
961 | | private_identification_t *this, identification_t *other) |
962 | 0 | { |
963 | 0 | chunk_t encoded = other->get_encoding(other); |
964 | | |
965 | | /* we do some extra sanity checks to check for invalid IDs with a |
966 | | * terminating null in it. */ |
967 | 0 | if (this->type == other->get_type(other) && |
968 | 0 | neither_is_regex(this, other) && |
969 | 0 | this->encoded.len == encoded.len && |
970 | 0 | memchr(this->encoded.ptr, 0, this->encoded.len) == NULL && |
971 | 0 | memchr(encoded.ptr, 0, encoded.len) == NULL && |
972 | 0 | strncasecmp(this->encoded.ptr, encoded.ptr, this->encoded.len) == 0) |
973 | 0 | { |
974 | 0 | return TRUE; |
975 | 0 | } |
976 | 0 | return FALSE; |
977 | 0 | } |
978 | | |
979 | | METHOD(identification_t, matches_binary, id_match_t, |
980 | | private_identification_t *this, identification_t *other) |
981 | 0 | { |
982 | 0 | if (other->get_type(other) == ID_ANY) |
983 | 0 | { |
984 | 0 | return ID_MATCH_ANY; |
985 | 0 | } |
986 | 0 | if (this->type == other->get_type(other) && |
987 | 0 | chunk_equals(this->encoded, other->get_encoding(other))) |
988 | 0 | { |
989 | 0 | return ID_MATCH_PERFECT; |
990 | 0 | } |
991 | 0 | return ID_MATCH_NONE; |
992 | 0 | } |
993 | | |
994 | | /** |
995 | | * Matches the regex in other against our own encoding. |
996 | | */ |
997 | | static id_match_t matches_regex(private_identification_t *this, |
998 | | private_identification_t *other) |
999 | 0 | { |
1000 | 0 | char buf[BUF_LEN-1]; |
1001 | 0 | int rc; |
1002 | |
|
1003 | 0 | if (this->regex) |
1004 | 0 | { /* don't match two regex values */ |
1005 | 0 | return ID_MATCH_NONE; |
1006 | 0 | } |
1007 | 0 | if (!this->encoded.len) |
1008 | 0 | { |
1009 | 0 | return ID_MATCH_NONE; |
1010 | 0 | } |
1011 | | /* match against the string representation of the identity */ |
1012 | 0 | if (snprintf(buf, sizeof(buf), "%Y", this) >= sizeof(buf)) |
1013 | 0 | { |
1014 | | /* fail if the buffer is too small. note that we use BUF_LEN-1 because |
1015 | | * the printf hook uses BUF_LEN to print the identity internally */ |
1016 | 0 | return ID_MATCH_NONE; |
1017 | 0 | } |
1018 | 0 | rc = regexec(other->regex, buf, 0, NULL, 0); |
1019 | 0 | return rc == 0 ? ID_MATCH_MAX_WILDCARDS : ID_MATCH_NONE; |
1020 | 0 | } |
1021 | | |
1022 | | METHOD(identification_t, matches_string, id_match_t, |
1023 | | private_identification_t *this, identification_t *other) |
1024 | 0 | { |
1025 | 0 | private_identification_t *other_priv = (private_identification_t*)other; |
1026 | 0 | chunk_t encoded = other->get_encoding(other); |
1027 | 0 | u_int len = encoded.len; |
1028 | |
|
1029 | 0 | if (other->get_type(other) == ID_ANY) |
1030 | 0 | { |
1031 | 0 | return ID_MATCH_ANY; |
1032 | 0 | } |
1033 | 0 | if (this->type != other->get_type(other)) |
1034 | 0 | { |
1035 | 0 | return ID_MATCH_NONE; |
1036 | 0 | } |
1037 | 0 | if (other_priv->regex) |
1038 | 0 | { |
1039 | 0 | return matches_regex(this, other_priv); |
1040 | 0 | } |
1041 | | /* try a equals check first */ |
1042 | 0 | if (equals_strcasecmp(this, other)) |
1043 | 0 | { |
1044 | 0 | return ID_MATCH_PERFECT; |
1045 | 0 | } |
1046 | 0 | if (len == 0 || this->encoded.len < len) |
1047 | 0 | { |
1048 | 0 | return ID_MATCH_NONE; |
1049 | 0 | } |
1050 | | |
1051 | | /* check for single wildcard at the head of the string */ |
1052 | 0 | if (*encoded.ptr == '*') |
1053 | 0 | { |
1054 | | /* single asterisk matches any string */ |
1055 | 0 | if (len-- == 1) |
1056 | 0 | { /* not better than ID_ANY */ |
1057 | 0 | return ID_MATCH_ANY; |
1058 | 0 | } |
1059 | 0 | if (strncasecmp(this->encoded.ptr + this->encoded.len - len, |
1060 | 0 | encoded.ptr + 1, len) == 0) |
1061 | 0 | { |
1062 | 0 | return ID_MATCH_ONE_WILDCARD; |
1063 | 0 | } |
1064 | 0 | } |
1065 | 0 | return ID_MATCH_NONE; |
1066 | 0 | } |
1067 | | |
1068 | | METHOD(identification_t, matches_any, id_match_t, |
1069 | | private_identification_t *this, identification_t *other) |
1070 | 0 | { |
1071 | 0 | if (other->get_type(other) == ID_ANY) |
1072 | 0 | { |
1073 | 0 | return ID_MATCH_ANY; |
1074 | 0 | } |
1075 | 0 | return ID_MATCH_NONE; |
1076 | 0 | } |
1077 | | |
1078 | | /** |
1079 | | * Match DNs given the matching function |
1080 | | */ |
1081 | | static id_match_t matches_dn_internal(private_identification_t *this, |
1082 | | identification_t *other, |
1083 | | bool (*match)(chunk_t,chunk_t,int*)) |
1084 | 0 | { |
1085 | 0 | private_identification_t *other_priv = (private_identification_t*)other; |
1086 | 0 | int wc; |
1087 | |
|
1088 | 0 | if (other->get_type(other) == ID_ANY) |
1089 | 0 | { |
1090 | 0 | return ID_MATCH_ANY; |
1091 | 0 | } |
1092 | | |
1093 | 0 | if (this->type == other->get_type(other)) |
1094 | 0 | { |
1095 | 0 | if (other_priv->regex) |
1096 | 0 | { |
1097 | 0 | return matches_regex(this, other_priv); |
1098 | 0 | } |
1099 | 0 | else if (match(this->encoded, other->get_encoding(other), &wc)) |
1100 | 0 | { |
1101 | 0 | wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS); |
1102 | 0 | return ID_MATCH_PERFECT - wc; |
1103 | 0 | } |
1104 | 0 | } |
1105 | 0 | return ID_MATCH_NONE; |
1106 | 0 | } |
1107 | | |
1108 | | METHOD(identification_t, matches_dn, id_match_t, |
1109 | | private_identification_t *this, identification_t *other) |
1110 | 0 | { |
1111 | 0 | return matches_dn_internal(this, other, compare_dn); |
1112 | 0 | } |
1113 | | |
1114 | | METHOD(identification_t, matches_dn_reordered, id_match_t, |
1115 | | private_identification_t *this, identification_t *other) |
1116 | 0 | { |
1117 | 0 | return matches_dn_internal(this, other, match_dn_reordered); |
1118 | 0 | } |
1119 | | |
1120 | | METHOD(identification_t, matches_dn_relaxed, id_match_t, |
1121 | | private_identification_t *this, identification_t *other) |
1122 | 0 | { |
1123 | 0 | return matches_dn_internal(this, other, match_dn_relaxed); |
1124 | 0 | } |
1125 | | |
1126 | | /** |
1127 | | * Transform netmask to CIDR bits |
1128 | | */ |
1129 | | static uint8_t netmask_to_cidr(char *netmask, uint8_t address_size) |
1130 | 0 | { |
1131 | 0 | uint8_t i, byte, netbits = 0; |
1132 | |
|
1133 | 0 | for (i = 0; i < address_size; i++) |
1134 | 0 | { |
1135 | 0 | byte = netmask[i]; |
1136 | |
|
1137 | 0 | if (byte == 0x00) |
1138 | 0 | { |
1139 | 0 | break; |
1140 | 0 | } |
1141 | 0 | if (byte == 0xff) |
1142 | 0 | { |
1143 | 0 | netbits += 8; |
1144 | 0 | } |
1145 | 0 | else |
1146 | 0 | { |
1147 | 0 | while (byte & 0x80) |
1148 | 0 | { |
1149 | 0 | netbits++; |
1150 | 0 | byte <<= 1; |
1151 | 0 | } |
1152 | 0 | } |
1153 | 0 | } |
1154 | 0 | return netbits; |
1155 | 0 | } |
1156 | | |
1157 | | /** |
1158 | | * Converts the given network/netmask to an address range |
1159 | | */ |
1160 | | static void subnet_to_range(chunk_t encoding, uint8_t address_size, |
1161 | | uint8_t *from, uint8_t *to) |
1162 | 0 | { |
1163 | 0 | uint8_t *network, *netmask, netbits, mask, i; |
1164 | |
|
1165 | 0 | network = encoding.ptr; |
1166 | 0 | netmask = encoding.ptr + address_size; |
1167 | 0 | netbits = netmask_to_cidr(netmask, address_size); |
1168 | |
|
1169 | 0 | memcpy(from, network, address_size); |
1170 | 0 | memcpy(to, network, address_size); |
1171 | |
|
1172 | 0 | i = netbits / 8; |
1173 | 0 | if (i < address_size) |
1174 | 0 | { |
1175 | 0 | mask = 0xff << (8 - netbits % 8); |
1176 | 0 | from[i] = from[i] & mask; |
1177 | 0 | to[i] = to[i] | ~mask; |
1178 | 0 | memset(&from[i+1], 0, address_size - i - 1); |
1179 | 0 | memset(&to[i+1], 0xff, address_size - i - 1); |
1180 | 0 | } |
1181 | 0 | } |
1182 | | |
1183 | | /** |
1184 | | * Matches one subnet (or address if netmask is NULL) against another |
1185 | | */ |
1186 | | static id_match_t match_subnets(uint8_t *network, uint8_t *netmask, |
1187 | | uint8_t *other_network, uint8_t *other_netmask, |
1188 | | uint8_t address_size) |
1189 | 0 | { |
1190 | 0 | uint8_t netbits, other_netbits, i; |
1191 | |
|
1192 | 0 | other_netbits = other_netmask ? netmask_to_cidr(other_netmask, address_size) |
1193 | 0 | : 8 * address_size; |
1194 | 0 | if (!other_netbits) |
1195 | 0 | { |
1196 | 0 | return ID_MATCH_MAX_WILDCARDS; |
1197 | 0 | } |
1198 | | |
1199 | 0 | netbits = netmask ? netmask_to_cidr(netmask, address_size) : 8 * address_size; |
1200 | |
|
1201 | 0 | if (netbits == other_netbits) |
1202 | 0 | { |
1203 | 0 | return memeq(network, other_network, address_size) ? ID_MATCH_PERFECT |
1204 | 0 | : ID_MATCH_NONE; |
1205 | 0 | } |
1206 | 0 | else if (netbits < other_netbits) |
1207 | 0 | { |
1208 | 0 | return ID_MATCH_NONE; |
1209 | 0 | } |
1210 | | |
1211 | 0 | for (i = 0; i < (other_netbits + 7)/8; i++) |
1212 | 0 | { |
1213 | 0 | if ((network[i] ^ other_network[i]) & other_netmask[i]) |
1214 | 0 | { |
1215 | 0 | return ID_MATCH_NONE; |
1216 | 0 | } |
1217 | 0 | } |
1218 | 0 | return ID_MATCH_ONE_WILDCARD; |
1219 | 0 | } |
1220 | | |
1221 | | /** |
1222 | | * Matches two address ranges against each other |
1223 | | */ |
1224 | | static id_match_t match_ranges(uint8_t *from, uint8_t *to, |
1225 | | uint8_t *other_from, uint8_t *other_to, |
1226 | | uint8_t address_size) |
1227 | 0 | { |
1228 | 0 | const uint8_t zeroes[16] = { 0 }; |
1229 | 0 | const uint8_t ones[16] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, |
1230 | 0 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; |
1231 | 0 | int match_from, match_to; |
1232 | |
|
1233 | 0 | if (memcmp(to, from, address_size) < 0 || |
1234 | 0 | memcmp(other_to, other_from, address_size) < 0) |
1235 | 0 | { |
1236 | | /* to is smaller than from in one of the ranges */ |
1237 | 0 | return ID_MATCH_NONE; |
1238 | 0 | } |
1239 | 0 | else if (memeq(other_from, zeroes, address_size) && |
1240 | 0 | memeq(other_to, ones, address_size)) |
1241 | 0 | { |
1242 | 0 | return ID_MATCH_MAX_WILDCARDS; |
1243 | 0 | } |
1244 | | |
1245 | 0 | match_from = memcmp(from, other_from, address_size); |
1246 | 0 | match_to = memcmp(to, other_to, address_size); |
1247 | |
|
1248 | 0 | if (!match_from && !match_to) |
1249 | 0 | { |
1250 | 0 | return ID_MATCH_PERFECT; |
1251 | 0 | } |
1252 | 0 | else if (match_from >= 0 && match_to <= 0) |
1253 | 0 | { |
1254 | 0 | return ID_MATCH_ONE_WILDCARD; |
1255 | 0 | } |
1256 | 0 | return ID_MATCH_NONE; |
1257 | 0 | } |
1258 | | |
1259 | | /** |
1260 | | * Match a subnet to an address |
1261 | | */ |
1262 | | static id_match_t matches_subnet_to_addr(private_identification_t *this, |
1263 | | identification_t *other, |
1264 | | uint8_t address_size) |
1265 | 0 | { |
1266 | 0 | chunk_t other_encoding; |
1267 | 0 | uint8_t *network, *netmask, *address; |
1268 | |
|
1269 | 0 | other_encoding = other->get_encoding(other); |
1270 | 0 | if (this->encoded.len != 2 * address_size || |
1271 | 0 | other_encoding.len != address_size) |
1272 | 0 | { |
1273 | 0 | return ID_MATCH_NONE; |
1274 | 0 | } |
1275 | 0 | network = this->encoded.ptr; |
1276 | 0 | netmask = this->encoded.ptr + address_size; |
1277 | 0 | address = other_encoding.ptr; |
1278 | 0 | return match_subnets(network, netmask, address, NULL, address_size); |
1279 | 0 | } |
1280 | | |
1281 | | /** |
1282 | | * Match a subnet to an address |
1283 | | */ |
1284 | | static id_match_t matches_range_to_addr(private_identification_t *this, |
1285 | | identification_t *other, |
1286 | | uint8_t address_size) |
1287 | 0 | { |
1288 | 0 | chunk_t other_encoding; |
1289 | 0 | uint8_t *from, *to, *address; |
1290 | |
|
1291 | 0 | other_encoding = other->get_encoding(other); |
1292 | 0 | if (this->encoded.len != 2 * address_size || |
1293 | 0 | other_encoding.len != address_size) |
1294 | 0 | { |
1295 | 0 | return ID_MATCH_NONE; |
1296 | 0 | } |
1297 | 0 | from = this->encoded.ptr; |
1298 | 0 | to = this->encoded.ptr + address_size; |
1299 | 0 | address = other_encoding.ptr; |
1300 | 0 | return match_ranges(from, to, address, address, address_size); |
1301 | 0 | } |
1302 | | |
1303 | | /** |
1304 | | * Matches an address to a subnet |
1305 | | */ |
1306 | | static id_match_t matches_addr_to_subnet(private_identification_t *this, |
1307 | | identification_t *other, |
1308 | | uint8_t address_size) |
1309 | 0 | { |
1310 | 0 | chunk_t other_encoding; |
1311 | 0 | uint8_t *address, *network, *netmask; |
1312 | |
|
1313 | 0 | other_encoding = other->get_encoding(other); |
1314 | 0 | if (this->encoded.len != address_size || |
1315 | 0 | other_encoding.len != 2 * address_size) |
1316 | 0 | { |
1317 | 0 | return ID_MATCH_NONE; |
1318 | 0 | } |
1319 | 0 | address = this->encoded.ptr; |
1320 | 0 | network = other_encoding.ptr; |
1321 | 0 | netmask = other_encoding.ptr + address_size; |
1322 | 0 | return match_subnets(address, NULL, network, netmask, address_size); |
1323 | 0 | } |
1324 | | |
1325 | | /** |
1326 | | * Matches a subnet to a subnet |
1327 | | */ |
1328 | | static id_match_t matches_subnet_to_subnet(private_identification_t *this, |
1329 | | identification_t *other, |
1330 | | uint8_t address_size) |
1331 | 0 | { |
1332 | 0 | chunk_t other_encoding; |
1333 | 0 | uint8_t *network, *netmask, *other_network, *other_netmask; |
1334 | |
|
1335 | 0 | other_encoding = other->get_encoding(other); |
1336 | 0 | if (this->encoded.len != 2 * address_size || |
1337 | 0 | other_encoding.len != 2 * address_size) |
1338 | 0 | { |
1339 | 0 | return ID_MATCH_NONE; |
1340 | 0 | } |
1341 | 0 | network = this->encoded.ptr; |
1342 | 0 | netmask = this->encoded.ptr + address_size; |
1343 | 0 | other_network = other_encoding.ptr; |
1344 | 0 | other_netmask = other_encoding.ptr + address_size; |
1345 | 0 | return match_subnets(network, netmask, other_network, other_netmask, |
1346 | 0 | address_size); |
1347 | 0 | } |
1348 | | |
1349 | | /** |
1350 | | * Matches a range to a subnet |
1351 | | */ |
1352 | | static id_match_t matches_range_to_subnet(private_identification_t *this, |
1353 | | identification_t *other, |
1354 | | uint8_t address_size) |
1355 | 0 | { |
1356 | 0 | chunk_t other_encoding; |
1357 | 0 | uint8_t *from, *to, other_from[address_size], other_to[address_size]; |
1358 | |
|
1359 | 0 | other_encoding = other->get_encoding(other); |
1360 | 0 | if (this->encoded.len != 2 * address_size || |
1361 | 0 | other_encoding.len != 2 * address_size) |
1362 | 0 | { |
1363 | 0 | return ID_MATCH_NONE; |
1364 | 0 | } |
1365 | | |
1366 | 0 | from = this->encoded.ptr; |
1367 | 0 | to = this->encoded.ptr + address_size; |
1368 | 0 | subnet_to_range(other_encoding, address_size, other_from, other_to); |
1369 | 0 | return match_ranges(from, to, other_from, other_to, address_size); |
1370 | 0 | } |
1371 | | |
1372 | | /** |
1373 | | * Match an address to a range |
1374 | | */ |
1375 | | static id_match_t matches_addr_to_range(private_identification_t *this, |
1376 | | identification_t *other, |
1377 | | uint8_t address_size) |
1378 | 0 | { |
1379 | 0 | chunk_t other_encoding; |
1380 | 0 | uint8_t *address, *from, *to; |
1381 | |
|
1382 | 0 | other_encoding = other->get_encoding(other); |
1383 | 0 | if (this->encoded.len != address_size || |
1384 | 0 | other_encoding.len != 2 * address_size) |
1385 | 0 | { |
1386 | 0 | return ID_MATCH_NONE; |
1387 | 0 | } |
1388 | 0 | address = this->encoded.ptr; |
1389 | 0 | from = other_encoding.ptr; |
1390 | 0 | to = other_encoding.ptr + address_size; |
1391 | 0 | return match_ranges(address, address, from, to, address_size); |
1392 | 0 | } |
1393 | | |
1394 | | /** |
1395 | | * Match a subnet to a range |
1396 | | */ |
1397 | | static id_match_t matches_subnet_to_range(private_identification_t *this, |
1398 | | identification_t *other, |
1399 | | uint8_t address_size) |
1400 | 0 | { |
1401 | 0 | chunk_t other_encoding; |
1402 | 0 | uint8_t from[address_size], to[address_size], *other_from, *other_to; |
1403 | |
|
1404 | 0 | other_encoding = other->get_encoding(other); |
1405 | 0 | if (this->encoded.len != 2 * address_size || |
1406 | 0 | other_encoding.len != 2 * address_size) |
1407 | 0 | { |
1408 | 0 | return ID_MATCH_NONE; |
1409 | 0 | } |
1410 | 0 | subnet_to_range(this->encoded, address_size, from, to); |
1411 | 0 | other_from = other_encoding.ptr; |
1412 | 0 | other_to = other_encoding.ptr + address_size; |
1413 | 0 | return match_ranges(from, to, other_from, other_to, address_size); |
1414 | 0 | } |
1415 | | |
1416 | | /** |
1417 | | * Match a range to a range |
1418 | | */ |
1419 | | static id_match_t matches_range_to_range(private_identification_t *this, |
1420 | | identification_t *other, |
1421 | | uint8_t address_size) |
1422 | 0 | { |
1423 | 0 | chunk_t other_encoding; |
1424 | 0 | uint8_t *from, *to, *other_from, *other_to; |
1425 | |
|
1426 | 0 | other_encoding = other->get_encoding(other); |
1427 | 0 | if (this->encoded.len != 2 * address_size || |
1428 | 0 | other_encoding.len != 2 * address_size) |
1429 | 0 | { |
1430 | 0 | return ID_MATCH_NONE; |
1431 | 0 | } |
1432 | 0 | from = this->encoded.ptr; |
1433 | 0 | to = this->encoded.ptr + address_size; |
1434 | 0 | other_from = other_encoding.ptr; |
1435 | 0 | other_to = other_encoding.ptr + address_size; |
1436 | 0 | return match_ranges(from, to, other_from, other_to, address_size); |
1437 | 0 | } |
1438 | | |
1439 | | METHOD(identification_t, matches_range, id_match_t, |
1440 | | private_identification_t *this, identification_t *other) |
1441 | 0 | { |
1442 | 0 | id_type_t other_type; |
1443 | 0 | uint8_t address_size = 0; |
1444 | |
|
1445 | 0 | other_type = other->get_type(other); |
1446 | 0 | if (other_type == ID_ANY) |
1447 | 0 | { |
1448 | 0 | return ID_MATCH_ANY; |
1449 | 0 | } |
1450 | 0 | if (this->type == other_type && |
1451 | 0 | chunk_equals(this->encoded, other->get_encoding(other))) |
1452 | 0 | { |
1453 | 0 | return ID_MATCH_PERFECT; |
1454 | 0 | } |
1455 | 0 | if (other_type == ID_IPV4_ADDR && |
1456 | 0 | (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV4_ADDR_RANGE)) |
1457 | 0 | { |
1458 | 0 | address_size = sizeof(struct in_addr); |
1459 | 0 | } |
1460 | 0 | else if (other_type == ID_IPV6_ADDR && |
1461 | 0 | (this->type == ID_IPV6_ADDR_SUBNET || this->type == ID_IPV6_ADDR_RANGE)) |
1462 | 0 | { |
1463 | 0 | address_size = sizeof(struct in6_addr); |
1464 | 0 | } |
1465 | 0 | if (address_size) |
1466 | 0 | { |
1467 | 0 | if (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV6_ADDR_SUBNET) |
1468 | 0 | { |
1469 | 0 | return matches_subnet_to_addr(this, other, address_size); |
1470 | 0 | } |
1471 | 0 | return matches_range_to_addr(this, other, address_size); |
1472 | 0 | } |
1473 | 0 | if (other_type == ID_IPV4_ADDR_SUBNET && |
1474 | 0 | (this->type == ID_IPV4_ADDR || this->type == ID_IPV4_ADDR_SUBNET || |
1475 | 0 | this->type == ID_IPV4_ADDR_RANGE)) |
1476 | 0 | { |
1477 | 0 | address_size = sizeof(struct in_addr); |
1478 | 0 | } |
1479 | 0 | else if (other_type == ID_IPV6_ADDR_SUBNET && |
1480 | 0 | (this->type == ID_IPV6_ADDR || this->type == ID_IPV6_ADDR_SUBNET || |
1481 | 0 | this->type == ID_IPV6_ADDR_RANGE)) |
1482 | 0 | { |
1483 | 0 | address_size = sizeof(struct in6_addr); |
1484 | 0 | } |
1485 | 0 | if (address_size) |
1486 | 0 | { |
1487 | 0 | if (this->type == ID_IPV4_ADDR || this->type == ID_IPV6_ADDR) |
1488 | 0 | { |
1489 | 0 | return matches_addr_to_subnet(this, other, address_size); |
1490 | 0 | } |
1491 | 0 | else if (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV6_ADDR_SUBNET) |
1492 | 0 | { |
1493 | 0 | return matches_subnet_to_subnet(this, other, address_size); |
1494 | 0 | } |
1495 | 0 | return matches_range_to_subnet(this, other, address_size); |
1496 | 0 | } |
1497 | 0 | if (other_type == ID_IPV4_ADDR_RANGE && |
1498 | 0 | (this->type == ID_IPV4_ADDR || this->type == ID_IPV4_ADDR_SUBNET || |
1499 | 0 | this->type == ID_IPV4_ADDR_RANGE)) |
1500 | 0 | { |
1501 | 0 | address_size = sizeof(struct in_addr); |
1502 | 0 | } |
1503 | 0 | else if (other_type == ID_IPV6_ADDR_RANGE && |
1504 | 0 | (this->type == ID_IPV6_ADDR || this->type == ID_IPV6_ADDR_SUBNET || |
1505 | 0 | this->type == ID_IPV6_ADDR_RANGE)) |
1506 | 0 | { |
1507 | 0 | address_size = sizeof(struct in6_addr); |
1508 | 0 | } |
1509 | 0 | if (address_size) |
1510 | 0 | { |
1511 | 0 | if (this->type == ID_IPV4_ADDR || this->type == ID_IPV6_ADDR) |
1512 | 0 | { |
1513 | 0 | return matches_addr_to_range(this, other, address_size); |
1514 | 0 | } |
1515 | 0 | else if (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV6_ADDR_SUBNET) |
1516 | 0 | { |
1517 | 0 | return matches_subnet_to_range(this, other, address_size); |
1518 | 0 | } |
1519 | 0 | return matches_range_to_range(this, other, address_size); |
1520 | 0 | } |
1521 | 0 | return ID_MATCH_NONE; |
1522 | 0 | } |
1523 | | |
1524 | | /** |
1525 | | * Convert the given identity to a string depending on its type. |
1526 | | */ |
1527 | | static void identity_to_string(private_identification_t *this, char buf[BUF_LEN]) |
1528 | 0 | { |
1529 | 0 | chunk_t proper; |
1530 | 0 | char *pos; |
1531 | 0 | uint8_t address_size; |
1532 | 0 | size_t len; |
1533 | 0 | int written; |
1534 | |
|
1535 | 0 | if (this->regex) |
1536 | 0 | { |
1537 | 0 | snprintf(buf, BUF_LEN, "%s", this->encoded.ptr); |
1538 | 0 | return; |
1539 | 0 | } |
1540 | | |
1541 | 0 | switch (this->type) |
1542 | 0 | { |
1543 | 0 | case ID_ANY: |
1544 | 0 | snprintf(buf, BUF_LEN, "%%any"); |
1545 | 0 | break; |
1546 | 0 | case ID_IPV4_ADDR: |
1547 | 0 | if (this->encoded.len < sizeof(struct in_addr) || |
1548 | 0 | inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL) |
1549 | 0 | { |
1550 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR)"); |
1551 | 0 | } |
1552 | 0 | break; |
1553 | 0 | case ID_IPV4_ADDR_SUBNET: |
1554 | 0 | address_size = sizeof(struct in_addr); |
1555 | 0 | if (this->encoded.len < 2 * address_size || |
1556 | 0 | inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL) |
1557 | 0 | { |
1558 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_SUBNET)"); |
1559 | 0 | break; |
1560 | 0 | } |
1561 | 0 | written = strlen(buf); |
1562 | 0 | snprintf(buf + written, BUF_LEN - written, "/%d", |
1563 | 0 | netmask_to_cidr(this->encoded.ptr + address_size, |
1564 | 0 | address_size)); |
1565 | 0 | break; |
1566 | 0 | case ID_IPV4_ADDR_RANGE: |
1567 | 0 | address_size = sizeof(struct in_addr); |
1568 | 0 | if (this->encoded.len < 2 * address_size || |
1569 | 0 | inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL) |
1570 | 0 | { |
1571 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)"); |
1572 | 0 | break; |
1573 | 0 | } |
1574 | 0 | written = strlen(buf); |
1575 | 0 | pos = buf + written; |
1576 | 0 | len = BUF_LEN - written; |
1577 | 0 | written = snprintf(pos, len, "-"); |
1578 | 0 | if (written < 0 || written >= len || |
1579 | 0 | inet_ntop(AF_INET, this->encoded.ptr + address_size, |
1580 | 0 | pos + written, len - written) == NULL) |
1581 | 0 | { |
1582 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)"); |
1583 | 0 | } |
1584 | 0 | break; |
1585 | 0 | case ID_IPV6_ADDR: |
1586 | 0 | if (this->encoded.len < sizeof(struct in6_addr) || |
1587 | 0 | inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL) |
1588 | 0 | { |
1589 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR)"); |
1590 | 0 | } |
1591 | 0 | break; |
1592 | 0 | case ID_IPV6_ADDR_SUBNET: |
1593 | 0 | address_size = sizeof(struct in6_addr); |
1594 | 0 | if (this->encoded.len < 2 * address_size || |
1595 | 0 | inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL) |
1596 | 0 | { |
1597 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_SUBNET)"); |
1598 | 0 | } |
1599 | 0 | else |
1600 | 0 | { |
1601 | 0 | written = strlen(buf); |
1602 | 0 | snprintf(buf + written, BUF_LEN - written, "/%d", |
1603 | 0 | netmask_to_cidr(this->encoded.ptr + address_size, |
1604 | 0 | address_size)); |
1605 | 0 | } |
1606 | 0 | break; |
1607 | 0 | case ID_IPV6_ADDR_RANGE: |
1608 | 0 | address_size = sizeof(struct in6_addr); |
1609 | 0 | if (this->encoded.len < 2 * address_size || |
1610 | 0 | inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL) |
1611 | 0 | { |
1612 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)"); |
1613 | 0 | break; |
1614 | 0 | } |
1615 | 0 | written = strlen(buf); |
1616 | 0 | pos = buf + written; |
1617 | 0 | len = BUF_LEN - written; |
1618 | 0 | written = snprintf(pos, len, "-"); |
1619 | 0 | if (written < 0 || written >= len || |
1620 | 0 | inet_ntop(AF_INET6, this->encoded.ptr + address_size, |
1621 | 0 | pos + written, len - written) == NULL) |
1622 | 0 | { |
1623 | 0 | snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)"); |
1624 | 0 | } |
1625 | 0 | break; |
1626 | 0 | case ID_FQDN: |
1627 | 0 | case ID_RFC822_ADDR: |
1628 | 0 | case ID_DER_ASN1_GN_URI: |
1629 | 0 | chunk_printable(this->encoded, &proper, '?'); |
1630 | 0 | snprintf(buf, BUF_LEN, "%.*s", (int)proper.len, proper.ptr); |
1631 | 0 | chunk_free(&proper); |
1632 | 0 | break; |
1633 | 0 | case ID_DER_ASN1_DN: |
1634 | 0 | dntoa(this->encoded, buf, BUF_LEN); |
1635 | 0 | break; |
1636 | 0 | case ID_DER_ASN1_GN: |
1637 | 0 | snprintf(buf, BUF_LEN, "(ASN.1 general name)"); |
1638 | 0 | break; |
1639 | 0 | case ID_KEY_ID: |
1640 | 0 | if (chunk_printable(this->encoded, NULL, '?') && |
1641 | 0 | this->encoded.len != HASH_SIZE_SHA1) |
1642 | 0 | { /* fully printable, use ascii version */ |
1643 | 0 | snprintf(buf, BUF_LEN, "%.*s", (int)this->encoded.len, |
1644 | 0 | this->encoded.ptr); |
1645 | 0 | } |
1646 | 0 | else |
1647 | 0 | { /* not printable, hex dump */ |
1648 | 0 | snprintf(buf, BUF_LEN, "%#B", &this->encoded); |
1649 | 0 | } |
1650 | 0 | break; |
1651 | 0 | default: |
1652 | 0 | snprintf(buf, BUF_LEN, "(unknown ID type: %d)", this->type); |
1653 | 0 | break; |
1654 | 0 | } |
1655 | 0 | } |
1656 | | |
1657 | | /** |
1658 | | * Described in header. |
1659 | | */ |
1660 | | int identification_printf_hook(printf_hook_data_t *data, |
1661 | | printf_hook_spec_t *spec, const void *const *args) |
1662 | 0 | { |
1663 | 0 | private_identification_t *this = *((private_identification_t**)(args[0])); |
1664 | 0 | char buf[BUF_LEN]; |
1665 | |
|
1666 | 0 | if (!this) |
1667 | 0 | { |
1668 | 0 | return print_in_hook(data, "%*s", spec->width, "(null)"); |
1669 | 0 | } |
1670 | | |
1671 | 0 | identity_to_string(this, buf); |
1672 | |
|
1673 | 0 | if (spec->minus) |
1674 | 0 | { |
1675 | 0 | return print_in_hook(data, "%-*s", spec->width, buf); |
1676 | 0 | } |
1677 | 0 | return print_in_hook(data, "%*s", spec->width, buf); |
1678 | 0 | } |
1679 | | |
1680 | | #ifdef HAVE_REGEX |
1681 | | |
1682 | | /** |
1683 | | * Compile the encoded regular expression. |
1684 | | */ |
1685 | | static bool compile_regex(private_identification_t *this) |
1686 | 0 | { |
1687 | 0 | char buf[BUF_LEN]; |
1688 | 0 | int err = 0; |
1689 | |
|
1690 | 0 | this->regex = malloc(sizeof(*this->regex)); |
1691 | 0 | err = regcomp(this->regex, this->encoded.ptr, |
1692 | 0 | REG_EXTENDED | REG_ICASE | REG_NOSUB); |
1693 | 0 | if (err != 0) |
1694 | 0 | { |
1695 | 0 | regerror(err, NULL, buf, sizeof(buf)); |
1696 | 0 | DBG1(DBG_LIB, "invalid regular expression '%s': %s", |
1697 | 0 | this->encoded.ptr, buf); |
1698 | 0 | return FALSE; |
1699 | 0 | } |
1700 | 0 | return TRUE; |
1701 | 0 | } |
1702 | | |
1703 | | #else /* HAVE_REGEX */ |
1704 | | |
1705 | | static bool compile_regex(private_identification_t *this) |
1706 | | { |
1707 | | DBG1(DBG_LIB, "regular expressions are not supported"); |
1708 | | return FALSE; |
1709 | | } |
1710 | | |
1711 | | #endif /* HAVE_REGEX */ |
1712 | | |
1713 | | METHOD(identification_t, clone_, identification_t*, |
1714 | | private_identification_t *this) |
1715 | 0 | { |
1716 | 0 | private_identification_t *clone = malloc_thing(private_identification_t); |
1717 | |
|
1718 | 0 | memcpy(clone, this, sizeof(private_identification_t)); |
1719 | 0 | if (this->regex) |
1720 | 0 | { |
1721 | | /* make sure we have the full encoding cloned */ |
1722 | 0 | clone->encoded = chunk_from_str(strdup(this->encoded.ptr)); |
1723 | 0 | compile_regex(clone); |
1724 | 0 | } |
1725 | 0 | else |
1726 | 0 | { |
1727 | 0 | clone->encoded = chunk_clone(this->encoded); |
1728 | 0 | } |
1729 | 0 | return &clone->public; |
1730 | 0 | } |
1731 | | |
1732 | | METHOD(identification_t, destroy, void, |
1733 | | private_identification_t *this) |
1734 | 0 | { |
1735 | 0 | chunk_free(&this->encoded); |
1736 | 0 | if (this->regex) |
1737 | 0 | { |
1738 | 0 | regfree(this->regex); |
1739 | 0 | free(this->regex); |
1740 | 0 | } |
1741 | 0 | free(this); |
1742 | 0 | } |
1743 | | |
1744 | | /** |
1745 | | * Generic constructor used for the other constructors. |
1746 | | */ |
1747 | | static private_identification_t *identification_create(id_type_t type) |
1748 | 0 | { |
1749 | 0 | private_identification_t *this; |
1750 | 0 | char *rdn_matching; |
1751 | |
|
1752 | 0 | INIT(this, |
1753 | 0 | .public = { |
1754 | 0 | .get_encoding = _get_encoding, |
1755 | 0 | .get_type = _get_type, |
1756 | 0 | .create_part_enumerator = _create_part_enumerator, |
1757 | 0 | .clone = _clone_, |
1758 | 0 | .destroy = _destroy, |
1759 | 0 | }, |
1760 | 0 | .type = type, |
1761 | 0 | ); |
1762 | |
|
1763 | 0 | switch (type) |
1764 | 0 | { |
1765 | 0 | case ID_ANY: |
1766 | 0 | this->public.hash = _hash_binary; |
1767 | 0 | this->public.equals = _equals_binary; |
1768 | 0 | this->public.matches = _matches_any; |
1769 | 0 | this->public.contains_wildcards = (void*)return_true; |
1770 | 0 | break; |
1771 | 0 | case ID_FQDN: |
1772 | 0 | case ID_RFC822_ADDR: |
1773 | 0 | this->public.hash = _hash_binary; |
1774 | 0 | this->public.equals = _equals_strcasecmp; |
1775 | 0 | this->public.matches = _matches_string; |
1776 | 0 | this->public.contains_wildcards = _contains_wildcards_memchr; |
1777 | 0 | break; |
1778 | 0 | case ID_DER_ASN1_DN: |
1779 | 0 | this->public.hash = _hash_dn; |
1780 | 0 | this->public.equals = _equals_dn; |
1781 | 0 | this->public.matches = _matches_dn; |
1782 | 0 | this->public.contains_wildcards = _contains_wildcards_dn; |
1783 | | /* check for more relaxed matching config */ |
1784 | 0 | rdn_matching = lib->settings->get_str(lib->settings, |
1785 | 0 | "%s.rdn_matching", NULL, lib->ns); |
1786 | 0 | if (streq("reordered", rdn_matching)) |
1787 | 0 | { |
1788 | 0 | this->public.matches = _matches_dn_reordered; |
1789 | 0 | } |
1790 | 0 | else if (streq("relaxed", rdn_matching)) |
1791 | 0 | { |
1792 | 0 | this->public.matches = _matches_dn_relaxed; |
1793 | 0 | } |
1794 | 0 | break; |
1795 | 0 | case ID_IPV4_ADDR: |
1796 | 0 | case ID_IPV6_ADDR: |
1797 | 0 | case ID_IPV4_ADDR_SUBNET: |
1798 | 0 | case ID_IPV6_ADDR_SUBNET: |
1799 | 0 | case ID_IPV4_ADDR_RANGE: |
1800 | 0 | case ID_IPV6_ADDR_RANGE: |
1801 | 0 | this->public.hash = _hash_binary; |
1802 | 0 | this->public.equals = _equals_binary; |
1803 | 0 | this->public.matches = _matches_range; |
1804 | 0 | this->public.contains_wildcards = (void*)return_false; |
1805 | 0 | break; |
1806 | 0 | default: |
1807 | 0 | this->public.hash = _hash_binary; |
1808 | 0 | this->public.equals = _equals_binary; |
1809 | 0 | this->public.matches = _matches_binary; |
1810 | 0 | this->public.contains_wildcards = (void*)return_false; |
1811 | 0 | break; |
1812 | 0 | } |
1813 | 0 | return this; |
1814 | 0 | } |
1815 | | |
1816 | | /** |
1817 | | * Prefixes used when parsing identities. |
1818 | | */ |
1819 | | static const struct { |
1820 | | const char *str; |
1821 | | id_type_t type; |
1822 | | bool regex; |
1823 | | } prefixes[] = { |
1824 | | { "ipv4:", ID_IPV4_ADDR, FALSE}, |
1825 | | { "ipv6:", ID_IPV6_ADDR, FALSE}, |
1826 | | { "ipv4net:", ID_IPV4_ADDR_SUBNET, FALSE}, |
1827 | | { "ipv6net:", ID_IPV6_ADDR_SUBNET, FALSE}, |
1828 | | { "ipv4range:", ID_IPV4_ADDR_RANGE, FALSE}, |
1829 | | { "ipv6range:", ID_IPV6_ADDR_RANGE, FALSE}, |
1830 | | { "rfc822:", ID_RFC822_ADDR, TRUE}, |
1831 | | { "email:", ID_RFC822_ADDR, TRUE}, |
1832 | | { "userfqdn:", ID_RFC822_ADDR, TRUE}, |
1833 | | { "fqdn:", ID_FQDN, TRUE}, |
1834 | | { "dns:", ID_FQDN, TRUE}, |
1835 | | { "asn1dn:", ID_DER_ASN1_DN, TRUE}, |
1836 | | { "asn1gn:", ID_DER_ASN1_GN, FALSE}, |
1837 | | { "xmppaddr:", ID_DER_ASN1_GN, FALSE}, |
1838 | | { "keyid:", ID_KEY_ID, FALSE}, |
1839 | | { "uri:", ID_DER_ASN1_GN_URI, FALSE}, |
1840 | | }; |
1841 | | |
1842 | | /** |
1843 | | * Create an identity for a specific type, determined by prefix |
1844 | | */ |
1845 | | static private_identification_t *create_from_string_with_prefix_type(char *str) |
1846 | 0 | { |
1847 | 0 | private_identification_t *this; |
1848 | 0 | int i; |
1849 | |
|
1850 | 0 | for (i = 0; i < countof(prefixes); i++) |
1851 | 0 | { |
1852 | 0 | if (strcasepfx(str, prefixes[i].str)) |
1853 | 0 | { |
1854 | 0 | this = identification_create(prefixes[i].type); |
1855 | 0 | str += strlen(prefixes[i].str); |
1856 | |
|
1857 | 0 | if (*str == '#') |
1858 | 0 | { |
1859 | 0 | this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL); |
1860 | 0 | } |
1861 | 0 | else |
1862 | 0 | { |
1863 | 0 | this->encoded = chunk_clone(chunk_from_str(str)); |
1864 | 0 | } |
1865 | |
|
1866 | 0 | if (prefixes[i].type == ID_DER_ASN1_GN && |
1867 | 0 | strcasepfx(prefixes[i].str, "xmppaddr:")) |
1868 | 0 | { |
1869 | 0 | this->encoded = asn1_wrap(ASN1_CONTEXT_C_0, "mm", |
1870 | 0 | asn1_build_known_oid(OID_XMPP_ADDR), |
1871 | 0 | asn1_wrap(ASN1_CONTEXT_C_0, "m", |
1872 | 0 | asn1_wrap(ASN1_UTF8STRING, "m", |
1873 | 0 | this->encoded))); |
1874 | 0 | } |
1875 | 0 | return this; |
1876 | 0 | } |
1877 | 0 | } |
1878 | 0 | return NULL; |
1879 | 0 | } |
1880 | | |
1881 | | /** |
1882 | | * Create an identity for a specific type, determined by a numerical prefix |
1883 | | * |
1884 | | * The prefix is of the form "{x}:", where x denotes the numerical identity |
1885 | | * type. |
1886 | | */ |
1887 | | static private_identification_t *create_from_string_with_num_type(char *str) |
1888 | 0 | { |
1889 | 0 | private_identification_t *this; |
1890 | 0 | u_long type; |
1891 | |
|
1892 | 0 | if (*str++ != '{') |
1893 | 0 | { |
1894 | 0 | return NULL; |
1895 | 0 | } |
1896 | 0 | errno = 0; |
1897 | 0 | type = strtoul(str, &str, 0); |
1898 | 0 | if (errno || *str++ != '}' || *str++ != ':') |
1899 | 0 | { |
1900 | 0 | return NULL; |
1901 | 0 | } |
1902 | 0 | this = identification_create(type); |
1903 | 0 | if (*str == '#') |
1904 | 0 | { |
1905 | 0 | this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL); |
1906 | 0 | } |
1907 | 0 | else |
1908 | 0 | { |
1909 | 0 | this->encoded = chunk_clone(chunk_from_str(str)); |
1910 | 0 | } |
1911 | 0 | return this; |
1912 | 0 | } |
1913 | | |
1914 | | /** |
1915 | | * Convert to an IPv4/IPv6 host address, subnet or address range |
1916 | | */ |
1917 | | static private_identification_t *create_ip_address_from_string(char *string, |
1918 | | bool is_ipv4) |
1919 | 0 | { |
1920 | 0 | private_identification_t *this; |
1921 | 0 | uint8_t encoding[32]; |
1922 | 0 | uint8_t *str, *pos, *address, *to_address, *netmask; |
1923 | 0 | size_t address_size; |
1924 | 0 | int bits, bytes, i; |
1925 | 0 | bool has_subnet = FALSE, has_range = FALSE; |
1926 | |
|
1927 | 0 | address = encoding; |
1928 | 0 | address_size = is_ipv4 ? sizeof(struct in_addr) : sizeof(struct in6_addr); |
1929 | |
|
1930 | 0 | str = strdup(string); |
1931 | 0 | pos = strchr(str, '/'); |
1932 | 0 | if (pos) |
1933 | 0 | { /* separate IP address from optional netmask */ |
1934 | |
|
1935 | 0 | *pos = '\0'; |
1936 | 0 | has_subnet = TRUE; |
1937 | 0 | } |
1938 | 0 | else |
1939 | 0 | { |
1940 | 0 | pos = strchr(str, '-'); |
1941 | 0 | if (pos) |
1942 | 0 | { /* separate lower address from upper address of IP range */ |
1943 | 0 | *pos = '\0'; |
1944 | 0 | has_range = TRUE; |
1945 | 0 | } |
1946 | 0 | } |
1947 | |
|
1948 | 0 | if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, str, address) != 1) |
1949 | 0 | { |
1950 | 0 | free(str); |
1951 | 0 | return NULL; |
1952 | 0 | } |
1953 | | |
1954 | 0 | if (has_subnet) |
1955 | 0 | { /* is IP subnet */ |
1956 | 0 | bits = atoi(pos + 1); |
1957 | 0 | if (bits > 8 * address_size) |
1958 | 0 | { |
1959 | 0 | free(str); |
1960 | 0 | return NULL; |
1961 | 0 | } |
1962 | 0 | bytes = bits / 8; |
1963 | 0 | bits -= 8 * bytes; |
1964 | 0 | netmask = encoding + address_size; |
1965 | |
|
1966 | 0 | for (i = 0; i < address_size; i++) |
1967 | 0 | { |
1968 | 0 | if (bytes) |
1969 | 0 | { |
1970 | 0 | *netmask = 0xff; |
1971 | 0 | bytes--; |
1972 | 0 | } |
1973 | 0 | else if (bits) |
1974 | 0 | { |
1975 | 0 | *netmask = 0xff << (8 - bits); |
1976 | 0 | bits = 0; |
1977 | 0 | } |
1978 | 0 | else |
1979 | 0 | { |
1980 | 0 | *netmask = 0x00; |
1981 | 0 | } |
1982 | 0 | *address++ &= *netmask++; |
1983 | 0 | } |
1984 | 0 | this = identification_create(is_ipv4 ? ID_IPV4_ADDR_SUBNET : |
1985 | 0 | ID_IPV6_ADDR_SUBNET); |
1986 | 0 | this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size)); |
1987 | 0 | } |
1988 | 0 | else if (has_range) |
1989 | 0 | { /* is IP range */ |
1990 | 0 | to_address = encoding + address_size; |
1991 | |
|
1992 | 0 | if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, pos + 1, to_address) != 1) |
1993 | 0 | { |
1994 | 0 | free(str); |
1995 | 0 | return NULL; |
1996 | 0 | } |
1997 | 0 | for (i = 0; i < address_size; i++) |
1998 | 0 | { |
1999 | 0 | if (address[i] != to_address[i]) |
2000 | 0 | { |
2001 | 0 | if (address[i] > to_address[i]) |
2002 | 0 | { |
2003 | 0 | free(str); |
2004 | 0 | return NULL; |
2005 | 0 | } |
2006 | 0 | break; |
2007 | 0 | } |
2008 | 0 | } |
2009 | 0 | this = identification_create(is_ipv4 ? ID_IPV4_ADDR_RANGE : |
2010 | 0 | ID_IPV6_ADDR_RANGE); |
2011 | 0 | this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size)); |
2012 | 0 | } |
2013 | 0 | else |
2014 | 0 | { /* is IP host address */ |
2015 | 0 | this = identification_create(is_ipv4 ? ID_IPV4_ADDR : ID_IPV6_ADDR); |
2016 | 0 | this->encoded = chunk_clone(chunk_create(encoding, address_size)); |
2017 | 0 | } |
2018 | 0 | free(str); |
2019 | |
|
2020 | 0 | return this; |
2021 | 0 | } |
2022 | | |
2023 | | /* |
2024 | | * Described in header. |
2025 | | */ |
2026 | | identification_t *identification_create_from_string(char *string) |
2027 | 0 | { |
2028 | 0 | private_identification_t *this; |
2029 | 0 | chunk_t encoded; |
2030 | |
|
2031 | 0 | if (string == NULL) |
2032 | 0 | { |
2033 | 0 | string = "%any"; |
2034 | 0 | } |
2035 | 0 | this = create_from_string_with_prefix_type(string); |
2036 | 0 | if (this) |
2037 | 0 | { |
2038 | 0 | return &this->public; |
2039 | 0 | } |
2040 | 0 | this = create_from_string_with_num_type(string); |
2041 | 0 | if (this) |
2042 | 0 | { |
2043 | 0 | return &this->public; |
2044 | 0 | } |
2045 | 0 | if (strchr(string, '=') != NULL) |
2046 | 0 | { |
2047 | | /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN. |
2048 | | * convert from LDAP style or openssl x509 -subject style to ASN.1 DN |
2049 | | */ |
2050 | 0 | if (atodn(string, &encoded) == SUCCESS) |
2051 | 0 | { |
2052 | 0 | this = identification_create(ID_DER_ASN1_DN); |
2053 | 0 | this->encoded = encoded; |
2054 | 0 | } |
2055 | 0 | else |
2056 | 0 | { |
2057 | 0 | this = identification_create(ID_KEY_ID); |
2058 | 0 | this->encoded = chunk_clone(chunk_from_str(string)); |
2059 | 0 | } |
2060 | 0 | return &this->public; |
2061 | 0 | } |
2062 | 0 | else if (strchr(string, '@') == NULL) |
2063 | 0 | { |
2064 | 0 | if (streq(string, "") |
2065 | 0 | || streq(string, "%any") |
2066 | 0 | || streq(string, "%any6") |
2067 | 0 | || streq(string, "0.0.0.0") |
2068 | 0 | || streq(string, "*") |
2069 | 0 | || streq(string, "::") |
2070 | 0 | || streq(string, "0::0")) |
2071 | 0 | { |
2072 | | /* any ID will be accepted */ |
2073 | 0 | this = identification_create(ID_ANY); |
2074 | 0 | return &this->public; |
2075 | 0 | } |
2076 | 0 | else |
2077 | 0 | { |
2078 | 0 | if (strchr(string, ':') == NULL) |
2079 | 0 | { |
2080 | | /* IPv4 address or subnet */ |
2081 | 0 | this = create_ip_address_from_string(string, TRUE); |
2082 | 0 | if (!this) |
2083 | 0 | { /* not IPv4, mostly FQDN */ |
2084 | 0 | this = identification_create(ID_FQDN); |
2085 | 0 | this->encoded = chunk_clone(chunk_from_str(string)); |
2086 | 0 | } |
2087 | 0 | return &this->public; |
2088 | 0 | } |
2089 | 0 | else |
2090 | 0 | { |
2091 | | /* IPv6 address or subnet */ |
2092 | 0 | this = create_ip_address_from_string(string, FALSE); |
2093 | 0 | if (!this) |
2094 | 0 | { /* not IPv4/6 fallback to KEY_ID */ |
2095 | 0 | this = identification_create(ID_KEY_ID); |
2096 | 0 | this->encoded = chunk_clone(chunk_from_str(string)); |
2097 | 0 | } |
2098 | 0 | return &this->public; |
2099 | 0 | } |
2100 | 0 | } |
2101 | 0 | } |
2102 | 0 | else |
2103 | 0 | { |
2104 | 0 | if (*string == '@') |
2105 | 0 | { |
2106 | 0 | string++; |
2107 | 0 | if (*string == '#') |
2108 | 0 | { |
2109 | 0 | this = identification_create(ID_KEY_ID); |
2110 | 0 | this->encoded = chunk_from_hex(chunk_from_str(string + 1), NULL); |
2111 | 0 | return &this->public; |
2112 | 0 | } |
2113 | 0 | else if (*string == '@') |
2114 | 0 | { |
2115 | 0 | this = identification_create(ID_RFC822_ADDR); |
2116 | 0 | this->encoded = chunk_clone(chunk_from_str(string + 1)); |
2117 | 0 | return &this->public; |
2118 | 0 | } |
2119 | 0 | else |
2120 | 0 | { |
2121 | 0 | this = identification_create(ID_FQDN); |
2122 | 0 | this->encoded = chunk_clone(chunk_from_str(string)); |
2123 | 0 | return &this->public; |
2124 | 0 | } |
2125 | 0 | } |
2126 | 0 | else |
2127 | 0 | { |
2128 | 0 | this = identification_create(ID_RFC822_ADDR); |
2129 | 0 | this->encoded = chunk_clone(chunk_from_str(string)); |
2130 | 0 | return &this->public; |
2131 | 0 | } |
2132 | 0 | } |
2133 | 0 | } |
2134 | | |
2135 | | /** |
2136 | | * Check if the given string should be parsed as regular expression identity. |
2137 | | * If so, it modifies the string and returns the identity type, otherwise, |
2138 | | * ID_ANY is returned. |
2139 | | */ |
2140 | | static id_type_t is_regex_identity(char **string) |
2141 | 0 | { |
2142 | 0 | char *regex; |
2143 | 0 | int i; |
2144 | |
|
2145 | 0 | for (i = 0; i < countof(prefixes); i++) |
2146 | 0 | { |
2147 | 0 | if (strcasepfx(*string, prefixes[i].str)) |
2148 | 0 | { |
2149 | 0 | regex = *string + strlen(prefixes[i].str); |
2150 | |
|
2151 | 0 | if (prefixes[i].regex && |
2152 | 0 | *regex == '^' && *(regex + strlen(regex) - 1) == '$') |
2153 | 0 | { |
2154 | 0 | *string = regex; |
2155 | 0 | return prefixes[i].type; |
2156 | 0 | } |
2157 | 0 | break; |
2158 | 0 | } |
2159 | 0 | } |
2160 | 0 | return ID_ANY; |
2161 | 0 | } |
2162 | | |
2163 | | /* |
2164 | | * Described in header. |
2165 | | */ |
2166 | | identification_t *identification_create_from_string_with_regex(char *string) |
2167 | 0 | { |
2168 | 0 | private_identification_t *this; |
2169 | 0 | id_type_t type; |
2170 | |
|
2171 | 0 | type = is_regex_identity(&string); |
2172 | 0 | if (type != ID_ANY) |
2173 | 0 | { |
2174 | 0 | this = identification_create(type); |
2175 | |
|
2176 | 0 | this->public.hash = _hash_binary; |
2177 | 0 | this->public.equals = _equals_binary; |
2178 | 0 | this->public.matches = _matches_any; |
2179 | 0 | this->public.contains_wildcards = (void*)return_true; |
2180 | | |
2181 | | /* this encoding explicitly includes the null-terminator so we can |
2182 | | * directly use it to compile the regex and printing */ |
2183 | 0 | this->encoded = chunk_from_str(strdup(string)); |
2184 | 0 | if (!compile_regex(this)) |
2185 | 0 | { |
2186 | 0 | destroy(this); |
2187 | 0 | return NULL; |
2188 | 0 | } |
2189 | 0 | return &this->public; |
2190 | 0 | } |
2191 | 0 | return identification_create_from_string(string); |
2192 | 0 | } |
2193 | | |
2194 | | /* |
2195 | | * Described in header. |
2196 | | */ |
2197 | | identification_t *identification_create_from_data(chunk_t data) |
2198 | 0 | { |
2199 | 0 | char buf[data.len + 1]; |
2200 | |
|
2201 | 0 | if (is_asn1(data) && is_valid_dn(data)) |
2202 | 0 | { |
2203 | 0 | return identification_create_from_encoding(ID_DER_ASN1_DN, data); |
2204 | 0 | } |
2205 | 0 | else |
2206 | 0 | { |
2207 | | /* use string constructor */ |
2208 | 0 | snprintf(buf, sizeof(buf), "%.*s", (int)data.len, data.ptr); |
2209 | 0 | return identification_create_from_string(buf); |
2210 | 0 | } |
2211 | 0 | } |
2212 | | |
2213 | | /* |
2214 | | * Described in header. |
2215 | | */ |
2216 | | identification_t *identification_create_from_encoding(id_type_t type, |
2217 | | chunk_t encoded) |
2218 | 0 | { |
2219 | 0 | private_identification_t *this = identification_create(type); |
2220 | | |
2221 | | /* apply encoded chunk */ |
2222 | 0 | if (type != ID_ANY) |
2223 | 0 | { |
2224 | 0 | this->encoded = chunk_clone(encoded); |
2225 | 0 | } |
2226 | 0 | return &(this->public); |
2227 | 0 | } |
2228 | | |
2229 | | /* |
2230 | | * Described in header. |
2231 | | */ |
2232 | | identification_t *identification_create_from_sockaddr(sockaddr_t *sockaddr) |
2233 | 0 | { |
2234 | 0 | switch (sockaddr->sa_family) |
2235 | 0 | { |
2236 | 0 | case AF_INET: |
2237 | 0 | { |
2238 | 0 | struct in_addr *addr = &(((struct sockaddr_in*)sockaddr)->sin_addr); |
2239 | |
|
2240 | 0 | return identification_create_from_encoding(ID_IPV4_ADDR, |
2241 | 0 | chunk_create((u_char*)addr, sizeof(struct in_addr))); |
2242 | 0 | } |
2243 | 0 | case AF_INET6: |
2244 | 0 | { |
2245 | 0 | struct in6_addr *addr = &(((struct sockaddr_in6*)sockaddr)->sin6_addr); |
2246 | |
|
2247 | 0 | return identification_create_from_encoding(ID_IPV6_ADDR, |
2248 | 0 | chunk_create((u_char*)addr, sizeof(struct in6_addr))); |
2249 | 0 | } |
2250 | 0 | default: |
2251 | 0 | { |
2252 | 0 | private_identification_t *this = identification_create(ID_ANY); |
2253 | |
|
2254 | 0 | return &(this->public); |
2255 | 0 | } |
2256 | 0 | } |
2257 | 0 | } |