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