admin.c revision 6b112236f31ae21c11e416d3dd5d265a5cc5177a
1/*	$NetBSD: admin.c,v 1.17.6.2 2008/06/18 07:30:19 mgrooms Exp $	*/
2
3/* Id: admin.c,v 1.25 2006/04/06 14:31:04 manubsd Exp */
4
5/*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "config.h"
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/socket.h>
39#ifndef ANDROID_CHANGES
40#include <sys/signal.h>
41#else
42#include <cutils/sockets.h>
43#include <arpa/inet.h>
44#include <ctype.h>
45#include "cfparse_proto.h"
46#define SIGHUP	1
47#endif
48#include <sys/stat.h>
49#include <sys/un.h>
50
51#include <net/pfkeyv2.h>
52
53#include <netinet/in.h>
54#include PATH_IPSEC_H
55
56
57#include <stdlib.h>
58#include <stdio.h>
59#include <string.h>
60#include <errno.h>
61#include <netdb.h>
62#ifdef HAVE_UNISTD_H
63#include <unistd.h>
64#endif
65#ifdef ENABLE_HYBRID
66#include <resolv.h>
67#endif
68
69#include "var.h"
70#include "misc.h"
71#include "vmbuf.h"
72#include "plog.h"
73#include "sockmisc.h"
74#include "debug.h"
75
76#include "schedule.h"
77#include "localconf.h"
78#include "remoteconf.h"
79#include "grabmyaddr.h"
80#include "isakmp_var.h"
81#include "isakmp.h"
82#include "oakley.h"
83#include "handler.h"
84#include "evt.h"
85#include "pfkey.h"
86#include "ipsec_doi.h"
87#include "admin.h"
88#include "admin_var.h"
89#include "isakmp_inf.h"
90#ifdef ENABLE_HYBRID
91#include "isakmp_cfg.h"
92#endif
93#include "session.h"
94#include "gcmalloc.h"
95
96#ifdef ENABLE_ADMINPORT
97char *adminsock_path = ADMINSOCK_PATH;
98uid_t adminsock_owner = 0;
99gid_t adminsock_group = 0;
100mode_t adminsock_mode = 0600;
101
102static struct sockaddr_un sunaddr;
103static int admin_process __P((int, char *));
104static int admin_reply __P((int, struct admin_com *, vchar_t *));
105
106int
107admin_handler()
108{
109	int so2;
110	struct sockaddr_storage from;
111	socklen_t fromlen = sizeof(from);
112	struct admin_com com;
113	char *combuf = NULL;
114	int len, error = -1;
115
116	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
117	if (so2 < 0) {
118		plog(LLV_ERROR, LOCATION, NULL,
119			"failed to accept admin command: %s\n",
120			strerror(errno));
121		return -1;
122	}
123
124	/* get buffer length */
125	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
126		if (errno == EINTR)
127			continue;
128		plog(LLV_ERROR, LOCATION, NULL,
129			"failed to recv admin command: %s\n",
130			strerror(errno));
131		goto end;
132	}
133
134	/* sanity check */
135	if (len < sizeof(com)) {
136		plog(LLV_ERROR, LOCATION, NULL,
137			"invalid header length of admin command\n");
138		goto end;
139	}
140
141	/* get buffer to receive */
142	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
143		plog(LLV_ERROR, LOCATION, NULL,
144			"failed to alloc buffer for admin command\n");
145		goto end;
146	}
147
148	/* get real data */
149	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
150		if (errno == EINTR)
151			continue;
152		plog(LLV_ERROR, LOCATION, NULL,
153			"failed to recv admin command: %s\n",
154			strerror(errno));
155		goto end;
156	}
157
158	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
159		/* reload does not work at all! */
160		signal_handler(SIGHUP);
161		goto end;
162	}
163
164	error = admin_process(so2, combuf);
165
166    end:
167	(void)close(so2);
168	if (combuf)
169		racoon_free(combuf);
170
171	return error;
172}
173
174/*
175 * main child's process.
176 */
177static int
178admin_process(so2, combuf)
179	int so2;
180	char *combuf;
181{
182	struct admin_com *com = (struct admin_com *)combuf;
183	vchar_t *buf = NULL;
184	vchar_t *id = NULL;
185	vchar_t *key = NULL;
186	int idtype = 0;
187	int error = -1;
188
189	com->ac_errno = 0;
190
191	switch (com->ac_cmd) {
192	case ADMIN_RELOAD_CONF:
193		/* don't entered because of proccessing it in other place. */
194		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
195		goto out;
196
197	case ADMIN_SHOW_SCHED:
198	{
199		caddr_t p = NULL;
200		int len;
201
202		com->ac_errno = -1;
203
204		if (sched_dump(&p, &len) == -1)
205			goto out2;
206
207		if ((buf = vmalloc(len)) == NULL)
208			goto out2;
209
210		memcpy(buf->v, p, len);
211
212		com->ac_errno = 0;
213out2:
214		racoon_free(p);
215		break;
216	}
217
218	case ADMIN_SHOW_EVT:
219		/* It's not really an error, don't force racoonctl to quit */
220		if ((buf = evt_dump()) == NULL)
221			com->ac_errno = 0;
222		break;
223
224	case ADMIN_SHOW_SA:
225	case ADMIN_FLUSH_SA:
226	    {
227		switch (com->ac_proto) {
228		case ADMIN_PROTO_ISAKMP:
229			switch (com->ac_cmd) {
230			case ADMIN_SHOW_SA:
231				buf = dumpph1();
232				if (buf == NULL)
233					com->ac_errno = -1;
234				break;
235			case ADMIN_FLUSH_SA:
236				flushph1();
237				break;
238			}
239			break;
240		case ADMIN_PROTO_IPSEC:
241		case ADMIN_PROTO_AH:
242		case ADMIN_PROTO_ESP:
243			switch (com->ac_cmd) {
244			case ADMIN_SHOW_SA:
245			    {
246				u_int p;
247				p = admin2pfkey_proto(com->ac_proto);
248				if (p == -1)
249					goto out;
250				buf = pfkey_dump_sadb(p);
251				if (buf == NULL)
252					com->ac_errno = -1;
253			    }
254				break;
255			case ADMIN_FLUSH_SA:
256				pfkey_flush_sadb(com->ac_proto);
257				break;
258			}
259			break;
260
261		case ADMIN_PROTO_INTERNAL:
262			switch (com->ac_cmd) {
263			case ADMIN_SHOW_SA:
264				buf = NULL; /*XXX dumpph2(&error);*/
265				if (buf == NULL)
266					com->ac_errno = error;
267				break;
268			case ADMIN_FLUSH_SA:
269				/*XXX flushph2();*/
270				com->ac_errno = 0;
271				break;
272			}
273			break;
274
275		default:
276			/* ignore */
277			com->ac_errno = -1;
278		}
279	    }
280		break;
281
282	case ADMIN_DELETE_SA: {
283		struct ph1handle *iph1;
284		struct sockaddr *dst;
285		struct sockaddr *src;
286		char *loc, *rem;
287
288		src = (struct sockaddr *)
289			&((struct admin_com_indexes *)
290			    ((caddr_t)com + sizeof(*com)))->src;
291		dst = (struct sockaddr *)
292			&((struct admin_com_indexes *)
293			    ((caddr_t)com + sizeof(*com)))->dst;
294
295		loc = racoon_strdup(saddrwop2str(src));
296		rem = racoon_strdup(saddrwop2str(dst));
297		STRDUP_FATAL(loc);
298		STRDUP_FATAL(rem);
299
300		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
301			plog(LLV_ERROR, LOCATION, NULL,
302			    "phase 1 for %s -> %s not found\n", loc, rem);
303		} else {
304			if (iph1->status == PHASE1ST_ESTABLISHED)
305				isakmp_info_send_d1(iph1);
306			purge_remote(iph1);
307		}
308
309		racoon_free(loc);
310		racoon_free(rem);
311
312		break;
313	}
314
315#ifdef ENABLE_HYBRID
316	case ADMIN_LOGOUT_USER: {
317		struct ph1handle *iph1;
318		char *user;
319		int found = 0;
320
321		if (com->ac_len > sizeof(com) + LOGINLEN + 1) {
322			plog(LLV_ERROR, LOCATION, NULL,
323			    "malformed message (login too long)\n");
324			break;
325		}
326
327		user = (char *)(com + 1);
328		found = purgeph1bylogin(user);
329		plog(LLV_INFO, LOCATION, NULL,
330		    "deleted %d SA for user \"%s\"\n", found, user);
331
332		break;
333	}
334#endif
335
336	case ADMIN_DELETE_ALL_SA_DST: {
337		struct ph1handle *iph1;
338		struct sockaddr *dst;
339		char *loc, *rem;
340
341		dst = (struct sockaddr *)
342			&((struct admin_com_indexes *)
343			    ((caddr_t)com + sizeof(*com)))->dst;
344
345		rem = racoon_strdup(saddrwop2str(dst));
346		STRDUP_FATAL(rem);
347
348		plog(LLV_INFO, LOCATION, NULL,
349		    "Flushing all SAs for peer %s\n", rem);
350
351		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
352			loc = racoon_strdup(saddrwop2str(iph1->local));
353			STRDUP_FATAL(loc);
354
355			if (iph1->status == PHASE1ST_ESTABLISHED)
356				isakmp_info_send_d1(iph1);
357			purge_remote(iph1);
358
359			racoon_free(loc);
360		}
361
362		racoon_free(rem);
363
364		break;
365	}
366
367	case ADMIN_ESTABLISH_SA_PSK: {
368		struct admin_com_psk *acp;
369		char *data;
370
371		com->ac_cmd = ADMIN_ESTABLISH_SA;
372
373		acp = (struct admin_com_psk *)
374		    ((char *)com + sizeof(*com) +
375		    sizeof(struct admin_com_indexes));
376
377		idtype = acp->id_type;
378
379		if ((id = vmalloc(acp->id_len)) == NULL) {
380			plog(LLV_ERROR, LOCATION, NULL,
381			    "cannot allocate memory: %s\n",
382			    strerror(errno));
383			break;
384		}
385		data = (char *)(acp + 1);
386		memcpy(id->v, data, id->l);
387
388		if ((key = vmalloc(acp->key_len)) == NULL) {
389			plog(LLV_ERROR, LOCATION, NULL,
390			    "cannot allocate memory: %s\n",
391			    strerror(errno));
392			vfree(id);
393			id = NULL;
394			break;
395		}
396		data = (char *)(data + acp->id_len);
397		memcpy(key->v, data, key->l);
398	}
399	/* FALLTHROUGH */
400	case ADMIN_ESTABLISH_SA:
401	    {
402		struct sockaddr *dst;
403		struct sockaddr *src;
404		src = (struct sockaddr *)
405			&((struct admin_com_indexes *)
406			    ((caddr_t)com + sizeof(*com)))->src;
407		dst = (struct sockaddr *)
408			&((struct admin_com_indexes *)
409			    ((caddr_t)com + sizeof(*com)))->dst;
410
411		switch (com->ac_proto) {
412		case ADMIN_PROTO_ISAKMP: {
413			struct remoteconf *rmconf;
414			struct sockaddr *remote = NULL;
415			struct sockaddr *local = NULL;
416			u_int16_t port;
417
418			com->ac_errno = -1;
419
420			/* search appropreate configuration */
421			rmconf = getrmconf(dst);
422			if (rmconf == NULL) {
423				plog(LLV_ERROR, LOCATION, NULL,
424					"no configuration found "
425					"for %s\n", saddrwop2str(dst));
426				goto out1;
427			}
428
429			/* get remote IP address and port number. */
430			if ((remote = dupsaddr(dst)) == NULL)
431				goto out1;
432
433			port = extract_port(rmconf->remote);
434			if (set_port(remote, port) == NULL)
435				goto out1;
436
437			/* get local address */
438			if ((local = dupsaddr(src)) == NULL)
439				goto out1;
440
441			port = getmyaddrsport(local);
442			if (set_port(local, port) == NULL)
443				goto out1;
444
445#ifdef ENABLE_HYBRID
446			/* Set the id and key */
447			if (id && key) {
448				if (xauth_rmconf_used(&rmconf->xauth) == -1)
449					goto out1;
450
451				if (rmconf->xauth->login != NULL) {
452					vfree(rmconf->xauth->login);
453					rmconf->xauth->login = NULL;
454				}
455				if (rmconf->xauth->pass != NULL) {
456					vfree(rmconf->xauth->pass);
457					rmconf->xauth->pass = NULL;
458				}
459
460				rmconf->xauth->login = id;
461				rmconf->xauth->pass = key;
462			}
463#endif
464
465			plog(LLV_INFO, LOCATION, NULL,
466				"accept a request to establish IKE-SA: "
467				"%s\n", saddrwop2str(remote));
468
469			/* begin ident mode */
470			if (isakmp_ph1begin_i(rmconf, remote, local) < 0)
471				goto out1;
472
473			com->ac_errno = 0;
474out1:
475			if (local != NULL)
476				racoon_free(local);
477			if (remote != NULL)
478				racoon_free(remote);
479			break;
480		}
481		case ADMIN_PROTO_AH:
482		case ADMIN_PROTO_ESP:
483			break;
484		default:
485			/* ignore */
486			com->ac_errno = -1;
487		}
488	    }
489		break;
490
491	default:
492		plog(LLV_ERROR, LOCATION, NULL,
493			"invalid command: %d\n", com->ac_cmd);
494		com->ac_errno = -1;
495	}
496
497	if ((error = admin_reply(so2, com, buf)) != 0)
498		goto out;
499
500	error = 0;
501out:
502	if (buf != NULL)
503		vfree(buf);
504
505	return error;
506}
507
508static int
509admin_reply(so, combuf, buf)
510	int so;
511	struct admin_com *combuf;
512	vchar_t *buf;
513{
514	int tlen;
515	char *retbuf = NULL;
516
517	if (buf != NULL)
518		tlen = sizeof(*combuf) + buf->l;
519	else
520		tlen = sizeof(*combuf);
521
522	retbuf = racoon_calloc(1, tlen);
523	if (retbuf == NULL) {
524		plog(LLV_ERROR, LOCATION, NULL,
525			"failed to allocate admin buffer\n");
526		return -1;
527	}
528
529	memcpy(retbuf, combuf, sizeof(*combuf));
530	((struct admin_com *)retbuf)->ac_len = tlen;
531
532	if (buf != NULL)
533		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
534
535	tlen = send(so, retbuf, tlen, 0);
536	racoon_free(retbuf);
537	if (tlen < 0) {
538		plog(LLV_ERROR, LOCATION, NULL,
539			"failed to send admin command: %s\n",
540			strerror(errno));
541		return -1;
542	}
543
544	return 0;
545}
546
547/* ADMIN_PROTO -> SADB_SATYPE */
548int
549admin2pfkey_proto(proto)
550	u_int proto;
551{
552	switch (proto) {
553	case ADMIN_PROTO_IPSEC:
554		return SADB_SATYPE_UNSPEC;
555	case ADMIN_PROTO_AH:
556		return SADB_SATYPE_AH;
557	case ADMIN_PROTO_ESP:
558		return SADB_SATYPE_ESP;
559	default:
560		plog(LLV_ERROR, LOCATION, NULL,
561			"unsupported proto for admin: %d\n", proto);
562		return -1;
563	}
564	/*NOTREACHED*/
565}
566
567int
568admin_init()
569{
570	if (adminsock_path == NULL) {
571		lcconf->sock_admin = -1;
572		return 0;
573	}
574
575	memset(&sunaddr, 0, sizeof(sunaddr));
576	sunaddr.sun_family = AF_UNIX;
577	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
578		"%s", adminsock_path);
579
580	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
581	if (lcconf->sock_admin == -1) {
582		plog(LLV_ERROR, LOCATION, NULL,
583			"socket: %s\n", strerror(errno));
584		return -1;
585	}
586
587	unlink(sunaddr.sun_path);
588	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
589			sizeof(sunaddr)) != 0) {
590		plog(LLV_ERROR, LOCATION, NULL,
591			"bind(sockname:%s): %s\n",
592			sunaddr.sun_path, strerror(errno));
593		(void)close(lcconf->sock_admin);
594		return -1;
595	}
596
597	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
598		plog(LLV_ERROR, LOCATION, NULL,
599		    "chown(%s, %d, %d): %s\n",
600		    sunaddr.sun_path, adminsock_owner,
601		    adminsock_group, strerror(errno));
602		(void)close(lcconf->sock_admin);
603		return -1;
604	}
605
606	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
607		plog(LLV_ERROR, LOCATION, NULL,
608		    "chmod(%s, 0%03o): %s\n",
609		    sunaddr.sun_path, adminsock_mode, strerror(errno));
610		(void)close(lcconf->sock_admin);
611		return -1;
612	}
613
614	if (listen(lcconf->sock_admin, 5) != 0) {
615		plog(LLV_ERROR, LOCATION, NULL,
616			"listen(sockname:%s): %s\n",
617			sunaddr.sun_path, strerror(errno));
618		(void)close(lcconf->sock_admin);
619		return -1;
620	}
621	plog(LLV_DEBUG, LOCATION, NULL,
622		"open %s as racoon management.\n", sunaddr.sun_path);
623
624	return 0;
625}
626
627int
628admin_close()
629{
630	close(lcconf->sock_admin);
631	return 0;
632}
633#endif
634
635#ifdef ANDROID_CHANGES
636// Add the android specific control commands from VPN settings.
637#define CMD_LOAD_CONFIG "LOAD_CONFIG "
638#define CMD_SETKEY "SETKEY "
639#define CMD_SET_CERTS "SET_CERTS "
640#define RACOON_SOCKET "racoon"
641#define PORT_L2TP 1701
642
643// The following policy is supported for now.
644#define INCOMING_POLICY "in ipsec esp/transport//require"
645#define OUTGOING_POLICY "out ipsec esp/transport//require"
646
647static inline int get_sockaddr_in(addr, port, sin)
648    const char *addr;
649    int port;
650    struct sockaddr_in *sin;
651{
652    struct hostent *entry;
653
654    sin->sin_family = AF_INET;
655    sin->sin_port = htons(port);
656    sin->sin_addr.s_addr = inet_addr(addr);
657
658    if ((int)sin->sin_addr.s_addr != -1) {
659        return 0;
660    }
661    if ((entry = gethostbyname(addr)) != NULL) {
662        memcpy(&sin->sin_addr, *entry->h_addr_list, sizeof(struct in_addr));
663        if ((int)sin->sin_addr.s_addr != -1) {
664            return 0;
665        }
666    }
667    plog(LLV_ERROR, LOCATION, NULL,
668         "ERROR: incorrect src or dst address(%s)", addr);
669    return -1;
670}
671
672static int parse_addresses(buf, src, dst)
673    char *buf;
674    struct sockaddr_in *src, *dst;
675{
676    char *tokens[2], *argv = buf;
677    int i = 0;
678    while(i < 2) {
679        if ((tokens[i++] = strtok(argv, " ")) == NULL) {
680            return -1;
681        }
682        argv = NULL;
683    }
684    if ((get_sockaddr_in(tokens[0], 0, src) != 0) ||
685        (get_sockaddr_in(tokens[1], PORT_L2TP, dst) != 0)) {
686        return -1;
687    }
688    return 0;
689}
690
691static int spdadd(addresses)
692    const char *addresses;
693{
694    struct sockaddr src, dst;
695    char *outpolicy, *inpolicy;
696    int inlen, outlen, plen;
697    int so = -1;
698
699    /* SETKEY src_ip dst_ip */
700    if (parse_addresses(addresses, (struct sockaddr_in *)&src,
701        (struct sockaddr_in *)&dst) < 0) {
702        exit(1);
703    }
704
705    outpolicy = ipsec_set_policy(OUTGOING_POLICY, strlen(OUTGOING_POLICY));
706    outlen = ipsec_get_policylen(outpolicy);
707    inpolicy = ipsec_set_policy(INCOMING_POLICY, strlen(INCOMING_POLICY));
708    inlen = ipsec_get_policylen(inpolicy);
709
710    if ((so = pfkey_open()) < 0) {
711        plog(LLV_ERROR, LOCATION, NULL, "ERROR: %s", ipsec_strerror());
712        exit(1);
713    }
714    // spdflush()
715    if (pfkey_send_spdflush(so) < 0) {
716        plog(LLV_ERROR, LOCATION, NULL, "ERROR: %s", ipsec_strerror());
717        exit(1);
718    }
719    plen = sizeof(struct in_addr) << 3;
720    // add outgoing policy
721    if (pfkey_send_spdadd(so, &src, plen, &dst, plen,
722                17, outpolicy, outlen, 0) < 0) {
723        plog(LLV_ERROR, LOCATION, NULL, "ERROR: %s", ipsec_strerror());
724        exit(1);
725    }
726    // add incoming policy
727    if (pfkey_send_spdadd(so, &dst, plen, &src, plen,
728                17, inpolicy, inlen, 0) < 0) {
729        plog(LLV_ERROR, LOCATION, NULL, "ERROR: %s", ipsec_strerror());
730        exit(1);
731    }
732
733    pfkey_close(so);
734    return 0;
735}
736
737static int setcerts(cmd)
738    const char *cmd;
739{
740    /*
741     * SET_CERTS has 4 arguments:
742     * destip cacert_path usercert_path userkey_path
743     */
744    struct remoteconf *tplrmconf;
745    struct sockaddr dst, anonymous;
746    char *tokens[4], *buf = (char*)cmd;
747    int i = 0;
748    while(i < 4) {
749        if ((tokens[i++] = strtok(buf, " ")) == NULL) {
750            plog(LLV_ERROR, LOCATION, NULL,
751                 "incorrect command SET_CERTS %s", cmd);
752            return -1;
753        }
754        buf = NULL;
755    }
756    if (get_sockaddr_in((struct sockaddr_in *)&dst, tokens[0], 0) != 0) {
757        plog(LLV_ERROR, LOCATION, NULL, "incorrect dest address %s", tokens[0]);
758        return -1;
759    }
760    anonymous.sa_family = AF_UNSPEC;
761    if((tplrmconf = getrmconf(&anonymous)) == NULL) {
762        plog(LLV_ERROR, LOCATION, NULL, "Can not find the remtoe template");
763        return -1;
764    }
765    memcpy(tplrmconf->remote, &dst, sizeof(dst));
766    tplrmconf->cacertfile = strdup(tokens[1]);
767    tplrmconf->mycertfile = strdup(tokens[2]);
768    tplrmconf->myprivfile = strdup(tokens[3]);
769    return 0;
770}
771
772static int
773control_process(buf)
774    char *buf;
775{
776    plog(LLV_ERROR, LOCATION, NULL, "control command %s", buf);
777    if(strncmp(buf, CMD_LOAD_CONFIG, strlen(CMD_LOAD_CONFIG)) == 0) {
778        /* LOAD_CONFIG /data/misc/vpn/xxx/racoon.conf */
779        lcconf->racoon_conf = strdup(buf + strlen(CMD_LOAD_CONFIG));
780        return cfreparse();
781    } else if (strncmp(buf, CMD_SETKEY, strlen(CMD_SETKEY)) == 0) {
782        return spdadd(buf + strlen(CMD_SETKEY));
783    } else if (strncmp(buf, CMD_SET_CERTS, strlen(CMD_SET_CERTS)) == 0) {
784        return setcerts(buf + strlen(CMD_SET_CERTS));
785    }
786    plog(LLV_ERROR, LOCATION, NULL, "Unsupported command '%s'", buf);
787    return -1;
788}
789
790int
791control_init()
792{
793    lcconf->control_client = -1;
794    lcconf->sock_control = android_get_control_socket(RACOON_SOCKET);
795    if (lcconf->sock_control < 0) {
796        plog(LLV_ERROR, LOCATION, NULL,
797             "Obtaining file descriptor socket '%s' failed: %s",
798             RACOON_SOCKET, strerror(errno));
799        return -1;
800    }
801    if (listen(lcconf->sock_control, 5) < 0) {
802        plog(LLV_ERROR, LOCATION, NULL,
803             "Unable to listen on fd '%d' for socket '%s': %s",
804             lcconf->sock_control, RACOON_SOCKET, strerror(errno));
805        close(lcconf->sock_control);
806        lcconf->sock_control = -1;
807        return -1;
808    }
809    return 0;
810}
811
812int
813control_newclient()
814{
815    struct sockaddr_storage from;
816    socklen_t fromlen = sizeof(from);
817
818    lcconf->control_client =
819        accept(lcconf->sock_control, (struct sockaddr *)&from, &fromlen);
820    if (lcconf->control_client < 0) {
821        plog(LLV_ERROR, LOCATION, NULL,
822            "failed to accept control command: %s\n",
823            strerror(errno));
824        return -1;
825    }
826    return 0;
827}
828
829int
830control_handler()
831{
832    char buf[512], reply;
833    int i, n, len, error = -1;
834
835    /* get command */
836    i = 0;
837    len = sizeof(buf);
838    while ((n = recv(lcconf->control_client, buf + i, len - i, 0)) > 0) {
839        i += n;
840        if (i >= len) {
841            plog(LLV_ERROR, LOCATION, NULL,
842                "command is too long: %s\n", buf);
843            goto end;
844        } else if (buf[i - 1] == 0) {
845            error = control_process(buf);
846            goto end;
847        }
848    }
849    plog(LLV_ERROR, LOCATION, NULL,
850        "failed to recv control command: %s\n", strerror(errno));
851
852end:
853    reply = error;
854    if (send(lcconf->control_client, &reply, 1, 0) != 1) {
855        plog(LLV_ERROR, LOCATION, NULL,
856             "failed to send the reply(%d) back\n", reply);
857    }
858    (void)close(lcconf->control_client);
859    lcconf->control_client = -1;
860    return error;
861}
862
863int
864control_close()
865{
866    close(lcconf->sock_control);
867    return 0;
868}
869
870void test_commands(char *cmd)
871{
872  control_process(0, cmd);
873}
874#endif
875