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