1/*	$NetBSD: admin.c,v 1.17.6.3 2009/04/20 13:32:57 tteras 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#include <sys/signal.h>
40#include <sys/stat.h>
41#include <sys/un.h>
42
43#include <net/pfkeyv2.h>
44
45#include <netinet/in.h>
46#include PATH_IPSEC_H
47
48
49#include <stdlib.h>
50#include <stdio.h>
51#include <string.h>
52#include <errno.h>
53#include <netdb.h>
54#ifdef HAVE_UNISTD_H
55#include <unistd.h>
56#endif
57#ifdef ENABLE_HYBRID
58#include <resolv.h>
59#endif
60
61#include "var.h"
62#include "misc.h"
63#include "vmbuf.h"
64#include "plog.h"
65#include "sockmisc.h"
66#include "debug.h"
67
68#include "schedule.h"
69#include "localconf.h"
70#include "remoteconf.h"
71#include "grabmyaddr.h"
72#include "isakmp_var.h"
73#include "isakmp.h"
74#include "oakley.h"
75#include "handler.h"
76#include "evt.h"
77#include "pfkey.h"
78#include "ipsec_doi.h"
79#include "admin.h"
80#include "admin_var.h"
81#include "isakmp_inf.h"
82#ifdef ENABLE_HYBRID
83#include "isakmp_cfg.h"
84#endif
85#include "session.h"
86#include "gcmalloc.h"
87
88#ifdef ENABLE_ADMINPORT
89char *adminsock_path = ADMINSOCK_PATH;
90uid_t adminsock_owner = 0;
91gid_t adminsock_group = 0;
92mode_t adminsock_mode = 0600;
93
94static struct sockaddr_un sunaddr;
95static int admin_process __P((int, char *));
96static int admin_reply __P((int, struct admin_com *, vchar_t *));
97
98int
99admin_handler()
100{
101	int so2;
102	struct sockaddr_storage from;
103	socklen_t fromlen = sizeof(from);
104	struct admin_com com;
105	char *combuf = NULL;
106	int len, error = -1;
107
108	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
109	if (so2 < 0) {
110		plog(LLV_ERROR, LOCATION, NULL,
111			"failed to accept admin command: %s\n",
112			strerror(errno));
113		return -1;
114	}
115
116	/* get buffer length */
117	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
118		if (errno == EINTR)
119			continue;
120		plog(LLV_ERROR, LOCATION, NULL,
121			"failed to recv admin command: %s\n",
122			strerror(errno));
123		goto end;
124	}
125
126	/* sanity check */
127	if (len < sizeof(com)) {
128		plog(LLV_ERROR, LOCATION, NULL,
129			"invalid header length of admin command\n");
130		goto end;
131	}
132
133	/* get buffer to receive */
134	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
135		plog(LLV_ERROR, LOCATION, NULL,
136			"failed to alloc buffer for admin command\n");
137		goto end;
138	}
139
140	/* get real data */
141	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
142		if (errno == EINTR)
143			continue;
144		plog(LLV_ERROR, LOCATION, NULL,
145			"failed to recv admin command: %s\n",
146			strerror(errno));
147		goto end;
148	}
149
150	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
151		/* reload does not work at all! */
152		signal_handler(SIGHUP);
153		goto end;
154	}
155
156	error = admin_process(so2, combuf);
157
158    end:
159	(void)close(so2);
160	if (combuf)
161		racoon_free(combuf);
162
163	return error;
164}
165
166/*
167 * main child's process.
168 */
169static int
170admin_process(so2, combuf)
171	int so2;
172	char *combuf;
173{
174	struct admin_com *com = (struct admin_com *)combuf;
175	vchar_t *buf = NULL;
176	vchar_t *id = NULL;
177	vchar_t *key = NULL;
178	int idtype = 0;
179	int error = -1;
180
181	com->ac_errno = 0;
182
183	switch (com->ac_cmd) {
184	case ADMIN_RELOAD_CONF:
185		/* don't entered because of proccessing it in other place. */
186		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
187		goto out;
188
189	case ADMIN_SHOW_SCHED:
190	{
191		caddr_t p = NULL;
192		int len;
193
194		com->ac_errno = -1;
195
196		if (sched_dump(&p, &len) == -1)
197			goto out2;
198
199		if ((buf = vmalloc(len)) == NULL)
200			goto out2;
201
202		memcpy(buf->v, p, len);
203
204		com->ac_errno = 0;
205out2:
206		racoon_free(p);
207		break;
208	}
209
210	case ADMIN_SHOW_EVT:
211		/* It's not really an error, don't force racoonctl to quit */
212		if ((buf = evt_dump()) == NULL)
213			com->ac_errno = 0;
214		break;
215
216	case ADMIN_SHOW_SA:
217	case ADMIN_FLUSH_SA:
218	    {
219		switch (com->ac_proto) {
220		case ADMIN_PROTO_ISAKMP:
221			switch (com->ac_cmd) {
222			case ADMIN_SHOW_SA:
223				buf = dumpph1();
224				if (buf == NULL)
225					com->ac_errno = -1;
226				break;
227			case ADMIN_FLUSH_SA:
228				flushph1();
229				break;
230			}
231			break;
232		case ADMIN_PROTO_IPSEC:
233		case ADMIN_PROTO_AH:
234		case ADMIN_PROTO_ESP:
235			switch (com->ac_cmd) {
236			case ADMIN_SHOW_SA:
237			    {
238				u_int p;
239				p = admin2pfkey_proto(com->ac_proto);
240				if (p == -1)
241					goto out;
242				buf = pfkey_dump_sadb(p);
243				if (buf == NULL)
244					com->ac_errno = -1;
245			    }
246				break;
247			case ADMIN_FLUSH_SA:
248				pfkey_flush_sadb(com->ac_proto);
249				break;
250			}
251			break;
252
253		case ADMIN_PROTO_INTERNAL:
254			switch (com->ac_cmd) {
255			case ADMIN_SHOW_SA:
256				buf = NULL; /*XXX dumpph2(&error);*/
257				if (buf == NULL)
258					com->ac_errno = error;
259				break;
260			case ADMIN_FLUSH_SA:
261				/*XXX flushph2();*/
262				com->ac_errno = 0;
263				break;
264			}
265			break;
266
267		default:
268			/* ignore */
269			com->ac_errno = -1;
270		}
271	    }
272		break;
273
274	case ADMIN_DELETE_SA: {
275		struct ph1handle *iph1;
276		struct sockaddr *dst;
277		struct sockaddr *src;
278		char *loc, *rem;
279
280		src = (struct sockaddr *)
281			&((struct admin_com_indexes *)
282			    ((caddr_t)com + sizeof(*com)))->src;
283		dst = (struct sockaddr *)
284			&((struct admin_com_indexes *)
285			    ((caddr_t)com + sizeof(*com)))->dst;
286
287		loc = racoon_strdup(saddrwop2str(src));
288		rem = racoon_strdup(saddrwop2str(dst));
289		STRDUP_FATAL(loc);
290		STRDUP_FATAL(rem);
291
292		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
293			plog(LLV_ERROR, LOCATION, NULL,
294			    "phase 1 for %s -> %s not found\n", loc, rem);
295		} else {
296			if (iph1->status == PHASE1ST_ESTABLISHED)
297				isakmp_info_send_d1(iph1);
298			purge_remote(iph1);
299		}
300
301		racoon_free(loc);
302		racoon_free(rem);
303
304		break;
305	}
306
307#ifdef ENABLE_HYBRID
308	case ADMIN_LOGOUT_USER: {
309		struct ph1handle *iph1;
310		char user[LOGINLEN+1];
311		int found = 0, len = com->ac_len - sizeof(com);
312
313		if (len > LOGINLEN) {
314			plog(LLV_ERROR, LOCATION, NULL,
315			    "malformed message (login too long)\n");
316			break;
317		}
318
319		memcpy(user, (char *)(com + 1), len);
320		user[len] = 0;
321
322		found = purgeph1bylogin(user);
323		plog(LLV_INFO, LOCATION, NULL,
324		    "deleted %d SA for user \"%s\"\n", found, user);
325
326		break;
327	}
328#endif
329
330	case ADMIN_DELETE_ALL_SA_DST: {
331		struct ph1handle *iph1;
332		struct sockaddr *dst;
333		char *loc, *rem;
334
335		dst = (struct sockaddr *)
336			&((struct admin_com_indexes *)
337			    ((caddr_t)com + sizeof(*com)))->dst;
338
339		rem = racoon_strdup(saddrwop2str(dst));
340		STRDUP_FATAL(rem);
341
342		plog(LLV_INFO, LOCATION, NULL,
343		    "Flushing all SAs for peer %s\n", rem);
344
345		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
346			loc = racoon_strdup(saddrwop2str(iph1->local));
347			STRDUP_FATAL(loc);
348
349			if (iph1->status == PHASE1ST_ESTABLISHED)
350				isakmp_info_send_d1(iph1);
351			purge_remote(iph1);
352
353			racoon_free(loc);
354		}
355
356		racoon_free(rem);
357
358		break;
359	}
360
361	case ADMIN_ESTABLISH_SA_PSK: {
362		struct admin_com_psk *acp;
363		char *data;
364
365		com->ac_cmd = ADMIN_ESTABLISH_SA;
366
367		acp = (struct admin_com_psk *)
368		    ((char *)com + sizeof(*com) +
369		    sizeof(struct admin_com_indexes));
370
371		idtype = acp->id_type;
372
373		if ((id = vmalloc(acp->id_len)) == NULL) {
374			plog(LLV_ERROR, LOCATION, NULL,
375			    "cannot allocate memory: %s\n",
376			    strerror(errno));
377			break;
378		}
379		data = (char *)(acp + 1);
380		memcpy(id->v, data, id->l);
381
382		if ((key = vmalloc(acp->key_len)) == NULL) {
383			plog(LLV_ERROR, LOCATION, NULL,
384			    "cannot allocate memory: %s\n",
385			    strerror(errno));
386			vfree(id);
387			id = NULL;
388			break;
389		}
390		data = (char *)(data + acp->id_len);
391		memcpy(key->v, data, key->l);
392	}
393	/* FALLTHROUGH */
394	case ADMIN_ESTABLISH_SA:
395	    {
396		struct sockaddr *dst;
397		struct sockaddr *src;
398		src = (struct sockaddr *)
399			&((struct admin_com_indexes *)
400			    ((caddr_t)com + sizeof(*com)))->src;
401		dst = (struct sockaddr *)
402			&((struct admin_com_indexes *)
403			    ((caddr_t)com + sizeof(*com)))->dst;
404
405		switch (com->ac_proto) {
406		case ADMIN_PROTO_ISAKMP: {
407			struct remoteconf *rmconf;
408			struct sockaddr *remote = NULL;
409			struct sockaddr *local = NULL;
410			u_int16_t port;
411
412			com->ac_errno = -1;
413
414			/* search appropreate configuration */
415			rmconf = getrmconf(dst);
416			if (rmconf == NULL) {
417				plog(LLV_ERROR, LOCATION, NULL,
418					"no configuration found "
419					"for %s\n", saddrwop2str(dst));
420				goto out1;
421			}
422
423			/* get remote IP address and port number. */
424			if ((remote = dupsaddr(dst)) == NULL)
425				goto out1;
426
427			port = extract_port(rmconf->remote);
428			if (set_port(remote, port) == NULL)
429				goto out1;
430
431			/* get local address */
432			if ((local = dupsaddr(src)) == NULL)
433				goto out1;
434
435			port = getmyaddrsport(local);
436			if (set_port(local, port) == NULL)
437				goto out1;
438
439#ifdef ENABLE_HYBRID
440			/* Set the id and key */
441			if (id && key) {
442				if (xauth_rmconf_used(&rmconf->xauth) == -1)
443					goto out1;
444
445				if (rmconf->xauth->login != NULL) {
446					vfree(rmconf->xauth->login);
447					rmconf->xauth->login = NULL;
448				}
449				if (rmconf->xauth->pass != NULL) {
450					vfree(rmconf->xauth->pass);
451					rmconf->xauth->pass = NULL;
452				}
453
454				rmconf->xauth->login = id;
455				rmconf->xauth->pass = key;
456			}
457#endif
458
459			plog(LLV_INFO, LOCATION, NULL,
460				"accept a request to establish IKE-SA: "
461				"%s\n", saddrwop2str(remote));
462
463			/* begin ident mode */
464			if (isakmp_ph1begin_i(rmconf, remote, local) < 0)
465				goto out1;
466
467			com->ac_errno = 0;
468out1:
469			if (local != NULL)
470				racoon_free(local);
471			if (remote != NULL)
472				racoon_free(remote);
473			break;
474		}
475		case ADMIN_PROTO_AH:
476		case ADMIN_PROTO_ESP:
477			break;
478		default:
479			/* ignore */
480			com->ac_errno = -1;
481		}
482	    }
483		break;
484
485	default:
486		plog(LLV_ERROR, LOCATION, NULL,
487			"invalid command: %d\n", com->ac_cmd);
488		com->ac_errno = -1;
489	}
490
491	if ((error = admin_reply(so2, com, buf)) != 0)
492		goto out;
493
494	error = 0;
495out:
496	if (buf != NULL)
497		vfree(buf);
498
499	return error;
500}
501
502static int
503admin_reply(so, combuf, buf)
504	int so;
505	struct admin_com *combuf;
506	vchar_t *buf;
507{
508	int tlen;
509	char *retbuf = NULL;
510
511	if (buf != NULL)
512		tlen = sizeof(*combuf) + buf->l;
513	else
514		tlen = sizeof(*combuf);
515
516	retbuf = racoon_calloc(1, tlen);
517	if (retbuf == NULL) {
518		plog(LLV_ERROR, LOCATION, NULL,
519			"failed to allocate admin buffer\n");
520		return -1;
521	}
522
523	memcpy(retbuf, combuf, sizeof(*combuf));
524	((struct admin_com *)retbuf)->ac_len = tlen;
525
526	if (buf != NULL)
527		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
528
529	tlen = send(so, retbuf, tlen, 0);
530	racoon_free(retbuf);
531	if (tlen < 0) {
532		plog(LLV_ERROR, LOCATION, NULL,
533			"failed to send admin command: %s\n",
534			strerror(errno));
535		return -1;
536	}
537
538	return 0;
539}
540
541/* ADMIN_PROTO -> SADB_SATYPE */
542int
543admin2pfkey_proto(proto)
544	u_int proto;
545{
546	switch (proto) {
547	case ADMIN_PROTO_IPSEC:
548		return SADB_SATYPE_UNSPEC;
549	case ADMIN_PROTO_AH:
550		return SADB_SATYPE_AH;
551	case ADMIN_PROTO_ESP:
552		return SADB_SATYPE_ESP;
553	default:
554		plog(LLV_ERROR, LOCATION, NULL,
555			"unsupported proto for admin: %d\n", proto);
556		return -1;
557	}
558	/*NOTREACHED*/
559}
560
561int
562admin_init()
563{
564	if (adminsock_path == NULL) {
565		lcconf->sock_admin = -1;
566		return 0;
567	}
568
569	memset(&sunaddr, 0, sizeof(sunaddr));
570	sunaddr.sun_family = AF_UNIX;
571	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
572		"%s", adminsock_path);
573
574	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
575	if (lcconf->sock_admin == -1) {
576		plog(LLV_ERROR, LOCATION, NULL,
577			"socket: %s\n", strerror(errno));
578		return -1;
579	}
580
581	unlink(sunaddr.sun_path);
582	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
583			sizeof(sunaddr)) != 0) {
584		plog(LLV_ERROR, LOCATION, NULL,
585			"bind(sockname:%s): %s\n",
586			sunaddr.sun_path, strerror(errno));
587		(void)close(lcconf->sock_admin);
588		return -1;
589	}
590
591	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
592		plog(LLV_ERROR, LOCATION, NULL,
593		    "chown(%s, %d, %d): %s\n",
594		    sunaddr.sun_path, adminsock_owner,
595		    adminsock_group, strerror(errno));
596		(void)close(lcconf->sock_admin);
597		return -1;
598	}
599
600	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
601		plog(LLV_ERROR, LOCATION, NULL,
602		    "chmod(%s, 0%03o): %s\n",
603		    sunaddr.sun_path, adminsock_mode, strerror(errno));
604		(void)close(lcconf->sock_admin);
605		return -1;
606	}
607
608	if (listen(lcconf->sock_admin, 5) != 0) {
609		plog(LLV_ERROR, LOCATION, NULL,
610			"listen(sockname:%s): %s\n",
611			sunaddr.sun_path, strerror(errno));
612		(void)close(lcconf->sock_admin);
613		return -1;
614	}
615	plog(LLV_DEBUG, LOCATION, NULL,
616		"open %s as racoon management.\n", sunaddr.sun_path);
617
618	return 0;
619}
620
621int
622admin_close()
623{
624	close(lcconf->sock_admin);
625	return 0;
626}
627#endif
628
629