c21bab7b23a03aa26b64f1b98b92846d8cd7b062
[strongswan.git] / src / pluto / id.c
1 /* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
2 * Copyright (C) 1999-2001 D. Hugh Redelmeier
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * RCSID $Id$
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <errno.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <unistd.h>
25 #ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */
26 # define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */
27 #endif
28 #include <sys/queue.h>
29
30 #include <freeswan.h>
31 #include <ipsec_policy.h>
32
33 #include "constants.h"
34 #include "defs.h"
35 #include "id.h"
36 #include "log.h"
37 #include "connections.h"
38 #include "packet.h"
39 #include "whack.h"
40
41 const struct id empty_id; /* ID_NONE */
42
43 enum myid_state myid_state = MYID_UNKNOWN;
44 struct id myids[MYID_SPECIFIED+1]; /* %myid */
45 char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */
46
47 /* initialize id module
48 * Fills in myid from environment variable IPSECmyid or defaultrouteaddr
49 */
50 void
51 init_id(void)
52 {
53 passert(empty_id.kind == ID_NONE);
54 myid_state = MYID_UNKNOWN;
55 {
56 enum myid_state s;
57
58 for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
59 {
60 myids[s] = empty_id;
61 myid_str[s] = NULL;
62 }
63 }
64 set_myid(MYID_SPECIFIED, getenv("IPSECmyid"));
65 set_myid(MYID_IP, getenv("defaultrouteaddr"));
66 set_myFQDN();
67 }
68
69 static void
70 calc_myid_str(enum myid_state s)
71 {
72 /* preformat the ID name */
73 char buf[BUF_LEN];
74
75 idtoa(&myids[s], buf, BUF_LEN);
76 replace(myid_str[s], clone_str(buf, "myid string"));
77 }
78
79
80 void
81 set_myid(enum myid_state s, char *idstr)
82 {
83 if (idstr != NULL)
84 {
85 struct id id;
86 err_t ugh = atoid(idstr, &id, FALSE);
87
88 if (ugh != NULL)
89 {
90 loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr);
91 }
92 else
93 {
94 free_id_content(&myids[s]);
95 unshare_id_content(&id);
96 myids[s] = id;
97 if (s == MYID_SPECIFIED)
98 myid_state = MYID_SPECIFIED;
99
100 calc_myid_str(s);
101 }
102 }
103 }
104
105 void
106 set_myFQDN(void)
107 {
108 char FQDN[HOST_NAME_MAX + 1];
109 int r = gethostname(FQDN, sizeof(FQDN));
110
111 free_id_content(&myids[MYID_HOSTNAME]);
112 myids[MYID_HOSTNAME] = empty_id;
113 if (r != 0)
114 {
115 log_errno((e, "gethostname() failed in set_myFQDN"));
116 }
117 else
118 {
119 FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */
120
121 {
122 size_t len = strlen(FQDN);
123
124 if (len > 0 && FQDN[len-1] == '.')
125 {
126 /* nuke trailing . */
127 FQDN[len-1]='\0';
128 }
129 }
130
131 if (!strcaseeq(FQDN, "localhost.localdomain"))
132 {
133 clonetochunk(myids[MYID_HOSTNAME].name, FQDN, strlen(FQDN), "my FQDN");
134 myids[MYID_HOSTNAME].kind = ID_FQDN;
135 calc_myid_str(MYID_HOSTNAME);
136 }
137 }
138 }
139
140 void
141 show_myid_status(void)
142 {
143 char idstr[BUF_LEN];
144
145 (void)idtoa(&myids[myid_state], idstr, sizeof(idstr));
146 whack_log(RC_COMMENT, "%%myid = %s", idstr);
147 }
148
149 /* Convert textual form of id into a (temporary) struct id.
150 * Note that if the id is to be kept, unshare_id_content will be necessary.
151 */
152 err_t
153 atoid(char *src, struct id *id, bool myid_ok)
154 {
155 err_t ugh = NULL;
156
157 *id = empty_id;
158
159 if (myid_ok && streq("%myid", src))
160 {
161 id->kind = ID_MYID;
162 }
163 else if (strchr(src, '=') != NULL)
164 {
165 /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */
166 id->kind = ID_DER_ASN1_DN;
167 id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */
168 id->name.len = 0;
169 /* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
170 * discard optional @ character in front of DN
171 */
172 ugh = atodn((*src == '@')?src+1:src, &id->name);
173 }
174 else if (strchr(src, '@') == NULL)
175 {
176 if (streq(src, "%any") || streq(src, "0.0.0.0"))
177 {
178 /* any ID will be accepted */
179 id->kind = ID_NONE;
180 }
181 else
182 {
183 /* !!! this test is not sufficient for distinguishing address families.
184 * We need a notation to specify that a FQDN is to be resolved to IPv6.
185 */
186 const struct af_info *afi = strchr(src, ':') == NULL
187 ? &af_inet4_info: &af_inet6_info;
188
189 id->kind = afi->id_addr;
190 ugh = ttoaddr(src, 0, afi->af, &id->ip_addr);
191 }
192 }
193 else
194 {
195 if (*src == '@')
196 {
197 if (*(src+1) == '#')
198 {
199 /* if there is a second specifier (#) on the line
200 * we interprete this as ID_KEY_ID
201 */
202 id->kind = ID_KEY_ID;
203 id->name.ptr = src;
204 /* discard @~, convert from hex to bin */
205 ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
206 }
207 else if (*(src+1) == '~')
208 {
209 /* if there is a second specifier (~) on the line
210 * we interprete this as a binary ID_DER_ASN1_DN
211 */
212 id->kind = ID_DER_ASN1_DN;
213 id->name.ptr = src;
214 /* discard @~, convert from hex to bin */
215 ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
216 }
217 else
218 {
219 id->kind = ID_FQDN;
220 id->name.ptr = src+1; /* discard @ */
221 id->name.len = strlen(src)-1;
222 }
223 }
224 else
225 {
226 /* We leave in @, as per DOI 4.6.2.4
227 * (but DNS wants . instead).
228 */
229 id->kind = ID_USER_FQDN;
230 id->name.ptr = src;
231 id->name.len = strlen(src);
232 }
233 }
234 return ugh;
235 }
236
237
238 /*
239 * Converts a binary key ID into hexadecimal format
240 */
241 int
242 keyidtoa(char *dst, size_t dstlen, chunk_t keyid)
243 {
244 int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen);
245 return (((size_t)n < dstlen)? n : dstlen) - 1;
246 }
247
248 void
249 iptoid(const ip_address *ip, struct id *id)
250 {
251 *id = empty_id;
252
253 switch (addrtypeof(ip))
254 {
255 case AF_INET:
256 id->kind = ID_IPV4_ADDR;
257 break;
258 case AF_INET6:
259 id->kind = ID_IPV6_ADDR;
260 break;
261 default:
262 bad_case(addrtypeof(ip));
263 }
264 id->ip_addr = *ip;
265 }
266
267 int
268 idtoa(const struct id *id, char *dst, size_t dstlen)
269 {
270 int n;
271
272 id = resolve_myid(id);
273 switch (id->kind)
274 {
275 case ID_NONE:
276 n = snprintf(dst, dstlen, "(none)");
277 break;
278 case ID_IPV4_ADDR:
279 case ID_IPV6_ADDR:
280 n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1;
281 break;
282 case ID_FQDN:
283 n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr);
284 break;
285 case ID_USER_FQDN:
286 n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr);
287 break;
288 case ID_DER_ASN1_DN:
289 n = dntoa(dst, dstlen, id->name);
290 break;
291 case ID_KEY_ID:
292 n = keyidtoa(dst, dstlen, id->name);
293 break;
294 default:
295 n = snprintf(dst, dstlen, "unknown id kind %d", id->kind);
296 break;
297 }
298
299 /* "Sanitize" string so that log isn't endangered:
300 * replace unprintable characters with '?'.
301 */
302 if (n > 0)
303 {
304 for ( ; *dst != '\0'; dst++)
305 if (!isprint(*dst))
306 *dst = '?';
307 }
308
309 return n;
310 }
311
312 /* Replace the shell metacharacters ', \, ", `, and $ in a character string
313 * by escape sequences consisting of their octal values
314 */
315 void
316 escape_metachar(const char *src, char *dst, size_t dstlen)
317 {
318 while (*src != '\0' && dstlen > 4)
319 {
320 switch (*src)
321 {
322 case '\'':
323 case '\\':
324 case '"':
325 case '`':
326 case '$':
327 sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src);
328 dst += 4;
329 dstlen -= 4;
330 break;
331 default:
332 *dst++ = *src;
333 dstlen--;
334 }
335 src++;
336 }
337 *dst = '\0';
338 }
339
340
341 /* Make private copy of string in struct id.
342 * This is needed if the result of atoid is to be kept.
343 */
344 void
345 unshare_id_content(struct id *id)
346 {
347 switch (id->kind)
348 {
349 case ID_FQDN:
350 case ID_USER_FQDN:
351 case ID_DER_ASN1_DN:
352 case ID_KEY_ID:
353 id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name");
354 break;
355 case ID_MYID:
356 case ID_NONE:
357 case ID_IPV4_ADDR:
358 case ID_IPV6_ADDR:
359 break;
360 default:
361 bad_case(id->kind);
362 }
363 }
364
365 void
366 free_id_content(struct id *id)
367 {
368 switch (id->kind)
369 {
370 case ID_FQDN:
371 case ID_USER_FQDN:
372 case ID_DER_ASN1_DN:
373 case ID_KEY_ID:
374 freeanychunk(id->name);
375 break;
376 case ID_MYID:
377 case ID_NONE:
378 case ID_IPV4_ADDR:
379 case ID_IPV6_ADDR:
380 break;
381 default:
382 bad_case(id->kind);
383 }
384 }
385
386 /* compare two struct id values */
387 bool
388 same_id(const struct id *a, const struct id *b)
389 {
390 a = resolve_myid(a);
391 b = resolve_myid(b);
392 if (a->kind != b->kind)
393 return FALSE;
394 switch (a->kind)
395 {
396 case ID_NONE:
397 return TRUE; /* kind of vacuous */
398
399 case ID_IPV4_ADDR:
400 case ID_IPV6_ADDR:
401 return sameaddr(&a->ip_addr, &b->ip_addr);
402
403 case ID_FQDN:
404 case ID_USER_FQDN:
405 /* assumptions:
406 * - case should be ignored
407 * - trailing "." should be ignored (even if the only character?)
408 */
409 {
410 size_t al = a->name.len
411 , bl = b->name.len;
412
413 while (al > 0 && a->name.ptr[al - 1] == '.')
414 al--;
415 while (bl > 0 && b->name.ptr[bl - 1] == '.')
416 bl--;
417 return al == bl
418 && strncasecmp(a->name.ptr, b->name.ptr, al) == 0;
419 }
420
421 case ID_DER_ASN1_DN:
422 return same_dn(a->name, b->name);
423
424 case ID_KEY_ID:
425 return a->name.len == b->name.len
426 && memeq(a->name.ptr, b->name.ptr, a->name.len);
427
428 default:
429 bad_case(a->kind);
430 }
431 return FALSE;
432 }
433
434 /* compare two struct id values, DNs can contain wildcards */
435 bool
436 match_id(const struct id *a, const struct id *b, int *wildcards)
437 {
438 if (b->kind == ID_NONE)
439 {
440 *wildcards = MAX_WILDCARDS;
441 return TRUE;
442 }
443 if (a->kind != b->kind)
444 return FALSE;
445 if (a->kind == ID_DER_ASN1_DN)
446 return match_dn(a->name, b->name, wildcards);
447 else
448 {
449 *wildcards = 0;
450 return same_id(a, b);
451 }
452 }
453
454 /* count the numer of wildcards in an id */
455 int
456 id_count_wildcards(const struct id *id)
457 {
458 switch (id->kind)
459 {
460 case ID_NONE:
461 return MAX_WILDCARDS;
462 case ID_DER_ASN1_DN:
463 return dn_count_wildcards(id->name);
464 default:
465 return 0;
466 }
467 }
468
469 /* build an ID payload
470 * Note: no memory is allocated for the body of the payload (tl->ptr).
471 * We assume it will end up being a pointer into a sufficiently
472 * stable datastructure. It only needs to last a short time.
473 */
474 void
475 build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
476 {
477 const struct id *id = resolve_myid(&end->id);
478
479 zero(hd);
480 hd->isaiid_idtype = id->kind;
481 switch (id->kind)
482 {
483 case ID_NONE:
484 hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr;
485 tl->len = addrbytesptr(&end->host_addr
486 , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
487 break;
488 case ID_FQDN:
489 case ID_USER_FQDN:
490 case ID_DER_ASN1_DN:
491 case ID_KEY_ID:
492 *tl = id->name;
493 break;
494 case ID_IPV4_ADDR:
495 case ID_IPV6_ADDR:
496 tl->len = addrbytesptr(&id->ip_addr
497 , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
498 break;
499 default:
500 bad_case(id->kind);
501 }
502 }
503
504 /*
505 * Local Variables:
506 * c-basic-offset:4
507 * c-style: pluto
508 * End:
509 */