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    sock_elem = racoon_malloc(sizeof(struct vpnctl_socket_elem));
227	if (sock_elem == NULL) {
228		plog(ASL_LEVEL_ERR,
229			"memory error: %s\n", strerror(errno));
230		return; //%%%%%% terminate
231	}
232	LIST_INIT(&sock_elem->bound_addresses);
233
234	sock_elem->sock = accept(lcconf->sock_vpncontrol, (struct sockaddr *)&from, &fromlen);
235	if (sock_elem->sock < 0) {
236		plog(ASL_LEVEL_ERR,
237			"failed to accept vpn_control command: %s\n", strerror(errno));
238		racoon_free(sock_elem);
239		return; //%%%%% terminate
240	}
241	LIST_INSERT_HEAD(&lcconf->vpnctl_comm_socks, sock_elem, chain);
242
243    sock_elem->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, sock_elem->sock, 0, dispatch_get_main_queue());
244    if (sock_elem->source == NULL) {
245		plog(ASL_LEVEL_ERR, "could not create comm socket source.");
246		racoon_free(sock_elem);
247		return; //%%%%% terminate
248    }
249    dispatch_source_set_event_handler(sock_elem->source,
250                                        ^{
251                                                vpncontrol_comm_handler(sock_elem);
252                                        });
253    sock = sock_elem->sock;
254
255    dispatch_source_t the_source = sock_elem->source;
256    dispatch_source_set_cancel_handler(sock_elem->source,
257                                       ^{
258                                           close(sock);
259                                           dispatch_release(the_source); /* Release the source on cancel */
260                                       });
261    dispatch_resume(sock_elem->source);
262
263	plog(ASL_LEVEL_NOTICE,
264		"accepted connection on vpn control socket.\n");
265	check_auto_exit();
266
267	return;
268}
269
270void
271vpncontrol_comm_handler(struct vpnctl_socket_elem *elem)
272{
273	struct vpnctl_hdr hdr;
274	char *combuf = NULL;
275	ssize_t len;
276
277	/* get buffer length */
278	while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
279		if (errno == EINTR)
280			continue;
281		plog(ASL_LEVEL_ERR,
282			"failed to recv vpn_control command: %s\n", strerror(errno));
283		goto end;
284	}
285	if (len == 0) {
286		plog(ASL_LEVEL_DEBUG,
287			"vpn_control socket closed by peer.\n");
288        /* kill all related connections */
289        vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
290		vpncontrol_close_comm(elem);
291		return; // %%%%%% terminate
292	}
293
294	/* sanity check */
295	if (len < sizeof(hdr)) {
296		plog(ASL_LEVEL_ERR,
297			"invalid header length of vpn_control command - len=%ld - expected %ld\n", len, sizeof(hdr));
298		goto end;
299	}
300
301	/* get buffer to receive */
302	if ((combuf = racoon_malloc(ntohs(hdr.len) + sizeof(hdr))) == 0) {
303		plog(ASL_LEVEL_ERR,
304			"failed to alloc buffer for vpn_control command\n");
305		goto end;
306	}
307
308	/* get real data */
309	while ((len = recv(elem->sock, combuf, ntohs(hdr.len) + sizeof(hdr), 0)) < 0) {
310		if (errno == EINTR)
311			continue;
312		plog(ASL_LEVEL_ERR,
313			"failed to recv vpn_control command: %s\n",
314			strerror(errno));
315		goto end;
316	}
317
318	(void)vpncontrol_process(elem, combuf);
319
320end:
321	if (combuf)
322		racoon_free(combuf);
323	return;
324}
325
326static int
327vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
328{
329	u_int16_t	error = 0;
330	struct vpnctl_hdr *hdr = ALIGNED_CAST(struct vpnctl_hdr *)combuf;
331
332	switch (ntohs(hdr->msg_type)) {
333
334		case VPNCTL_CMD_BIND:
335			{
336				struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
337				struct bound_addr *addr;
338
339				plog(ASL_LEVEL_DEBUG,
340					"received bind command on vpn control socket.\n");
341				addr = racoon_calloc(1, sizeof(struct bound_addr));
342				if (addr == NULL) {
343					plog(ASL_LEVEL_ERR,
344						"memory error: %s\n", strerror(errno));
345					error = -1;
346					break;
347				}
348				if (ntohs(pkt->vers_len)) {
349					addr->version = vmalloc(ntohs(pkt->vers_len));
350					if (addr->version == NULL) {
351						plog(ASL_LEVEL_ERR,
352							"memory error: %s\n", strerror(errno));
353						error = -1;
354						break;
355					}
356					memcpy(addr->version->v, pkt + 1, ntohs(pkt->vers_len));
357				}
358				addr->address = pkt->address;
359				LIST_INSERT_HEAD(&elem->bound_addresses, addr, chain);
360				lcconf->auto_exit_state |= LC_AUTOEXITSTATE_CLIENT;	/* client side */
361			}
362			break;
363
364		case VPNCTL_CMD_UNBIND:
365			{
366				struct vpnctl_cmd_unbind *pkt = ALIGNED_CAST(struct vpnctl_cmd_unbind *)combuf;
367				struct bound_addr *addr;
368				struct bound_addr *t_addr;
369
370				plog(ASL_LEVEL_DEBUG,
371					"received unbind command on vpn control socket.\n");
372				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
373					if (pkt->address == 0xFFFFFFFF ||
374						pkt->address == addr->address) {
375						flushsainfo_dynamic(addr->address);
376						LIST_REMOVE(addr, chain);
377						if (addr->version)
378							vfree(addr->version);
379						racoon_free(addr);
380					}
381				}
382			}
383			break;
384
385		case VPNCTL_CMD_REDIRECT:
386			{
387				struct vpnctl_cmd_redirect *redirect_msg = ALIGNED_CAST(struct vpnctl_cmd_redirect *)combuf;
388				struct redirect *raddr;
389				struct redirect *t_raddr;
390				int found = 0;
391
392				plog(ASL_LEVEL_DEBUG,
393					"received redirect command on vpn control socket - address = %x.\n", ntohl(redirect_msg->redirect_address));
394
395				LIST_FOREACH_SAFE(raddr, &lcconf->redirect_addresses, chain, t_raddr) {
396					if (raddr->cluster_address == redirect_msg->address) {
397						if (redirect_msg->redirect_address == 0) {
398							LIST_REMOVE(raddr, chain);
399							racoon_free(raddr);
400						} else {
401							raddr->redirect_address = redirect_msg->redirect_address;
402							raddr->force = ntohs(redirect_msg->force);
403						}
404						found = 1;
405						break;
406					}
407				}
408				if (!found) {
409					raddr = racoon_malloc(sizeof(struct redirect));
410					if (raddr == NULL) {
411						plog(ASL_LEVEL_DEBUG,
412							"cannot allcoate memory for redirect address.\n");
413						error = -1;
414						break;
415					}
416					raddr->cluster_address = redirect_msg->address;
417					raddr->redirect_address = redirect_msg->redirect_address;
418					raddr->force = ntohs(redirect_msg->force);
419					LIST_INSERT_HEAD(&lcconf->redirect_addresses, raddr, chain);
420
421				}
422			}
423			break;
424
425		case VPNCTL_CMD_PING:
426			break;	/* just reply for now */
427
428		case VPNCTL_CMD_XAUTH_INFO:
429			{
430				struct vpnctl_cmd_xauth_info *pkt = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)combuf;
431				struct bound_addr *addr;
432				struct bound_addr *t_addr;
433				void *attr_list;
434
435				plog(ASL_LEVEL_DEBUG,
436					"received xauth info command vpn control socket.\n");
437				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
438					if (pkt->address == addr->address) {
439						/* reply to the last xauth request */
440						attr_list = pkt + 1;
441						error = vpn_xauth_reply(pkt->address, attr_list, ntohs(pkt->hdr.len) - sizeof(u_int32_t));
442						break;
443					}
444				}
445			}
446			break;
447
448		case VPNCTL_CMD_CONNECT:
449			{
450				struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
451				struct bound_addr *addr;
452				struct bound_addr *t_addr;
453
454				plog(ASL_LEVEL_DEBUG,
455					"received connect command on vpn control socket.\n");
456				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
457					if (pkt->address == addr->address) {
458						/* start the connection */
459						error = vpn_connect(addr, VPN_STARTED_BY_API);
460						break;
461					}
462				}
463			}
464			break;
465
466		case VPNCTL_CMD_DISCONNECT:
467			{
468				struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
469				struct bound_addr *addr;
470				struct bound_addr *t_addr;
471
472				plog(ASL_LEVEL_DEBUG,
473					"received disconnect command on vpn control socket.\n");
474				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
475					if (pkt->address == addr->address) {
476						/* stop the connection */
477						error = vpn_disconnect(addr, ike_session_stopped_by_vpn_disconnect);
478						break;
479					}
480				}
481			}
482			break;
483
484		case VPNCTL_CMD_START_PH2:
485			{
486				struct vpnctl_cmd_start_ph2 *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_ph2 *)combuf;
487				struct bound_addr *addr;
488				struct bound_addr *t_addr;
489
490				plog(ASL_LEVEL_DEBUG, "received start_ph2 command on vpn control socket.\n");
491				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
492					if (pkt->address == addr->address) {
493						/* start the connection */
494						error = vpn_start_ph2(addr, pkt);
495						break;
496					}
497				}
498			}
499			break;
500
501		case VPNCTL_CMD_START_DPD:
502            {
503                struct vpnctl_cmd_start_dpd *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)combuf;
504                struct bound_addr *srv;
505                struct bound_addr *t_addr;
506
507                plog(ASL_LEVEL_DEBUG,
508                     "received start_dpd command on vpn control socket.\n");
509                LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
510                    if (pkt->address == srv->address) {
511                        union {                             // Wcast-align fix - force alignment
512                            struct sockaddr_storage ss;
513                            struct sockaddr_in	addr_in;
514                        } daddr;
515
516                        bzero(&daddr, sizeof(struct sockaddr_in));
517                        daddr.addr_in.sin_len = sizeof(struct sockaddr_in);
518                        daddr.addr_in.sin_addr.s_addr = srv->address;
519                        daddr.addr_in.sin_port = 0;
520                        daddr.addr_in.sin_family = AF_INET;
521
522                        /* start the dpd */
523                        error = ike_session_ph1_force_dpd(&daddr.ss);
524                        break;
525                    }
526                }
527            }
528			break;
529
530		case VPNCTL_CMD_ASSERT:
531			{
532				struct vpnctl_cmd_assert *pkt = ALIGNED_CAST(struct vpnctl_cmd_assert *)combuf;
533//				struct bound_addr *addr;
534//				struct bound_addr *t_addr;
535				struct sockaddr_in saddr;
536				struct sockaddr_in daddr;
537
538				plogdump(ASL_LEVEL_DEBUG, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr), "received assert command on vpn control socket.\n");
539//				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
540//					if (pkt->dst_address == addr->address) {
541						bzero(&saddr, sizeof(saddr));
542						saddr.sin_len = sizeof(saddr);
543						saddr.sin_addr.s_addr = pkt->src_address;
544						saddr.sin_port = 0;
545						saddr.sin_family = AF_INET;
546						bzero(&daddr, sizeof(daddr));
547						daddr.sin_len = sizeof(daddr);
548						daddr.sin_addr.s_addr = pkt->dst_address;
549						daddr.sin_port = 0;
550						daddr.sin_family = AF_INET;
551
552						error = vpn_assert((struct sockaddr_storage *)&saddr, (struct sockaddr_storage *)&daddr);
553						break;
554//					}
555//				}
556			}
557			break;
558
559		case VPNCTL_CMD_RECONNECT:
560			{
561				struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
562				struct bound_addr *addr;
563				struct bound_addr *t_addr;
564
565				plog(ASL_LEVEL_DEBUG,
566					 "received reconnect command on vpn control socket.\n");
567				LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
568					if (pkt->address == addr->address) {
569						/* start the connection */
570						error = vpn_connect(addr, VPN_RESTARTED_BY_API);
571						break;
572					}
573				}
574			}
575			break;
576
577		default:
578			plog(ASL_LEVEL_ERR,
579				"invalid command: %d\n", ntohs(hdr->msg_type));
580			error = -1;		// for now
581			break;
582	}
583
584	hdr->len = 0;
585	hdr->result = htons(error);
586	if (vpncontrol_reply(elem->sock, combuf) < 0)
587		return -1;
588
589	return 0;
590
591}
592
593static int
594vpncontrol_reply(int so, char *combuf)
595{
596	ssize_t tlen;
597
598	tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
599	if (tlen < 0) {
600		plog(ASL_LEVEL_ERR,
601			"failed to send vpn_control message: %s\n", strerror(errno));
602		return -1;
603	}
604
605	return 0;
606}
607
608int
609vpncontrol_notify_need_authinfo(phase1_handle_t *iph1, void* attr_list, size_t attr_len)
610{
611	struct vpnctl_status_need_authinfo *msg = NULL;
612	struct vpnctl_socket_elem *sock_elem;
613	struct bound_addr *bound_addr;
614	size_t msg_size;
615	ssize_t tlen;
616	u_int32_t address;
617	void *ptr;
618
619	if (!iph1)
620		goto end;
621
622	plog(ASL_LEVEL_DEBUG,
623		"sending vpn_control xauth need info status\n");
624
625	msg = (struct vpnctl_status_need_authinfo *)racoon_malloc(msg_size = sizeof(struct vpnctl_status_need_authinfo) + attr_len);
626	if (msg == NULL) {
627		plog(ASL_LEVEL_ERR,
628			"unable to allocate space for vpn control message.\n");
629		return -1;
630	}
631	msg->hdr.flags = 0;
632
633	if (iph1->remote->ss_family == AF_INET)
634		address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
635	else
636		goto end;		// for now
637
638	msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
639	msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
640	if (!ike_session_is_client_ph1_rekey(iph1)) {
641		msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_AUTHINFO);
642	} else {
643		msg->hdr.msg_type = htons(VPNCTL_STATUS_NEED_REAUTHINFO);
644	}
645	msg->address = address;
646	ptr = msg + 1;
647	memcpy(ptr, attr_list, attr_len);
648
649	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
650		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
651			if (bound_addr->address == 0xFFFFFFFF ||
652				bound_addr->address == address) {
653				plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
654				tlen = send(sock_elem->sock, msg, msg_size, 0);
655				if (tlen < 0) {
656					plog(ASL_LEVEL_ERR,
657						"failed to send vpn_control need authinfo status: %s\n", strerror(errno));
658				}
659				break;
660			}
661		}
662	}
663
664end:
665	if (msg)
666		racoon_free(msg);
667	return 0;
668}
669
670int
671vpncontrol_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)
672{
673	struct vpnctl_status_failed *msg = NULL;
674	struct vpnctl_socket_elem *sock_elem;
675	struct bound_addr *bound_addr;
676	size_t len;
677    ssize_t tlen;
678
679	len = sizeof(struct vpnctl_status_failed) + data_len;
680
681	msg = (struct vpnctl_status_failed *)racoon_malloc(len);
682	if (msg == NULL) {
683		plog(ASL_LEVEL_DEBUG,
684				"unable to allcate memory for vpn control status message.\n");
685		return -1;
686	}
687
688	msg->hdr.msg_type = htons(VPNCTL_STATUS_IKE_FAILED);
689	msg->hdr.flags = msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
690	msg->hdr.len = htons(len - sizeof(struct vpnctl_hdr));
691	msg->address = address;
692	msg->ike_code = htons(notify_code);
693	msg->from = htons(from);
694	if (data_len > 0)
695		memcpy(msg->data, data, data_len);
696	plog(ASL_LEVEL_DEBUG,
697			"sending vpn_control ike failed message - code=%d  from=%s.\n", notify_code,
698					(from == FROM_LOCAL ? "local" : "remote"));
699
700	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
701		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
702			if (bound_addr->address == 0xFFFFFFFF ||
703				bound_addr->address == address) {
704				tlen = send(sock_elem->sock, msg, len, 0);
705				if (tlen < 0) {
706					plog(ASL_LEVEL_ERR,
707						"Unable to send vpn_control ike notify failed: %s\n", strerror(errno));
708				}
709				break;
710			}
711		}
712	}
713
714	if (msg)
715		racoon_free(msg);
716	return 0;
717}
718
719char *
720vpncontrol_status_2_str(u_int16_t msg_type)
721{
722    switch (msg_type) {
723        case VPNCTL_STATUS_IKE_FAILED:
724            return "IKE failed";
725        case VPNCTL_STATUS_PH1_START_US:
726            return "Phase 1 started by us";
727        case VPNCTL_STATUS_PH1_START_PEER:
728            return "Phase 1 started by peer";
729        case VPNCTL_STATUS_PH1_ESTABLISHED:
730            return "Phase 1 established";
731        case VPNCTL_STATUS_PH2_START:
732            return "Phase 2 started";
733        case VPNCTL_STATUS_PH2_ESTABLISHED:
734            return "Phase 2 established";
735        case VPNCTL_STATUS_NEED_AUTHINFO:
736            return "Need authentication info";
737        case VPNCTL_STATUS_NEED_REAUTHINFO:
738            return "Need re-authentication info";
739        default:
740            return "";
741    }
742}
743
744
745int
746vpncontrol_notify_phase_change(int start, u_int16_t from, phase1_handle_t *iph1, phase2_handle_t *iph2)
747{
748	struct vpnctl_status_phase_change *msg;
749	struct vpnctl_socket_elem *sock_elem;
750	struct bound_addr *bound_addr;
751	ssize_t tlen;
752	size_t msg_size;
753	u_int32_t address;
754
755    if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
756		if (vpn_get_config(iph1, &msg, &msg_size) == 1)
757			return 0;	/* mode config not finished yet */
758	} else {
759		msg = racoon_malloc(msg_size = sizeof(struct vpnctl_status_phase_change));
760		msg->hdr.flags = 0;
761	}
762
763	if (msg == NULL) {
764		plog(ASL_LEVEL_ERR,
765						"unable to allocate space for vpn control message.\n");
766		return -1;
767	}
768	if (iph1) {
769		if (iph1->remote->ss_family == AF_INET)
770			address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
771		else
772			goto end;		// for now
773		msg->hdr.msg_type = htons(start ?
774			(from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER)
775			: VPNCTL_STATUS_PH1_ESTABLISHED);
776		// TODO: indicate version
777	} else {
778		if (iph2->dst->ss_family == AF_INET)
779			address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
780		else
781			goto end;		// for now
782		msg->hdr.msg_type = htons(start ? VPNCTL_STATUS_PH2_START : VPNCTL_STATUS_PH2_ESTABLISHED);
783		// TODO: indicate version
784	}
785    plog(ASL_LEVEL_NOTICE,
786         ">>>>> phase change status = %s\n", vpncontrol_status_2_str(ntohs(msg->hdr.msg_type)));
787
788	msg->hdr.cookie = msg->hdr.reserved = msg->hdr.result = 0;
789	msg->hdr.len = htons((msg_size) - sizeof(struct vpnctl_hdr));
790	msg->address = address;
791
792	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
793		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
794			if (bound_addr->address == 0xFFFFFFFF ||
795				bound_addr->address == address) {
796				plog(ASL_LEVEL_DEBUG, "vpn control writing %zu bytes\n", msg_size);
797				tlen = send(sock_elem->sock, msg, msg_size, 0);
798				if (tlen < 0) {
799					plog(ASL_LEVEL_ERR,
800						"failed to send vpn_control phase change status: %s\n", strerror(errno));
801				}
802				break;
803			}
804		}
805	}
806
807end:
808	if (msg)
809		racoon_free(msg);
810	return 0;
811}
812
813static int
814vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
815{
816	struct vpnctl_status_peer_resp msg;
817	struct vpnctl_socket_elem *sock_elem;
818	struct bound_addr *bound_addr;
819	ssize_t tlen;
820	int    rc = -1;
821
822	bzero(&msg, sizeof(msg));
823	msg.hdr.msg_type = htons(VPNCTL_STATUS_PEER_RESP);
824	msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
825	msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
826	msg.address = address;
827	msg.ike_code = notify_code;
828	plog(ASL_LEVEL_DEBUG,
829		 "sending vpn_control status (peer response) message - code=%d  addr=%x.\n", notify_code, address);
830
831	LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
832		LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
833			if (bound_addr->address == 0xFFFFFFFF ||
834				bound_addr->address == address) {
835				tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
836				if (tlen < 0) {
837					plog(ASL_LEVEL_ERR,
838						 "unable to send vpn_control status (peer response): %s\n", strerror(errno));
839				} else {
840					rc = 0;
841				}
842				break;
843			}
844		}
845	}
846
847	return rc;
848}
849
850int
851vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, phase1_handle_t *iph1)
852{
853	u_int32_t address;
854	int       rc;
855
856	if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
857		if (iph1->remote->ss_family == AF_INET)
858			address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
859		else
860			address = 0;
861	} else {
862		return 0;
863	}
864
865	if ((rc = vpncontrol_notify_peer_resp(notify_code, address)) == 0) {
866		iph1->parent_session->controller_awaiting_peer_resp = 0;
867	}
868	return rc;
869}
870
871int
872vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, phase2_handle_t *iph2)
873{
874	u_int32_t address;
875	int       rc;
876
877	if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
878		if (iph2->dst->ss_family == AF_INET)
879			address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
880		else
881			address = 0;
882	} else {
883		return 0;
884	}
885
886	if ((rc = vpncontrol_notify_peer_resp(notify_code, address)) == 0) {
887		iph2->parent_session->controller_awaiting_peer_resp = 0;
888	}
889	return rc;
890}
891
892int
893vpncontrol_init(void)
894{
895    int sock;
896
897	if (vpncontrolsock_path == NULL) {
898		lcconf->sock_vpncontrol = -1;
899		return 0;
900	}
901
902	if ( (lcconf->sock_vpncontrol = checklaunchd()) == 0 ) {
903		memset(&sunaddr, 0, sizeof(sunaddr));
904		sunaddr.sun_family = AF_UNIX;
905		snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
906			"%s", vpncontrolsock_path);
907
908		lcconf->sock_vpncontrol = socket(AF_UNIX, SOCK_STREAM, 0);
909		if (lcconf->sock_vpncontrol == -1) {
910			plog(ASL_LEVEL_ERR,
911				"socket: %s\n", strerror(errno));
912			return -1;
913		}
914
915		if (fcntl(lcconf->sock_vpncontrol, F_SETFL, O_NONBLOCK) == -1) {
916			plog(ASL_LEVEL_ERR, "failed to put VPN-Control socket in non-blocking mode\n");
917		}
918
919		unlink(sunaddr.sun_path);
920		if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
921				sizeof(sunaddr)) != 0) {
922			plog(ASL_LEVEL_ERR,
923				"bind(sockname:%s): %s\n",
924				sunaddr.sun_path, strerror(errno));
925			(void)close(lcconf->sock_vpncontrol);
926			return -1;
927		}
928
929		if (chown(sunaddr.sun_path, vpncontrolsock_owner, vpncontrolsock_group) != 0) {
930			plog(ASL_LEVEL_ERR,
931				"chown(%s, %d, %d): %s\n",
932				sunaddr.sun_path, vpncontrolsock_owner,
933				vpncontrolsock_group, strerror(errno));
934			(void)close(lcconf->sock_vpncontrol);
935			return -1;
936		}
937
938		if (chmod(sunaddr.sun_path, vpncontrolsock_mode) != 0) {
939			plog(ASL_LEVEL_ERR,
940				"chmod(%s, 0%03o): %s\n",
941				sunaddr.sun_path, vpncontrolsock_mode, strerror(errno));
942			(void)close(lcconf->sock_vpncontrol);
943			return -1;
944		}
945
946		if (listen(lcconf->sock_vpncontrol, 5) != 0) {
947			plog(ASL_LEVEL_ERR,
948				"listen(sockname:%s): %s\n",
949				sunaddr.sun_path, strerror(errno));
950			(void)close(lcconf->sock_vpncontrol);
951			return -1;
952		}
953		plog(ASL_LEVEL_DEBUG,
954			"opened %s as racoon management.\n", sunaddr.sun_path);
955	}
956    lcconf->vpncontrol_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->sock_vpncontrol, 0, dispatch_get_main_queue());
957    if (lcconf->vpncontrol_source == NULL) {
958        plog(ASL_LEVEL_ERR, "could not create vpncontrol socket source.");
959        return -1;
960    }
961    dispatch_source_set_event_handler_f(lcconf->vpncontrol_source, vpncontrol_handler);
962    sock = lcconf->sock_vpncontrol;
963    dispatch_source_set_cancel_handler(lcconf->vpncontrol_source,
964                                         ^{
965                                                close(sock);
966                                         });
967    dispatch_resume(lcconf->vpncontrol_source);
968    return 0;
969}
970
971void
972vpncontrol_disconnect_all(struct vpnctl_socket_elem *elem, const char *reason)
973{
974    struct bound_addr *addr;
975    struct bound_addr *t_addr;
976
977    plog(ASL_LEVEL_DEBUG,
978         "received disconnect all command.\n");
979
980    LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
981        /* stop any connections */
982        vpn_disconnect(addr, reason);
983    }
984}
985
986void
987vpncontrol_close()
988{
989    struct vpnctl_socket_elem *elem;
990	struct vpnctl_socket_elem *t_elem;
991
992    plog(ASL_LEVEL_DEBUG,
993         "vpncontrol_close.\n");
994
995    dispatch_source_cancel(lcconf->vpncontrol_source);
996    lcconf->vpncontrol_source = NULL;
997
998    lcconf->sock_vpncontrol = -1;
999    LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem)
1000        vpncontrol_close_comm(elem);
1001}
1002
1003static void
1004vpncontrol_close_comm(struct vpnctl_socket_elem *elem)
1005{
1006	struct bound_addr *addr;
1007	struct bound_addr *t_addr;
1008
1009	plog(ASL_LEVEL_DEBUG,
1010		"vpncontrol_close_comm.\n");
1011
1012	LIST_REMOVE(elem, chain);
1013	if (elem->sock != -1)
1014		dispatch_source_cancel(elem->source);
1015	LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
1016		flushsainfo_dynamic(addr->address);
1017		LIST_REMOVE(addr, chain);
1018		if (addr->version)
1019			vfree(addr->version);
1020		racoon_free(addr);
1021	}
1022	racoon_free(elem);
1023	check_auto_exit();
1024}
1025
1026int
1027vpn_control_connected(void)
1028{
1029	if (LIST_EMPTY(&lcconf->vpnctl_comm_socks))
1030		return 0;
1031	else
1032		return 1;
1033}
1034
1035#endif
1036