1/* $Id: vpn_control.c,v 1.17.2.4 2005/07/12 11:49:44 manubsd Exp $ */
2
3/*
4 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
5 *
6 * @APPLE_LICENSE_HEADER_START@
7 *
8 * The contents of this file constitute Original Code as defined in and
9 * are subject to the Apple Public Source License Version 1.1 (the
10 * "License").  You may not use this file except in compliance with the
11 * License.  Please obtain a copy of the License at
12 * http://www.apple.com/publicsource and read it before using this file.
13 *
14 * This Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25/*
26 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 *    notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 *    notice, this list of conditions and the following disclaimer in the
36 *    documentation and/or other materials provided with the distribution.
37 * 3. Neither the name of the project nor the names of its contributors
38 *    may be used to endorse or promote products derived from this software
39 *    without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 */
53
54//#define LION_TEST 1
55
56
57#include "config.h"
58
59#include <sys/types.h>
60#include <sys/param.h>
61#include <sys/socket.h>
62#include <sys/signal.h>
63#include <sys/stat.h>
64#include <sys/un.h>
65
66#include <net/pfkeyv2.h>
67
68#include <netinet/in.h>
69#ifndef HAVE_NETINET6_IPSEC
70#include <netinet/ipsec.h>
71#else
72#include <netinet6/ipsec.h>
73#endif
74
75
76#include <stdlib.h>
77#include <stdio.h>
78#include <string.h>
79#include <errno.h>
80#include <netdb.h>
81#ifdef HAVE_UNISTD_H
82#include <unistd.h>
83#endif
84#include <launch.h>
85#ifndef LION_TEST
86#include <launch_priv.h>
87#endif
88#include <fcntl.h>
89
90#include "var.h"
91#include "misc.h"
92#include "vmbuf.h"
93#include "plog.h"
94#include "sockmisc.h"
95#include "debug.h"
96
97#include "schedule.h"
98#include "localconf.h"
99#include "remoteconf.h"
100#include "grabmyaddr.h"
101#include "isakmp_var.h"
102#include "isakmp.h"
103#include "oakley.h"
104#include "handler.h"
105#include "pfkey.h"
106#include "ipsec_doi.h"
107#include "vpn_control.h"
108#include "vpn_control_var.h"
109#include "isakmp_inf.h"
110#include "session.h"
111#include "gcmalloc.h"
112#include "isakmp_cfg.h"
113#include "sainfo.h"
114
115#ifdef ENABLE_VPNCONTROL_PORT
116char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
117uid_t vpncontrolsock_owner = 0;
118gid_t vpncontrolsock_group = 0;
119mode_t vpncontrolsock_mode = 0600;
120
121static struct sockaddr_un sunaddr;
122static int vpncontrol_process (struct vpnctl_socket_elem *, char *);
123static int vpncontrol_reply (int, char *);
124static void vpncontrol_close_comm (struct vpnctl_socket_elem *);
125static int checklaunchd (void);
126extern int vpn_get_config (phase1_handle_t *, struct vpnctl_status_phase_change **, size_t *);
127extern int vpn_xauth_reply (u_int32_t, void *, size_t);
128
129
130int
131checklaunchd()
132{
133	launch_data_t checkin_response = NULL;
134#ifdef LION_TEST
135    launch_data_t checkin_request = NULL;
136#endif
137	launch_data_t sockets_dict, listening_fd_array;
138	launch_data_t listening_fd;
139	struct sockaddr_storage fdsockaddr;
140	socklen_t fdsockaddrlen = sizeof(fdsockaddr);
141	int socketct;
142	int i;
143	int listenerct;
144	int returnval = 0;
145	int fd;
146
147	/* check in with launchd */
148#ifdef LION_TEST
149    if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
150#else
151	if ((checkin_response = launch_socket_service_check_in()) == NULL) {
152#endif
153		plog(ASL_LEVEL_ERR,
154			 "failed to launch_socket_service_check_in.\n");
155		goto done;
156	}
157#ifdef LION_TEST
158    if ((checkin_response = launch_msg(checkin_request)) == NULL) {
159        plog(ASL_LEVEL_ERR, "failed to launch_msg.\n");
160        goto done;
161    }
162#endif
163	if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
164		plog(ASL_LEVEL_ERR,
165			 "launch_data_get_type error %d\n",
166			 launch_data_get_errno(checkin_response));
167		goto done;
168	}
169	if ( (sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS)) == NULL){
170		plog(ASL_LEVEL_ERR,
171			 "failed to launch_data_dict_lookup.\n");
172		goto done;
173	}
174	if ( !(socketct = launch_data_dict_get_count(sockets_dict))){
175		plog(ASL_LEVEL_ERR,
176			 "launch_data_dict_get_count returns no socket defined.\n");
177		goto done;
178	}
179
180	if ( (listening_fd_array = launch_data_dict_lookup(sockets_dict, "Listeners")) == NULL ){
181		plog(ASL_LEVEL_ERR,
182			 "failed to launch_data_dict_lookup.\n");
183		goto done;
184	}
185	listenerct = launch_data_array_get_count(listening_fd_array);
186	for (i = 0; i < listenerct; i++) {
187		listening_fd = launch_data_array_get_index(listening_fd_array, i);
188		fd = launch_data_get_fd( listening_fd );
189		if ( getsockname( fd , (struct sockaddr *)&fdsockaddr, &fdsockaddrlen)){
190			continue;
191		}
192
193		/* Is this the VPN control socket? */
194		if ( fdsockaddr.ss_family == AF_UNIX &&
195				(!(strcmp(vpncontrolsock_path, ((struct sockaddr_un *)&fdsockaddr)->sun_path))))
196		{
197			plog(ASL_LEVEL_INFO,
198				 "found launchd socket.\n");
199			returnval = fd;
200			break;
201		}
202	}
203	// TODO: check if we have any leaked fd
204	if ( listenerct == i){
205		plog(ASL_LEVEL_ERR,
206			 "failed to find launchd socket\n");
207		returnval = 0;
208	}
209
210done:
211	if (checkin_response)
212		launch_data_free(checkin_response);
213	return(returnval);
214}
215
216
217void
218vpncontrol_handler(void *unused)
219{
220	struct sockaddr_storage from;
221	socklen_t fromlen = sizeof(from);
222    int sock;
223
224	struct vpnctl_socket_elem *sock_elem;
225
226
227    sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
228	if (sock_elem == NULL) {
229		plog(ASL_LEVEL_ERR,
230			"memory error: %s\n", strerror(errno));
231		return; //%%%%%% terminate
232	}
233	LIST_INIT(&sock_elem->bound_addresses);
234
235	sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
236	if (sock_elem->sock < 0) {
237		plog(ASL_LEVEL_ERR,
238			"failed to accept vpn_control command: %s\n", strerror(errno));
239		racoon_free(sock_elem);
240		return; //%%%%% terminate
241	}
242	LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain);
243
244    sock_elem->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, sock_elem->sock, 0, dispatch_get_main_queue());
245    if (sock_elem->source == NULL) {
246		plog(ASL_LEVEL_ERR, "could not create comm socket source.");
247		racoon_free(sock_elem);
248		return; //%%%%% terminate
249    }
250    dispatch_source_set_event_handler(sock_elem->source,
251                                        ^{
252                                                vpncontrol_comm_handler(sock_elem);
253                                        });
254    sock = sock_elem->sock;
255
256    dispatch_source_t the_source = sock_elem->source;
257    dispatch_source_set_cancel_handler(sock_elem->source,
258                                       ^{
259                                           close(sock);
260                                           dispatch_release(the_source); /* Release the source on cancel */
261                                       });
262    dispatch_resume(sock_elem->source);
263
264	plog(ASL_LEVEL_NOTICE,
265		"accepted connection on vpn control socket.\n");
266	check_auto_exit();
267
268	return;
269}
270
271void
272vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
273{
274	struct vpnctl_hdr hdr;
275	char *combuf = NULL;
276	ssize_t len;
277
278	/* get buffer length */
279	while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
280		if (errno == EINTR)
281			continue;
282		plog(ASL_LEVEL_ERR,
283			"failed to recv vpn_control command: %s\n", strerror(errno));
284		goto end;
285	}
286	if (len == 0) {
287		plog(ASL_LEVEL_DEBUG,
288			"vpn_control socket closed by peer.\n");
289        /* kill all related connections */
290        vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
291		vpncontrol_close_comm(elem);
292		return; // %%%%%% terminate
293	}
294
295	/* sanity check */
296	if (len < sizeof(hdr)) {
297		plog(ASL_LEVEL_ERR,
298			"invalid header length of vpn_control command - len=%ld - expected %ld\n", len, sizeof(hdr));
299		goto end;
300	}
301
302	/* get buffer to receive */
303	if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) {
304		plog(ASL_LEVEL_ERR,
305			"failed to alloc buffer for vpn_control command\n");
306		goto end;
307	}
308
309	/* get real data */
310	while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
311		if (errno == EINTR)
312			continue;
313		plog(ASL_LEVEL_ERR,
314			"failed to recv vpn_control command: %s\n",
315			strerror(errno));
316		goto end;
317	}
318
319	(void)vpncontrol_process(elem, combuf);
320
321end:
322	if (combuf)
323		racoon_free(combuf);
324	return;
325}
326
327static int
328vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
329{
330	u_int16_t	error = 0;
331	struct vpnctl_hdr *hdr = ALIGNED_CAST(struct vpnctl_hdr *)combuf;
332
333	switch (ntohs(hdr->msg_type)) {
334
335		case VPNCTL_CMD_BIND:
336			{
337				struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
338				struct bound_addr *addr;
339
340				plog(ASL_LEVEL_DEBUG,
341					"received bind command on vpn control socket.\n");
342				addr = racoon_calloc(1, sizeof(struct bound_addr));
343				if (addr == NULL) {
344					plog(ASL_LEVEL_ERR,
345						"memory error: %s\n", strerror(errno));
346					error = -1;
347					break;
348				}
349				if (ntohs(pkt->vers_len)) {
350					addr->version = vmalloc(ntohs(pkt->vers_len));
351					if (addr->version == NULL) {
352						plog(ASL_LEVEL_ERR,
353							"memory error: %s\n", strerror(errno));
354						error = -1;
355						break;
356					}
357					memcpy(addr->version->v, pkt + 1, ntohs(pkt->vers_len));
358				}
359				addr->address = pkt->address;
360				LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain);
361				lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT;	/* client side */
362			}
363			break;
364
365		case VPNCTL_CMD_UNBIND:
366			{
367				struct vpnctl_cmd_unbind *pkt = ALIGNED_CAST(struct vpnctl_cmd_unbind *)combuf;
368				struct bound_addr *addr;
369				struct bound_addr *t_addr;
370
371				plog(ASL_LEVEL_DEBUG,
372					"received unbind command on vpn control socket.\n");
373				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
374					if (pkt->address == 0xFFFFFFFF ||
375						pkt->address == addr->address) {
376						flushsainfo_dynamic(addr->address);
377						LIST_REMOVE(addr, chain);
378						if (addr->version)
379							vfree(addr->version);
380						racoon_free(addr);
381					}
382				}
383			}
384			break;
385
386		case VPNCTL_CMD_REDIRECT:
387			{
388				struct vpnctl_cmd_redirect *redirect_msg = ALIGNED_CAST(struct vpnctl_cmd_redirect *)combuf;
389				struct redirect *raddr;
390				struct redirect *t_raddr;
391				int found = 0;
392
393				plog(ASL_LEVEL_DEBUG,
394					"received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
395
396				LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
397					if (raddr->cluster_address == redirect_msg->address) {
398						if (redirect_msg->redirect_address == 0) {
399							LIST_REMOVE(raddr, chain);
400							racoon_free(raddr);
401						} else {
402							raddr->redirect_address = redirect_msg->redirect_address;
403							raddr->force = ntohs(redirect_msg->force);
404						}
405						found = 1;
406						break;
407					}
408				}
409				if (!found) {
410					raddr = racoon_malloc(sizeof(struct redirect));
411					if (raddr == NULL) {
412						plog(ASL_LEVEL_DEBUG,
413							"cannot allcoate memory for redirect address.\n");
414						error = -1;
415						break;
416					}
417					raddr->cluster_address = redirect_msg->address;
418					raddr->redirect_address = redirect_msg->redirect_address;
419					raddr->force = ntohs(redirect_msg->force);
420					LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain);
421
422				}
423			}
424			break;
425
426		case VPNCTL_CMD_PING:
427			break;	/* just reply for now */
428
429		case VPNCTL_CMD_XAUTH_INFO:
430			{
431				struct vpnctl_cmd_xauth_info *pkt = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)combuf;
432				struct bound_addr *addr;
433				struct bound_addr *t_addr;
434				void *attr_list;
435
436				plog(ASL_LEVEL_DEBUG,
437					"received xauth info command vpn control socket.\n");
438				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
439					if (pkt->address == addr->address) {
440						/* reply to the last xauth request */
441						attr_list = pkt + 1;
442						error = vpn_xauth_reply(pkt->address, attr_list, ntohs(pkt->hdr.len) - sizeof(u_int32_t));
443						break;
444					}
445				}
446			}
447			break;
448
449		case VPNCTL_CMD_CONNECT:
450			{
451				struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
452				struct bound_addr *addr;
453				struct bound_addr *t_addr;
454
455				plog(ASL_LEVEL_DEBUG,
456					"received connect command on vpn control socket.\n");
457				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
458					if (pkt->address == addr->address) {
459						/* start the connection */
460						error = vpn_connect(addr, VPN_STARTED_BY_API);
461						break;
462					}
463				}
464			}
465			break;
466
467		case VPNCTL_CMD_DISCONNECT:
468			{
469				struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
470				struct bound_addr *addr;
471				struct bound_addr *t_addr;
472
473				plog(ASL_LEVEL_DEBUG,
474					"received disconnect command on vpn control socket.\n");
475				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
476					if (pkt->address == addr->address) {
477						/* stop the connection */
478						error = vpn_disconnect(addr, ike_session_stopped_by_vpn_disconnect);
479						break;
480					}
481				}
482			}
483			break;
484
485		case VPNCTL_CMD_START_PH2:
486			{
487				struct vpnctl_cmd_start_ph2 *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_ph2 *)combuf;
488				struct bound_addr *addr;
489				struct bound_addr *t_addr;
490
491				plog(ASL_LEVEL_DEBUG, "received start_ph2 command on vpn control socket.\n");
492				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
493					if (pkt->address == addr->address) {
494						/* start the connection */
495						error = vpn_start_ph2(addr, pkt);
496						break;
497					}
498				}
499			}
500			break;
501
502		case VPNCTL_CMD_START_DPD:
503            {
504                struct vpnctl_cmd_start_dpd *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)combuf;
505                struct bound_addr *srv;
506                struct bound_addr *t_addr;
507
508                plog(ASL_LEVEL_DEBUG,
509                     "received start_dpd command on vpn control socket.\n");
510                LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
511                    if (pkt->address == srv->address) {
512                        union {                             // Wcast-align fix - force alignment
513                            struct sockaddr_storage ss;
514                            struct sockaddr_in	addr_in;
515                        } daddr;
516
517                        bzero(&daddr, sizeof(struct sockaddr_in));
518                        daddr.addr_in.sin_len = sizeof(struct sockaddr_in);
519                        daddr.addr_in.sin_addr.s_addr = srv->address;
520                        daddr.addr_in.sin_port = 0;
521                        daddr.addr_in.sin_family = AF_INET;
522
523                        /* start the dpd */
524                        error = ike_session_ph1_force_dpd(&daddr.ss);
525                        break;
526                    }
527                }
528            }
529			break;
530
531		case VPNCTL_CMD_ASSERT:
532			{
533				struct vpnctl_cmd_assert *pkt = ALIGNED_CAST(struct vpnctl_cmd_assert *)combuf;
534//				struct bound_addr *addr;
535//				struct bound_addr *t_addr;
536				struct sockaddr_in saddr;
537				struct sockaddr_in daddr;
538
539				plogdump(ASL_LEVEL_DEBUG, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr), "received assert command on vpn control socket.\n");
540//				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
541//					if (pkt->dst_address == addr->address) {
542						bzero(&saddr, sizeof(saddr));
543						saddr.sin_len = sizeof(saddr);
544						saddr.sin_addr.s_addr = pkt->src_address;
545						saddr.sin_port = 0;
546						saddr.sin_family = AF_INET;
547						bzero(&daddr, sizeof(daddr));
548						daddr.sin_len = sizeof(daddr);
549						daddr.sin_addr.s_addr = pkt->dst_address;
550						daddr.sin_port = 0;
551						daddr.sin_family = AF_INET;
552
553						error = vpn_assert((struct sockaddr_storage *)&saddr, (struct sockaddr_storage *)&daddr);
554						break;
555//					}
556//				}
557			}
558			break;
559
560		case VPNCTL_CMD_RECONNECT:
561			{
562				struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
563				struct bound_addr *addr;
564				struct bound_addr *t_addr;
565
566				plog(ASL_LEVEL_DEBUG,
567					 "received reconnect command on vpn control socket.\n");
568				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
569					if (pkt->address == addr->address) {
570						/* start the connection */
571						error = vpn_connect(addr, VPN_RESTARTED_BY_API);
572						break;
573					}
574				}
575			}
576			break;
577
578		default:
579			plog(ASL_LEVEL_ERR,
580				"invalid command: %d\n", ntohs(hdr->msg_type));
581			error = -1;		// for now
582			break;
583	}
584
585	hdr->len = 0;
586	hdr->result = htons(error);
587	if (vpncontrol_reply(elem->sock, combuf) < 0)
588		return -1;
589
590	return 0;
591
592}
593
594static int
595vpncontrol_reply(int so, char *combuf)
596{
597	ssize_t tlen;
598
599	tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
600	if (tlen < 0) {
601		plog(ASL_LEVEL_ERR,
602			"failed to send vpn_control message: %s\n", strerror(errno));
603		return -1;
604	}
605
606	return 0;
607}
608
609int
610vpncontrol_notify_need_authinfo(phase1_handle_t *iph1, void* attr_list, size_t attr_len)
611{
612	struct vpnctl_status_need_authinfo *msg = NULL;
613	struct vpnctl_socket_elem *sock_elem;
614	struct bound_addr *bound_addr;
615	size_t msg_size;
616	ssize_t tlen;
617	u_int32_t address;
618	void *ptr;
619
620	if (!iph1)
621		goto end;
622
623	plog(ASL_LEVEL_DEBUG,
624		"sending vpn_control xauth need info status\n");
625
626	msg = (struct vpnctl_status_need_authinfo *)racoon_malloc(msg_size = sizeof(struct vpnctl_status_need_authinfo) + attr_len);
627	if (msg == NULL) {
628		plog(ASL_LEVEL_ERR,
629			"unable to allocate space for vpn control message.\n");
630		return -1;
631	}
632	msg->hdr.flags = 0;
633
634	if (iph1->remote->ss_family == AF_INET)
635		address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
636	else
637		goto end;		// for now
638
639	msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
640	msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
641	if (!ike_session_is_client_ph1_rekey(iph1)) {
642		msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_AUTHINFO);
643	} else {
644		msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_REAUTHINFO);
645	}
646	msg->address = address;
647	ptr = msg + 1;
648	memcpy(ptr, attr_list, attr_len);
649
650	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
651		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
652			if (bound_addr->address == 0xFFFFFFFF ||
653				bound_addr->address == address) {
654				plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
655				tlen = send(sock_elem->sock, msg, msg_size, 0);
656				if (tlen < 0) {
657					plog(ASL_LEVEL_ERR,
658						"failed to send vpn_control need authinfo status: %s\n", strerror(errno));
659				}
660				break;
661			}
662		}
663	}
664
665end:
666	if (msg)
667		racoon_free(msg);
668	return 0;
669}
670
671int
672vpncontrol_notify_ike_failed(u_int16_t notify_code, u_int16_t from, u_int32_t address, u_int16_t data_len, u_int8_t *data)
673{
674	struct vpnctl_status_failed *msg = NULL;
675	struct vpnctl_socket_elem *sock_elem;
676	struct bound_addr *bound_addr;
677	size_t len;
678    ssize_t tlen;
679
680	len = sizeof(struct vpnctl_status_failed) + data_len;
681
682	msg = (struct vpnctl_status_failed *)racoon_malloc(len);
683	if (msg == NULL) {
684		plog(ASL_LEVEL_DEBUG,
685				"unable to allcate memory for vpn control status message.\n");
686		return -1;
687	}
688
689	msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED);
690	msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
691	msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr));
692	msg->address = address;
693	msg->ike_code = htons(notify_code);
694	msg->from = htons(from);
695	if (data_len > 0)
696		memcpy(msg->data, data, data_len);
697	plog(ASL_LEVEL_DEBUG,
698			"sending vpn_control ike failed message - code=%d  from=%s.\n", notify_code,
699					(from == FROM_LOCAL ? "local" : "remote"));
700
701	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
702		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
703			if (bound_addr->address == 0xFFFFFFFF ||
704				bound_addr->address == address) {
705				tlen = send(sock_elem->sock, msg, len, 0);
706				if (tlen < 0) {
707					plog(ASL_LEVEL_ERR,
708						"Unable to send vpn_control ike notify failed: %s\n", strerror(errno));
709				}
710				break;
711			}
712		}
713	}
714
715	if (msg)
716		racoon_free(msg);
717	return 0;
718}
719
720char *
721vpncontrol_status_2_str(u_int16_t msg_type)
722{
723    switch (msg_type) {
724        case VPNCTL_STATUS_IKE_FAILED:
725            return "IKE failed";
726        case VPNCTL_STATUS_PH1_START_US:
727            return "Phase 1 started by us";
728        case VPNCTL_STATUS_PH1_START_PEER:
729            return "Phase 1 started by peer";
730        case VPNCTL_STATUS_PH1_ESTABLISHED:
731            return "Phase 1 established";
732        case VPNCTL_STATUS_PH2_START:
733            return "Phase 2 started";
734        case VPNCTL_STATUS_PH2_ESTABLISHED:
735            return "Phase 2 established";
736        case VPNCTL_STATUS_NEED_AUTHINFO:
737            return "Need authentication info";
738        case VPNCTL_STATUS_NEED_REAUTHINFO:
739            return "Need re-authentication info";
740        default:
741            return "";
742    }
743}
744
745
746int
747vpncontrol_notify_phase_change(int start, u_int16_t from, phase1_handle_t *iph1, phase2_handle_t *iph2)
748{
749	struct vpnctl_status_phase_change *msg;
750	struct vpnctl_socket_elem *sock_elem;
751	struct bound_addr *bound_addr;
752	ssize_t tlen;
753	size_t msg_size;
754	u_int32_t address;
755
756    if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
757		if (vpn_get_config(iph1, &msg, &msg_size) == 1)
758			return 0;	/* mode config not finished yet */
759	} else {
760		msg = racoon_malloc(msg_size = sizeof(struct vpnctl_status_phase_change));
761		msg->hdr.flags = 0;
762	}
763
764	if (msg == NULL) {
765		plog(ASL_LEVEL_ERR,
766						"unable to allocate space for vpn control message.\n");
767		return -1;
768	}
769	if (iph1) {
770		if (iph1->remote->ss_family == AF_INET)
771			address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
772		else
773			goto end;		// for now
774		msg->hdr.msg_type = htons(start ?
775			(from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER)
776			: VPNCTL_STATUS_PH1_ESTABLISHED);
777		// TODO: indicate version
778	} else {
779		if (iph2->dst->ss_family == AF_INET)
780			address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
781		else
782			goto end;		// for now
783		msg->hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
784		// TODO: indicate version
785	}
786    plog(ASL_LEVEL_NOTICE,
787         ">>>>> phase change status = %s\n", vpncontrol_status_2_str(ntohs(msg->hdr.msg_type)));
788
789	msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
790	msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
791	msg->address = address;
792
793	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
794		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
795			if (bound_addr->address == 0xFFFFFFFF ||
796				bound_addr->address == address) {
797				plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
798				tlen = send(sock_elem->sock, msg, msg_size, 0);
799				if (tlen < 0) {
800					plog(ASL_LEVEL_ERR,
801						"failed to send vpn_control phase change status: %s\n", strerror(errno));
802				}
803				break;
804			}
805		}
806	}
807
808end:
809	if (msg)
810		racoon_free(msg);
811	return 0;
812}
813
814static int
815vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
816{
817	struct vpnctl_status_peer_resp msg;
818	struct vpnctl_socket_elem *sock_elem;
819	struct bound_addr *bound_addr;
820	ssize_t tlen;
821	int    rc = -1;
822
823	bzero(&msg, sizeof(msg));
824	msg.hdr.msg_type = htons(VPNCTL_STATUS_PEER_RESP);
825	msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
826	msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
827	msg.address = address;
828	msg.ike_code = notify_code;
829	plog(ASL_LEVEL_DEBUG,
830		 "sending vpn_control status (peer response) message - code=%d  addr=%x.\n", notify_code, address);
831
832	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
833		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
834			if (bound_addr->address == 0xFFFFFFFF ||
835				bound_addr->address == address) {
836				tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
837				if (tlen < 0) {
838					plog(ASL_LEVEL_ERR,
839						 "unable to send vpn_control status (peer response): %s\n", strerror(errno));
840				} else {
841					rc = 0;
842				}
843				break;
844			}
845		}
846	}
847
848	return rc;
849}
850
851int
852vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, phase1_handle_t *iph1)
853{
854	u_int32_t address;
855	int       rc;
856
857	if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
858		if (iph1->remote->ss_family == AF_INET)
859			address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
860		else
861			address = 0;
862	} else {
863		return 0;
864	}
865
866	if ((rc = vpncontrol_notify_peer_resp(notify_code, address)) == 0) {
867		iph1->parent_session->controller_awaiting_peer_resp = 0;
868	}
869	return rc;
870}
871
872int
873vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, phase2_handle_t *iph2)
874{
875	u_int32_t address;
876	int       rc;
877
878	if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
879		if (iph2->dst->ss_family == AF_INET)
880			address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
881		else
882			address = 0;
883	} else {
884		return 0;
885	}
886
887	if ((rc = vpncontrol_notify_peer_resp(notify_code, address)) == 0) {
888		iph2->parent_session->controller_awaiting_peer_resp = 0;
889	}
890	return rc;
891}
892
893int
894vpncontrol_init(void)
895{
896    int sock;
897
898	if (vpncontrolsock_path == NULL) {
899		lcconf->sock_vpncontrol = -1;
900		return 0;
901	}
902
903	if ( (lcconf->sock_vpncontrol = checklaunchd()) == 0 ) {
904		memset(&sunaddr, 0, sizeof(sunaddr));
905		sunaddr.sun_family = AF_UNIX;
906		snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
907			"%s", vpncontrolsock_path);
908
909		lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
910		if (lcconf->sock_vpncontrol == -1) {
911			plog(ASL_LEVEL_ERR,
912				"socket: %s\n", strerror(errno));
913			return -1;
914		}
915
916		if (fcntl(lcconf->sock_vpncontrol, F_SETFL, O_NONBLOCK) == -1) {
917			plog(ASL_LEVEL_ERR, "failed to put VPN-Control socket in non-blocking mode\n");
918		}
919
920		unlink(sunaddr.sun_path);
921		if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
922				sizeof(sunaddr)) != 0) {
923			plog(ASL_LEVEL_ERR,
924				"bind(sockname:%s): %s\n",
925				sunaddr.sun_path, strerror(errno));
926			(void)close(lcconf->sock_vpncontrol);
927			return -1;
928		}
929
930		if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
931			plog(ASL_LEVEL_ERR,
932				"chown(%s, %d, %d): %s\n",
933				sunaddr.sun_path, vpncontrolsock_owner,
934				vpncontrolsock_group, strerror(errno));
935			(void)close(lcconf->sock_vpncontrol);
936			return -1;
937		}
938
939		if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
940			plog(ASL_LEVEL_ERR,
941				"chmod(%s, 0%03o): %s\n",
942				sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
943			(void)close(lcconf->sock_vpncontrol);
944			return -1;
945		}
946
947		if (listen(lcconf->sock_vpncontrol, 5) != 0) {
948			plog(ASL_LEVEL_ERR,
949				"listen(sockname:%s): %s\n",
950				sunaddr.sun_path, strerror(errno));
951			(void)close(lcconf->sock_vpncontrol);
952			return -1;
953		}
954		plog(ASL_LEVEL_DEBUG,
955			"opened %s as racoon management.\n", sunaddr.sun_path);
956	}
957    lcconf->vpncontrol_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->sock_vpncontrol, 0, dispatch_get_main_queue());
958    if (lcconf->vpncontrol_source == NULL) {
959        plog(ASL_LEVEL_ERR, "could not create vpncontrol socket source.");
960        return -1;
961    }
962    dispatch_source_set_event_handler_f(lcconf->vpncontrol_source, vpncontrol_handler);
963    sock = lcconf->sock_vpncontrol;
964    dispatch_source_set_cancel_handler(lcconf->vpncontrol_source,
965                                         ^{
966                                                close(sock);
967                                         });
968    dispatch_resume(lcconf->vpncontrol_source);
969    return 0;
970}
971
972void
973vpncontrol_disconnect_all(struct vpnctl_socket_elem *elem, const char *reason)
974{
975    struct bound_addr *addr;
976    struct bound_addr *t_addr;
977
978    plog(ASL_LEVEL_DEBUG,
979         "received disconnect all command.\n");
980
981    LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
982        /* stop any connections */
983        vpn_disconnect(addr, reason);
984    }
985}
986
987void
988vpncontrol_close()
989{
990    struct vpnctl_socket_elem *elem;
991	struct vpnctl_socket_elem *t_elem;
992
993    plog(ASL_LEVEL_DEBUG,
994         "vpncontrol_close.\n");
995
996    dispatch_source_cancel(lcconf->vpncontrol_source);
997    lcconf->vpncontrol_source = NULL;
998
999    lcconf->sock_vpncontrol = -1;
1000    LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
1001        vpncontrol_close_comm(elem);
1002}
1003
1004static void
1005vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
1006{
1007	struct bound_addr *addr;
1008	struct bound_addr *t_addr;
1009
1010	plog(ASL_LEVEL_DEBUG,
1011		"vpncontrol_close_comm.\n");
1012
1013	LIST_REMOVE(elem, chain);
1014	if (elem->sock != -1)
1015		dispatch_source_cancel(elem->source);
1016	LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
1017		flushsainfo_dynamic(addr->address);
1018		LIST_REMOVE(addr, chain);
1019		if (addr->version)
1020			vfree(addr->version);
1021		racoon_free(addr);
1022	}
1023	racoon_free(elem);
1024	check_auto_exit();
1025
1026}
1027
1028int
1029vpn_control_connected(void)
1030{
1031	if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
1032		return 0;
1033	else
1034		return 1;
1035}
1036
1037#endif
1038