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