xref: /openbsd-src/usr.sbin/ikectl/ikectl.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: ikectl.c,v 1.13 2012/05/02 18:01:25 gsoares Exp $	*/
2 
3 /*
4  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net>
5  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/param.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/queue.h>
26 #include <sys/un.h>
27 #include <sys/tree.h>
28 
29 #include <err.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <event.h>
36 
37 #include "iked.h"
38 #include "parser.h"
39 
40 __dead void	 usage(void);
41 
42 struct imsgname {
43 	int type;
44 	char *name;
45 	void (*func)(struct imsg *);
46 };
47 
48 struct imsgname *monitor_lookup(u_int8_t);
49 void		 monitor_id(struct imsg *);
50 int		 monitor(struct imsg *);
51 
52 int		 ca_opt(struct parse_result *);
53 
54 struct imsgname imsgs[] = {
55 	{ IMSG_CTL_OK,			"ok",			NULL },
56 	{ IMSG_CTL_FAIL,		"fail",			NULL },
57 	{ IMSG_CTL_VERBOSE,		"verbose",		NULL },
58 	{ IMSG_CTL_RELOAD,		"reload",		NULL },
59 	{ IMSG_CTL_RESET,		"reset",		NULL },
60 	{ 0,				NULL,			NULL }
61 
62 };
63 struct imsgname imsgunknown = {
64 	-1,				"<unknown>",		NULL
65 };
66 
67 struct imsgbuf	*ibuf;
68 struct snmpd	*env;
69 
70 __dead void
71 usage(void)
72 {
73 	extern char *__progname;
74 
75 	fprintf(stderr, "usage: %s [-q] [-s socket] command [arg ...]\n",
76 	    __progname);
77 	exit(1);
78 }
79 
80 int
81 ca_opt(struct parse_result *res)
82 {
83 	struct ca	*ca;
84 	size_t		 len;
85 	char		*p;
86 
87 	ca = ca_setup(res->caname, (res->action == CA_CREATE),
88 	    res->quiet, res->pass);
89 	if (ca == NULL)
90 		errx(1, "ca_setup failed");
91 
92 	/* assume paths are relative to /etc if not absolute */
93 	if (res->path && (res->path[0] != '.') && (res->path[0] != '/')) {
94 		len = 5 + strlen(res->path) + 1;
95 		if ((p = malloc(len)) == NULL)
96 			err(1, "malloc");
97 		snprintf(p, len, "/etc/%s", res->path);
98 		free(res->path);
99 		res->path = p;
100 	}
101 
102 	switch (res->action) {
103 	case CA_CREATE:
104 		ca_create(ca);
105 		break;
106 	case CA_DELETE:
107 		ca_delete(ca);
108 		break;
109 	case CA_INSTALL:
110 		ca_install(ca, res->path);
111 		break;
112 	case CA_EXPORT:
113 		ca_export(ca, NULL, res->peer, res->pass);
114 		break;
115 	case CA_CERT_CREATE:
116 	case CA_SERVER:
117 	case CA_CLIENT:
118 		ca_certificate(ca, res->host, res->htype, res->action);
119 		break;
120 	case CA_CERT_DELETE:
121 		ca_delkey(ca, res->host);
122 		break;
123 	case CA_CERT_INSTALL:
124 		ca_cert_install(ca, res->host, res->path);
125 		break;
126 	case CA_CERT_EXPORT:
127 		ca_export(ca, res->host, res->peer, res->pass);
128 		break;
129 	case CA_CERT_REVOKE:
130 		ca_revoke(ca, res->host);
131 		break;
132 	case SHOW_CA_CERTIFICATES:
133 		ca_show_certs(ca, res->host);
134 		break;
135 	case CA_KEY_CREATE:
136 		ca_key_create(ca, res->host);
137 		break;
138 	case CA_KEY_DELETE:
139 		ca_key_delete(ca, res->host);
140 		break;
141 	case CA_KEY_INSTALL:
142 		ca_key_install(ca, res->host, res->path);
143 		break;
144 	case CA_KEY_IMPORT:
145 		ca_key_import(ca, res->host, res->path);
146 		break;
147 	default:
148 		break;
149 	}
150 
151 	return (0);
152 }
153 
154 int
155 main(int argc, char *argv[])
156 {
157 	struct sockaddr_un	 sun;
158 	struct parse_result	*res;
159 	struct imsg		 imsg;
160 	int			 ctl_sock;
161 	int			 done = 1;
162 	int			 n;
163 	int			 ch;
164 	int			 v = 0;
165 	int			 quiet = 0;
166 	const char		*sock = IKED_SOCKET;
167 
168 	if ((env = calloc(1, sizeof(struct snmpd *))) == NULL)
169 		err(1, "calloc");
170 
171 	while ((ch = getopt(argc, argv, "qs:")) != -1) {
172 		switch (ch) {
173 		case 'q':
174 			quiet = 1;
175 			break;
176 		case 's':
177 			sock = optarg;
178 			break;
179 		default:
180 			usage();
181 			/* NOTREACHED */
182 		}
183 	}
184 	argc -= optind;
185 	argv += optind;
186 
187 	/* parse options */
188 	if ((res = parse(argc, argv)) == NULL)
189 		exit(1);
190 
191 	res->quiet = quiet;
192 
193 	switch (res->action) {
194 	case CA_CREATE:
195 	case CA_DELETE:
196 	case CA_INSTALL:
197 	case CA_EXPORT:
198 	case CA_CERT_CREATE:
199 	case CA_CLIENT:
200 	case CA_SERVER:
201 	case CA_CERT_DELETE:
202 	case CA_CERT_INSTALL:
203 	case CA_CERT_EXPORT:
204 	case CA_CERT_REVOKE:
205 	case SHOW_CA:
206 	case SHOW_CA_CERTIFICATES:
207 	case CA_KEY_CREATE:
208 	case CA_KEY_DELETE:
209 	case CA_KEY_INSTALL:
210 	case CA_KEY_IMPORT:
211 		ca_opt(res);
212 		break;
213 	case NONE:
214 		usage();
215 		break;
216 	default:
217 		goto connect;
218 	}
219 
220 	free(env);
221 	return (0);
222 
223  connect:
224 	/* connect to iked control socket */
225 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
226 		err(1, "socket");
227 
228 	bzero(&sun, sizeof(sun));
229 	sun.sun_family = AF_UNIX;
230 	strlcpy(sun.sun_path, sock, sizeof(sun.sun_path));
231  reconnect:
232 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
233 		/* Keep retrying if running in monitor mode */
234 		if (res->action == MONITOR &&
235 		    (errno == ENOENT || errno == ECONNREFUSED)) {
236 			usleep(100);
237 			goto reconnect;
238 		}
239 		err(1, "connect: %s", sock);
240 	}
241 
242 	if (res->ibuf != NULL)
243 		ibuf = res->ibuf;
244 	else
245 		if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
246 			err(1, "malloc");
247 	imsg_init(ibuf, ctl_sock);
248 
249 	/* process user request */
250 	switch (res->action) {
251 	case RESETALL:
252 		v = RESET_ALL;
253 		break;
254 	case RESETCA:
255 		v = RESET_CA;
256 		break;
257 	case RESETPOLICY:
258 		v = RESET_POLICY;
259 		break;
260 	case RESETSA:
261 		v = RESET_SA;
262 		break;
263 	case RESETUSER:
264 		v = RESET_USER;
265 		break;
266 	case LOG_VERBOSE:
267 		v = 2;
268 		break;
269 	case LOG_BRIEF:
270 	default:
271 		v = 0;
272 		break;
273 	}
274 
275 	switch (res->action) {
276 	case NONE:
277 		usage();
278 		/* NOTREACHED */
279 		break;
280 	case RESETALL:
281 	case RESETCA:
282 	case RESETPOLICY:
283 	case RESETSA:
284 	case RESETUSER:
285 		imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v));
286 		printf("reset request sent.\n");
287 		break;
288 	case LOAD:
289 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
290 		    res->path, strlen(res->path));
291 		break;
292 	case RELOAD:
293 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
294 		break;
295 	case MONITOR:
296 		imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
297 		done = 0;
298 		break;
299 	case COUPLE:
300 		imsg_compose(ibuf, IMSG_CTL_COUPLE, 0, 0, -1, NULL, 0);
301 		break;
302 	case DECOUPLE:
303 		imsg_compose(ibuf, IMSG_CTL_DECOUPLE, 0, 0, -1, NULL, 0);
304 		break;
305 	case ACTIVE:
306 		imsg_compose(ibuf, IMSG_CTL_ACTIVE, 0, 0, -1, NULL, 0);
307 		break;
308 	case PASSIVE:
309 		imsg_compose(ibuf, IMSG_CTL_PASSIVE, 0, 0, -1, NULL, 0);
310 		break;
311 	case LOG_VERBOSE:
312 	case LOG_BRIEF:
313 		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v));
314 		printf("logging request sent.\n");
315 		break;
316 	default:
317 		break;
318 	}
319 
320 	while (ibuf->w.queued)
321 		if (msgbuf_write(&ibuf->w) < 0)
322 			err(1, "write error");
323 
324 	while (!done) {
325 		if ((n = imsg_read(ibuf)) == -1)
326 			errx(1, "imsg_read error");
327 		if (n == 0)
328 			errx(1, "pipe closed");
329 
330 		while (!done) {
331 			if ((n = imsg_get(ibuf, &imsg)) == -1)
332 				errx(1, "imsg_get error");
333 			if (n == 0)
334 				break;
335 			switch (res->action) {
336 			case MONITOR:
337 				done = monitor(&imsg);
338 				break;
339 			default:
340 				break;
341 			}
342 			imsg_free(&imsg);
343 		}
344 	}
345 	close(ctl_sock);
346 	free(ibuf);
347 
348 	return (0);
349 }
350 
351 struct imsgname *
352 monitor_lookup(u_int8_t type)
353 {
354 	int i;
355 
356 	for (i = 0; imsgs[i].name != NULL; i++)
357 		if (imsgs[i].type == type)
358 			return (&imsgs[i]);
359 	return (&imsgunknown);
360 }
361 
362 int
363 monitor(struct imsg *imsg)
364 {
365 	time_t			 now;
366 	int			 done = 0;
367 	struct imsgname		*imn;
368 
369 	now = time(NULL);
370 
371 	imn = monitor_lookup(imsg->hdr.type);
372 	printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name,
373 	    imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid);
374 	printf("\ttimestamp: %u, %s", now, ctime(&now));
375 	if (imn->type == -1)
376 		done = 1;
377 	if (imn->func != NULL)
378 		(*imn->func)(imsg);
379 
380 	return (done);
381 }
382