]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/localconf.c
ipsec-317.220.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / localconf.c
1 /* $KAME: localconf.c,v 1.33 2001/08/09 07:32:19 sakane Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <ctype.h>
42 #include <err.h>
43
44 #include "var.h"
45 #include "misc.h"
46 #include "vmbuf.h"
47 #include "plog.h"
48 #include "debug.h"
49
50 #include "localconf.h"
51 #include "algorithm.h"
52 #include "isakmp_var.h"
53 #include "isakmp.h"
54 #include "ipsec_doi.h"
55 #include "grabmyaddr.h"
56 #include "vendorid.h"
57 #include "str2val.h"
58 #include "safefile.h"
59 #include "gcmalloc.h"
60 #include "session.h"
61
62 #include <CoreFoundation/CoreFoundation.h>
63 #if HAVE_SECURITY_FRAMEWORK
64 #include <Security/Security.h>
65 #endif
66
67 struct localconf *lcconf;
68 struct localconf *saved_lcconf;
69
70 static void setdefault (void);
71
72 void
73 initlcconf()
74 {
75 lcconf = racoon_calloc(1, sizeof(*lcconf));
76 if (lcconf == NULL)
77 errx(1, "failed to allocate local conf.");
78
79 setdefault();
80 lcconf->sock_vpncontrol = -1; /* not to be done during flush */
81 lcconf->racoon_conf = LC_DEFAULT_CF;
82 TAILQ_INIT(&lcconf->saved_msg_queue);
83 }
84
85 void
86 flushlcconf()
87 {
88 int i;
89
90 setdefault();
91 clear_myaddr();
92 for (i = 0; i < LC_PATHTYPE_MAX; i++) {
93 if (lcconf->pathinfo[i]) {
94 racoon_free(lcconf->pathinfo[i]);
95 lcconf->pathinfo[i] = NULL;
96 }
97 }
98 for (i = 0; i < IDTYPE_MAX; i++) {
99 if (lcconf->ident[i])
100 vfree(lcconf->ident[i]);
101 lcconf->ident[i] = NULL;
102 }
103 if (lcconf->ext_nat_id) {
104 vfree(lcconf->ext_nat_id);
105 lcconf->ext_nat_id = NULL;
106 }
107 }
108
109 static void
110 setdefault()
111 {
112 lcconf->uid = 0;
113 lcconf->gid = 0;
114 lcconf->autograbaddr = 1;
115 lcconf->port_isakmp = PORT_ISAKMP;
116 lcconf->port_isakmp_natt = PORT_ISAKMP_NATT;
117 lcconf->default_af = AF_INET;
118 lcconf->pad_random = LC_DEFAULT_PAD_RANDOM;
119 lcconf->pad_randomlen = LC_DEFAULT_PAD_RANDOMLEN;
120 lcconf->pad_maxsize = LC_DEFAULT_PAD_MAXSIZE;
121 lcconf->pad_strict = LC_DEFAULT_PAD_STRICT;
122 lcconf->pad_excltail = LC_DEFAULT_PAD_EXCLTAIL;
123 lcconf->retry_counter = LC_DEFAULT_RETRY_COUNTER;
124 lcconf->retry_interval = LC_DEFAULT_RETRY_INTERVAL;
125 lcconf->count_persend = LC_DEFAULT_COUNT_PERSEND;
126 lcconf->secret_size = LC_DEFAULT_SECRETSIZE;
127 lcconf->retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1;
128 lcconf->wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE;
129 lcconf->strict_address = FALSE;
130 lcconf->complex_bundle = TRUE; /*XXX FALSE;*/
131 lcconf->natt_ka_interval = LC_DEFAULT_NATT_KA_INTERVAL;
132 lcconf->auto_exit_delay = 0;
133 lcconf->auto_exit_state &= ~LC_AUTOEXITSTATE_SET;
134 lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT; /* always auto exit as default */
135 }
136
137
138 void
139 savelcconf(void)
140 {
141 saved_lcconf = lcconf;
142 lcconf = NULL;
143 initlcconf();
144 }
145
146 void
147 restorelcconf(void)
148 {
149 flushlcconf();
150 racoon_free(lcconf);
151 lcconf = saved_lcconf;
152 saved_lcconf = NULL;
153 }
154
155
156 /*
157 * get PSK by string.
158 */
159 vchar_t *
160 getpskbyname(id0)
161 vchar_t *id0;
162 {
163 char *id;
164 vchar_t *key = NULL;
165
166 plog(ASL_LEVEL_DEBUG, "Getting pre-shared key by name.\n");
167
168 id = racoon_calloc(1, 1 + id0->l - sizeof(struct ipsecdoi_id_b));
169 if (id == NULL) {
170 plog(ASL_LEVEL_ERR,
171 "failed to get psk buffer.\n");
172 goto end;
173 }
174 memcpy(id, id0->v + sizeof(struct ipsecdoi_id_b),
175 id0->l - sizeof(struct ipsecdoi_id_b));
176 id[id0->l - sizeof(struct ipsecdoi_id_b)] = '\0';
177
178 key = getpsk(id, id0->l - sizeof(struct ipsecdoi_id_b));
179
180 end:
181 if (id)
182 racoon_free(id);
183 return key;
184 }
185
186 #if HAVE_KEYCHAIN
187 /*
188 * get PSK from keyChain.
189 */
190 vchar_t *
191 getpskfromkeychain(const char *name, u_int8_t etype, int secrettype, vchar_t *id_p)
192 {
193 SecKeychainRef keychain = NULL;
194 vchar_t *key = NULL;
195 void *cur_password = NULL;
196 UInt32 cur_password_len = 0;
197 OSStatus status;
198 char serviceName[] = "com.apple.net.racoon";
199
200 plog(ASL_LEVEL_DEBUG, "Getting pre-shared key from keychain.\n");
201
202 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
203 if (status != noErr) {
204 plog(ASL_LEVEL_ERR,
205 "failed to set system keychain domain.\n");
206 goto end;
207 }
208
209 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
210 &keychain);
211 if (status != noErr) {
212 plog(ASL_LEVEL_ERR,
213 "failed to get system keychain domain.\n");
214 goto end;
215 }
216
217 if (secrettype == SECRETTYPE_KEYCHAIN_BY_ID && etype == ISAKMP_ETYPE_AGG) {
218 /* try looking up based on peers id */
219
220 char* peer_id = NULL;
221 int idlen = id_p->l - sizeof(struct ipsecdoi_id_b);
222 u_int8_t id_type = (ALIGNED_CAST(struct ipsecdoi_id_b *)(id_p->v))->type;
223
224 switch (id_type) {
225 case IPSECDOI_ID_IPV4_ADDR:
226 case IPSECDOI_ID_IPV6_ADDR:
227 case IPSECDOI_ID_IPV4_ADDR_SUBNET:
228 case IPSECDOI_ID_IPV4_ADDR_RANGE:
229 case IPSECDOI_ID_IPV6_ADDR_SUBNET:
230 case IPSECDOI_ID_IPV6_ADDR_RANGE:
231 case IPSECDOI_ID_DER_ASN1_DN:
232 case IPSECDOI_ID_DER_ASN1_GN:
233 goto no_id;
234 break;
235
236 case IPSECDOI_ID_FQDN:
237 case IPSECDOI_ID_USER_FQDN:
238 case IPSECDOI_ID_KEY_ID:
239 peer_id = racoon_malloc(1 + idlen);
240 if (peer_id == NULL)
241 goto end;
242 memcpy(peer_id, id_p->v + sizeof(struct ipsecdoi_id_b), idlen);
243 *(peer_id + idlen) = '\0';
244 plog(ASL_LEVEL_ERR,
245 "getting shared secret from keychain using %s.\n", peer_id);
246
247 break;
248 default:
249 goto end;
250 break;
251 }
252
253 status = SecKeychainFindGenericPassword(keychain,
254 strlen(serviceName),
255 serviceName,
256 idlen,
257 peer_id,
258 &cur_password_len,
259 &cur_password,
260 NULL);
261
262 /* try find it using using only the peer id. */
263 if (status == errSecItemNotFound)
264 status = SecKeychainFindGenericPassword(keychain,
265 idlen,
266 peer_id,
267 0,
268 0,
269 &cur_password_len,
270 &cur_password,
271 NULL);
272 if (peer_id)
273 racoon_free(peer_id);
274 if (status == noErr)
275 goto end;
276 /* otherwise fall through to use the default value */
277 }
278
279 no_id:
280 /* use the value in remote config sharedsecret field
281 this is either the value specified for lookup or the
282 default when lookup by id fails.
283 */
284 status = SecKeychainFindGenericPassword(keychain,
285 strlen(serviceName),
286 serviceName,
287 strlen(name),
288 name,
289 &cur_password_len,
290 &cur_password,
291 NULL);
292
293 /* try find it using using only name. */
294 if (status == errSecItemNotFound)
295 status = SecKeychainFindGenericPassword(keychain,
296 strlen(name),
297 name,
298 0,
299 0,
300 &cur_password_len,
301 &cur_password,
302 NULL);
303
304 switch (status) {
305
306 case noErr :
307 goto end;
308 break;
309
310 case errSecItemNotFound :
311 break;
312
313 default :
314 plog(ASL_LEVEL_ERR,
315 "failed to get preshared key from system keychain (error %ld).\n", (long)status);
316 }
317
318 end:
319
320 if (cur_password) {
321 key = vmalloc(cur_password_len);
322 if (key == NULL) {
323 plog(ASL_LEVEL_ERR,
324 "failed to allocate key buffer.\n");
325 } else
326 memcpy(key->v, cur_password, cur_password_len);
327 free(cur_password);
328 }
329
330 if (keychain)
331 CFRelease(keychain);
332
333 return key;
334 }
335 #endif
336
337 /*
338 * get PSK by address.
339 */
340 vchar_t *
341 getpskbyaddr(remote)
342 struct sockaddr_storage *remote;
343 {
344 vchar_t *key = NULL;
345 char addr[NI_MAXHOST], port[NI_MAXSERV];
346
347 plog(ASL_LEVEL_DEBUG, "Getting pre-shared key by addr.\n");
348
349 GETNAMEINFO((struct sockaddr *)remote, addr, port);
350
351 key = getpsk(addr, strlen(addr));
352
353 return key;
354 }
355
356 vchar_t *
357 getpsk(str, len)
358 const char *str;
359 const int len;
360 {
361 FILE *fp;
362 char buf[1024]; /* XXX how is variable length ? */
363 vchar_t *key = NULL;
364 char *p, *q;
365 size_t keylen;
366 char *k = NULL;
367
368 plog(ASL_LEVEL_DEBUG, "Getting pre-shared key from file.\n");
369
370 if (safefile(lcconf->pathinfo[LC_PATHTYPE_PSK], 1) == 0)
371 fp = fopen(lcconf->pathinfo[LC_PATHTYPE_PSK], "r");
372 else
373 fp = NULL;
374 if (fp == NULL) {
375 plog(ASL_LEVEL_ERR,
376 "failed to open pre_share_key file %s\n",
377 lcconf->pathinfo[LC_PATHTYPE_PSK]);
378 return NULL;
379 }
380
381 while (fgets(buf, sizeof(buf), fp) != NULL) {
382 /* comment line */
383 if (buf[0] == '#')
384 continue;
385
386 /* search the end of 1st string. */
387 for (p = buf; *p != '\0' && !isspace((int)*p); p++)
388 ;
389 if (*p == '\0')
390 continue; /* no 2nd parameter */
391 *p = '\0';
392 /* search the 1st of 2nd string. */
393 while (isspace((int)*++p))
394 ;
395 if (*p == '\0')
396 continue; /* no 2nd parameter */
397 p--;
398 if (strncmp(buf, str, len) == 0 && buf[len] == '\0') {
399 p++;
400 keylen = 0;
401 for (q = p; *q != '\0' && *q != '\n'; q++)
402 keylen++;
403 *q = '\0';
404
405 /* fix key if hex string */
406 if (strncmp(p, "0x", 2) == 0) {
407 k = str2val(p + 2, 16, &keylen);
408 if (k == NULL) {
409 plog(ASL_LEVEL_ERR,
410 "failed to get psk buffer.\n");
411 goto end;
412 }
413 p = k;
414 }
415
416 key = vmalloc(keylen);
417 if (key == NULL) {
418 plog(ASL_LEVEL_ERR,
419 "failed to allocate key buffer.\n");
420 goto end;
421 }
422 memcpy(key->v, p, key->l);
423 if (k)
424 racoon_free(k);
425 goto end;
426 }
427 }
428
429 end:
430 fclose(fp);
431 return key;
432 }
433
434 /*
435 * get a file name of a type specified.
436 */
437 void
438 getpathname(path, len, type, name)
439 char *path;
440 int len, type;
441 const char *name;
442 {
443 snprintf(path, len, "%s%s%s",
444 name[0] == '/' ? "" : lcconf->pathinfo[type],
445 name[0] == '/' ? "" : "/",
446 name);
447
448 plog(ASL_LEVEL_DEBUG, "filename: %s\n", path);
449 }
450
451 #if 0 /* DELETEIT */
452 static int lc_doi2idtype[] = {
453 -1,
454 -1,
455 LC_IDENTTYPE_FQDN,
456 LC_IDENTTYPE_USERFQDN,
457 -1,
458 -1,
459 -1,
460 -1,
461 -1,
462 LC_IDENTTYPE_CERTNAME,
463 -1,
464 LC_IDENTTYPE_KEYID,
465 };
466
467 /*
468 * convert DOI value to idtype
469 * OUT -1 : NG
470 * other: converted.
471 */
472 int
473 doi2idtype(idtype)
474 int idtype;
475 {
476 if (ARRAYLEN(lc_doi2idtype) > idtype)
477 return lc_doi2idtype[idtype];
478 return -1;
479 }
480 #endif
481
482 static int lc_sittype2doi[] = {
483 IPSECDOI_SIT_IDENTITY_ONLY,
484 IPSECDOI_SIT_SECRECY,
485 IPSECDOI_SIT_INTEGRITY,
486 };
487
488 /*
489 * convert sittype to DOI value.
490 * OUT -1 : NG
491 * other: converted.
492 */
493 int
494 sittype2doi(sittype)
495 int sittype;
496 {
497 if (ARRAYLEN(lc_sittype2doi) > sittype)
498 return lc_sittype2doi[sittype];
499 return -1;
500 }
501
502 static int lc_doitype2doi[] = {
503 IPSEC_DOI,
504 };
505
506 /*
507 * convert doitype to DOI value.
508 * OUT -1 : NG
509 * other: converted.
510 */
511 int
512 doitype2doi(doitype)
513 int doitype;
514 {
515 if (ARRAYLEN(lc_doitype2doi) > doitype)
516 return lc_doitype2doi[doitype];
517 return -1;
518 }
519
520
521