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