xref: /openbsd-src/usr.sbin/ikectl/ikectl.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /*	$OpenBSD: ikectl.c,v 1.27 2021/11/21 22:44:08 tobhe 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		 show_string(struct imsg *);
52 
53 int		 ca_opt(struct parse_result *);
54 
55 struct imsgname imsgs[] = {
56 	{ IMSG_CTL_OK,			"ok",			NULL },
57 	{ IMSG_CTL_FAIL,		"fail",			NULL },
58 	{ IMSG_CTL_VERBOSE,		"verbose",		NULL },
59 	{ IMSG_CTL_RELOAD,		"reload",		NULL },
60 	{ IMSG_CTL_RESET,		"reset",		NULL },
61 	{ IMSG_CTL_SHOW_SA,		"show sa",		NULL },
62 	{ IMSG_CTL_SHOW_CERTSTORE,	"show certstore",	NULL },
63 	{ 0,				NULL,			NULL }
64 
65 };
66 struct imsgname imsgunknown = {
67 	-1,				"<unknown>",		NULL
68 };
69 
70 struct imsgbuf	*ibuf;
71 
72 __dead void
73 usage(void)
74 {
75 	extern char *__progname;
76 
77 	fprintf(stderr, "usage: %s [-q] [-s socket] command [arg ...]\n",
78 	    __progname);
79 	exit(1);
80 }
81 
82 int
83 ca_opt(struct parse_result *res)
84 {
85 	struct ca	*ca;
86 	size_t		 len;
87 	char		*p;
88 
89 	ca = ca_setup(res->caname, (res->action == CA_CREATE),
90 	    res->quiet, res->pass);
91 	if (ca == NULL)
92 		errx(1, "ca_setup failed");
93 
94 	/* assume paths are relative to /etc if not absolute */
95 	if (res->path && (res->path[0] != '.') && (res->path[0] != '/')) {
96 		len = 5 + strlen(res->path) + 1;
97 		if ((p = malloc(len)) == NULL)
98 			err(1, "malloc");
99 		snprintf(p, len, "/etc/%s", res->path);
100 		free(res->path);
101 		res->path = p;
102 	}
103 
104 	switch (res->action) {
105 	case CA_CREATE:
106 		ca_create(ca);
107 		break;
108 	case CA_DELETE:
109 		ca_delete(ca);
110 		break;
111 	case CA_INSTALL:
112 		ca_install(ca, res->path);
113 		break;
114 	case CA_EXPORT:
115 		ca_export(ca, NULL, res->peer, res->pass);
116 		break;
117 	case CA_CERT_CREATE:
118 	case CA_SERVER:
119 	case CA_CLIENT:
120 	case CA_OCSP:
121 		ca_certificate(ca, res->host, res->htype, res->action);
122 		break;
123 	case CA_CERT_DELETE:
124 		ca_delkey(ca, res->host);
125 		break;
126 	case CA_CERT_INSTALL:
127 		ca_cert_install(ca, res->host, res->path);
128 		break;
129 	case CA_CERT_EXPORT:
130 		ca_export(ca, res->host, res->peer, res->pass);
131 		break;
132 	case CA_CERT_REVOKE:
133 		ca_revoke(ca, res->host);
134 		break;
135 	case SHOW_CA_CERTIFICATES:
136 		ca_show_certs(ca, res->host);
137 		break;
138 	case CA_KEY_CREATE:
139 		ca_key_create(ca, res->host);
140 		break;
141 	case CA_KEY_DELETE:
142 		ca_key_delete(ca, res->host);
143 		break;
144 	case CA_KEY_INSTALL:
145 		ca_key_install(ca, res->host, res->path);
146 		break;
147 	case CA_KEY_IMPORT:
148 		ca_key_import(ca, res->host, res->path);
149 		break;
150 	default:
151 		break;
152 	}
153 
154 	return (0);
155 }
156 
157 int
158 main(int argc, char *argv[])
159 {
160 	struct sockaddr_un	 sun;
161 	struct parse_result	*res;
162 	struct imsg		 imsg;
163 	int			 ctl_sock;
164 	int			 done = 1;
165 	int			 n;
166 	int			 ch;
167 	int			 v = 0;
168 	int			 quiet = 0;
169 	const char		*sock = IKED_SOCKET;
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_OCSP:
202 	case CA_CERT_DELETE:
203 	case CA_CERT_INSTALL:
204 	case CA_CERT_EXPORT:
205 	case CA_CERT_REVOKE:
206 	case SHOW_CA:
207 	case SHOW_CA_CERTIFICATES:
208 	case CA_KEY_CREATE:
209 	case CA_KEY_DELETE:
210 	case CA_KEY_INSTALL:
211 	case CA_KEY_IMPORT:
212 		if (pledge("stdio proc exec rpath wpath cpath fattr tty", NULL)
213 		    == -1)
214 			err(1, "pledge");
215 		ca_opt(res);
216 		break;
217 	case NONE:
218 		usage();
219 		break;
220 	default:
221 		goto connect;
222 	}
223 
224 	return (0);
225 
226  connect:
227 	/* connect to iked control socket */
228 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
229 		err(1, "socket");
230 
231 	bzero(&sun, sizeof(sun));
232 	sun.sun_family = AF_UNIX;
233 	strlcpy(sun.sun_path, sock, sizeof(sun.sun_path));
234  reconnect:
235 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
236 		/* Keep retrying if running in monitor mode */
237 		if (res->action == MONITOR &&
238 		    (errno == ENOENT || errno == ECONNREFUSED)) {
239 			usleep(100);
240 			goto reconnect;
241 		}
242 		err(1, "connect: %s", sock);
243 	}
244 
245 	if (pledge("stdio", NULL) == -1)
246 		err(1, "pledge");
247 
248 	if (res->ibuf != NULL)
249 		ibuf = res->ibuf;
250 	else
251 		if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
252 			err(1, "malloc");
253 	imsg_init(ibuf, ctl_sock);
254 
255 	/* process user request */
256 	switch (res->action) {
257 	case RESETALL:
258 		v = RESET_ALL;
259 		break;
260 	case RESETCA:
261 		v = RESET_CA;
262 		break;
263 	case RESETPOLICY:
264 		v = RESET_POLICY;
265 		break;
266 	case RESETSA:
267 		v = RESET_SA;
268 		break;
269 	case RESETUSER:
270 		v = RESET_USER;
271 		break;
272 	case LOG_VERBOSE:
273 		v = 2;
274 		break;
275 	case LOG_BRIEF:
276 	default:
277 		v = 0;
278 		break;
279 	}
280 
281 	switch (res->action) {
282 	case NONE:
283 		usage();
284 		/* NOTREACHED */
285 		break;
286 	case RESETALL:
287 	case RESETCA:
288 	case RESETPOLICY:
289 	case RESETSA:
290 	case RESETUSER:
291 		imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v));
292 		printf("reset request sent.\n");
293 		break;
294 	case LOAD:
295 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
296 		    res->path, strlen(res->path));
297 		break;
298 	case RESET_ID:
299 		imsg_compose(ibuf, IMSG_CTL_RESET_ID, 0, 0, -1,
300 		    res->id, strlen(res->id));
301 		break;
302 	case SHOW_SA:
303 		imsg_compose(ibuf, IMSG_CTL_SHOW_SA, 0, 0, -1, NULL, 0);
304 		done = 0;
305 		break;
306 	case SHOW_CERTSTORE:
307 		imsg_compose(ibuf, IMSG_CTL_SHOW_CERTSTORE, 0, 0, -1, NULL, 0);
308 		done = 0;
309 		break;
310 	case RELOAD:
311 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
312 		break;
313 	case MONITOR:
314 		imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
315 		done = 0;
316 		break;
317 	case COUPLE:
318 		imsg_compose(ibuf, IMSG_CTL_COUPLE, 0, 0, -1, NULL, 0);
319 		break;
320 	case DECOUPLE:
321 		imsg_compose(ibuf, IMSG_CTL_DECOUPLE, 0, 0, -1, NULL, 0);
322 		break;
323 	case ACTIVE:
324 		imsg_compose(ibuf, IMSG_CTL_ACTIVE, 0, 0, -1, NULL, 0);
325 		break;
326 	case PASSIVE:
327 		imsg_compose(ibuf, IMSG_CTL_PASSIVE, 0, 0, -1, NULL, 0);
328 		break;
329 	case LOG_VERBOSE:
330 	case LOG_BRIEF:
331 		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v));
332 		printf("logging request sent.\n");
333 		break;
334 	default:
335 		break;
336 	}
337 
338 	while (ibuf->w.queued)
339 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
340 			err(1, "write error");
341 
342 	while (!done) {
343 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
344 			errx(1, "imsg_read error");
345 		if (n == 0)
346 			errx(1, "pipe closed");
347 
348 		while (!done) {
349 			if ((n = imsg_get(ibuf, &imsg)) == -1)
350 				errx(1, "imsg_get error");
351 			if (n == 0)
352 				break;
353 			switch (res->action) {
354 			case MONITOR:
355 				done = monitor(&imsg);
356 				break;
357 			case SHOW_SA:
358 			case SHOW_CERTSTORE:
359 				done = show_string(&imsg);
360 				break;
361 			default:
362 				break;
363 			}
364 			imsg_free(&imsg);
365 		}
366 	}
367 	close(ctl_sock);
368 	free(ibuf);
369 
370 	return (0);
371 }
372 
373 struct imsgname *
374 monitor_lookup(uint8_t type)
375 {
376 	int i;
377 
378 	for (i = 0; imsgs[i].name != NULL; i++)
379 		if (imsgs[i].type == type)
380 			return (&imsgs[i]);
381 	return (&imsgunknown);
382 }
383 
384 int
385 monitor(struct imsg *imsg)
386 {
387 	time_t			 now;
388 	int			 done = 0;
389 	struct imsgname		*imn;
390 
391 	now = time(NULL);
392 
393 	imn = monitor_lookup(imsg->hdr.type);
394 	printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name,
395 	    imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid);
396 	printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now));
397 	if (imn->type == -1)
398 		done = 1;
399 	if (imn->func != NULL)
400 		(*imn->func)(imsg);
401 
402 	return (done);
403 }
404 
405 int
406 show_string(struct imsg *imsg)
407 {
408 	int	done = 0;
409 
410 	switch (imsg->hdr.type) {
411 	case IMSG_CTL_SHOW_SA:
412 	case IMSG_CTL_SHOW_CERTSTORE:
413 		break;
414 	default:
415 		return (done);
416 	}
417 	if (IMSG_DATA_SIZE(imsg) > 0)
418 		printf("%s", (char *)imsg->data);
419 	else
420 		done = 1;
421 
422 	return (done);
423 }
424