1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2016 by Delphix. All rights reserved. 24 * Copyright 2024 Oxide Computer Company 25 */ 26 27 /* 28 * NOTE:I'm trying to use "struct sadb_foo" instead of "sadb_foo_t" 29 * as a maximal PF_KEY portability test. 30 * 31 * Also, this is a deliberately single-threaded app, also for portability 32 * to systems without POSIX threads. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/socket.h> 38 #include <sys/sysmacros.h> 39 #include <sys/fcntl.h> 40 #include <net/pfkeyv2.h> 41 #include <arpa/inet.h> 42 #include <netinet/in.h> 43 #include <sys/uio.h> 44 45 #include <syslog.h> 46 #include <signal.h> 47 #include <unistd.h> 48 #include <limits.h> 49 #include <stdlib.h> 50 #include <stdio.h> 51 #include <stdarg.h> 52 #include <netdb.h> 53 #include <pwd.h> 54 #include <errno.h> 55 #include <libintl.h> 56 #include <locale.h> 57 #include <fcntl.h> 58 #include <strings.h> 59 #include <ctype.h> 60 #include <sys/cladm.h> 61 62 #include <ipsec_util.h> 63 64 static int keysock; 65 static int cluster_socket; 66 static uint32_t seq; 67 static pid_t mypid; 68 static boolean_t vflag = B_FALSE; /* Verbose? */ 69 static boolean_t cflag = B_FALSE; /* Check Only */ 70 static boolean_t tcpkey = B_FALSE; /* Run as tcpkey */ 71 72 const char *progname; 73 char *my_fmri = NULL; 74 FILE *debugfile = stdout; 75 static struct sockaddr_in cli_addr; 76 static boolean_t in_cluster_mode = B_FALSE; 77 78 #define MAX_GET_SIZE 1024 79 /* 80 * WARN() and ERROR() do the same thing really, with ERROR() the function 81 * that prints the error buffer needs to be called at the end of a code block 82 * This will print out all accumulated errors before bailing. The WARN() 83 * macro calls handle_errors() in such a way that it prints the message 84 * then continues. 85 * If the FATAL() macro used call handle_errors() immediately. 86 */ 87 #define ERROR(x, y, z) x = record_error(x, y, z) 88 #define ERROR1(w, x, y, z) w = record_error(w, x, y, z) 89 #define ERROR2(v, w, x, y, z) v = record_error(v, w, x, y, z) 90 #define WARN(x, y, z) ERROR(x, y, z);\ 91 handle_errors(x, NULL, B_FALSE, B_FALSE); x = NULL 92 #define WARN1(w, x, y, z) ERROR1(w, x, y, z);\ 93 handle_errors(w, NULL, B_FALSE, B_FALSE); w = NULL 94 #define WARN2(v, w, x, y, z) ERROR2(v, w, x, y, z);\ 95 handle_errors(v, NULL, B_FALSE, B_FALSE); v = NULL 96 #define FATAL(x, y, z) ERROR(x, y, z);\ 97 handle_errors(x, y, B_TRUE, B_TRUE) 98 #define FATAL1(w, x, y, z) ERROR1(w, x, y, z);\ 99 handle_errors(w, x, B_TRUE, B_TRUE) 100 101 #define QUOTE(x) #x 102 103 /* Defined as a uint64_t array for alignment purposes. */ 104 static uint64_t get_buffer[MAX_GET_SIZE]; 105 106 /* 107 * Disable default TAB completion for now (until some brave soul tackles it). 108 */ 109 /* ARGSUSED */ 110 static 111 CPL_MATCH_FN(no_match) 112 { 113 return (0); 114 } 115 116 /* 117 * Create/Grow a buffer large enough to hold error messages. If *ebuf 118 * is not NULL then it will contain a copy of the command line that 119 * triggered the error/warning, copy this into a new buffer or 120 * append new messages to the existing buffer. 121 */ 122 /*PRINTFLIKE1*/ 123 char * 124 record_error(char *ep, char *ebuf, char *fmt, ...) 125 { 126 char *err_ptr; 127 char tmp_buff[1024]; 128 va_list ap; 129 int length = 0; 130 err_ptr = ep; 131 132 va_start(ap, fmt); 133 length = vsnprintf(tmp_buff, sizeof (tmp_buff), fmt, ap); 134 va_end(ap); 135 136 /* There is a new line character */ 137 length++; 138 139 if (ep == NULL) { 140 if (ebuf != NULL) 141 length += strlen(ebuf); 142 } else { 143 length += strlen(ep); 144 } 145 146 if (err_ptr == NULL) 147 err_ptr = calloc(length, sizeof (char)); 148 else 149 err_ptr = realloc(err_ptr, length); 150 151 if (err_ptr == NULL) 152 Bail("realloc() failure"); 153 154 /* 155 * If (ep == NULL) then this is the first error to record, 156 * copy in the command line that triggered this error/warning. 157 */ 158 if (ep == NULL && ebuf != NULL) 159 (void) strlcpy(err_ptr, ebuf, length); 160 161 /* 162 * Now the actual error. 163 */ 164 (void) strlcat(err_ptr, tmp_buff, length); 165 return (err_ptr); 166 } 167 168 /* 169 * If not in interactive mode print usage message and exit. 170 */ 171 static void 172 usage(void) 173 { 174 if (!interactive) { 175 (void) fprintf(stderr, gettext("Usage:\t" 176 "%s [ -nvp ] | cmd [sa_type] [extfield value]*\n"), 177 progname); 178 (void) fprintf(stderr, 179 gettext("\t%s [ -nvp ] -f infile\n"), progname); 180 (void) fprintf(stderr, 181 gettext("\t%s [ -nvp ] -s outfile\n"), progname); 182 EXIT_FATAL(NULL); 183 } else { 184 (void) fprintf(stderr, 185 gettext("Type help or ? for usage info\n")); 186 } 187 } 188 189 190 /* 191 * Print out any errors, tidy up as required. 192 * error pointer ep will be free()'d 193 */ 194 void 195 handle_errors(char *ep, char *ebuf, boolean_t fatal, boolean_t done) 196 { 197 if (ep != NULL) { 198 if (my_fmri == NULL) { 199 /* 200 * For now suppress the errors when run from smf(7) 201 * because potentially sensitive information could 202 * end up in a publicly readable logfile. 203 */ 204 (void) fprintf(stdout, "%s\n", ep); 205 (void) fflush(stdout); 206 } 207 free(ep); 208 if (fatal) { 209 if (ebuf != NULL) { 210 free(ebuf); 211 } 212 /* reset command buffer */ 213 if (interactive) 214 longjmp(env, 1); 215 } else { 216 return; 217 } 218 } else { 219 /* 220 * No errors, if this is the last time that this function 221 * is called, free(ebuf) and reset command buffer. 222 */ 223 if (done) { 224 if (ebuf != NULL) { 225 free(ebuf); 226 } 227 /* reset command buffer */ 228 if (interactive) 229 longjmp(env, 1); 230 } 231 return; 232 } 233 EXIT_FATAL(NULL); 234 } 235 236 /* 237 * Initialize a PF_KEY base message. 238 */ 239 static void 240 msg_init(struct sadb_msg *msg, uint8_t type, uint8_t satype) 241 { 242 msg->sadb_msg_version = PF_KEY_V2; 243 msg->sadb_msg_type = type; 244 msg->sadb_msg_errno = 0; 245 msg->sadb_msg_satype = satype; 246 /* For starters... */ 247 msg->sadb_msg_len = SADB_8TO64(sizeof (*msg)); 248 msg->sadb_msg_reserved = 0; 249 msg->sadb_msg_seq = ++seq; 250 msg->sadb_msg_pid = mypid; 251 } 252 253 /* 254 * parseXXX and rparseXXX commands parse input and convert them to PF_KEY 255 * field values, or do the reverse for the purposes of saving the SA tables. 256 * (See the save_XXX functions.) 257 */ 258 259 #define CMD_NONE 0 260 #define CMD_UPDATE 2 261 #define CMD_UPDATE_PAIR 3 262 #define CMD_ADD 4 263 #define CMD_DELETE 5 264 #define CMD_DELETE_PAIR 6 265 #define CMD_GET 7 266 #define CMD_FLUSH 9 267 #define CMD_DUMP 10 268 #define CMD_MONITOR 11 269 #define CMD_PMONITOR 12 270 #define CMD_QUIT 13 271 #define CMD_SAVE 14 272 #define CMD_HELP 15 273 274 /* 275 * Parse the command. 276 */ 277 struct cmdtable { 278 char *cmd; 279 int token; 280 }; 281 282 static struct cmdtable default_cmdtable[] = { 283 /* 284 * Q: Do we want to do GETSPI? 285 * A: No, it's for automated key mgmt. only. Either that, 286 * or it isn't relevant until we support non IPsec SA types. 287 */ 288 { "update", CMD_UPDATE }, 289 { "update-pair", CMD_UPDATE_PAIR }, 290 { "add", CMD_ADD }, 291 { "delete", CMD_DELETE }, 292 { "delete-pair", CMD_DELETE_PAIR }, 293 { "get", CMD_GET }, 294 /* 295 * Q: And ACQUIRE and REGISTER and EXPIRE? 296 * A: not until we support non IPsec SA types. 297 */ 298 { "flush", CMD_FLUSH }, 299 { "dump", CMD_DUMP }, 300 { "monitor", CMD_MONITOR }, 301 { "passive_monitor", CMD_PMONITOR }, 302 { "pmonitor", CMD_PMONITOR }, 303 { "quit", CMD_QUIT }, 304 { "exit", CMD_QUIT }, 305 { "save", CMD_SAVE }, 306 { "help", CMD_HELP }, 307 { "?", CMD_HELP }, 308 { NULL, CMD_NONE } 309 }; 310 311 static struct cmdtable tcpkey_cmdtable[] = { 312 { "update", CMD_UPDATE }, 313 { "add", CMD_ADD }, 314 { "delete", CMD_DELETE }, 315 { "get", CMD_GET }, 316 { "flush", CMD_FLUSH }, 317 { "dump", CMD_DUMP }, 318 { "quit", CMD_QUIT }, 319 { "exit", CMD_QUIT }, 320 { "save", CMD_SAVE }, 321 { "help", CMD_HELP }, 322 { "?", CMD_HELP }, 323 { NULL, CMD_NONE } 324 }; 325 326 static int 327 parsecmd(char *cmdstr) 328 { 329 struct cmdtable *ct; 330 331 ct = tcpkey ? tcpkey_cmdtable : default_cmdtable; 332 333 while (ct->cmd != NULL && strcmp(ct->cmd, cmdstr) != 0) 334 ct++; 335 return (ct->token); 336 } 337 338 /* 339 * Convert a number from a command line. I picked "u_longlong_t" for the 340 * number because we need the largest number available. Also, the strto<num> 341 * calls don't deal in units of uintNN_t. 342 */ 343 static u_longlong_t 344 parsenum(char *num, boolean_t bail, char *ebuf) 345 { 346 u_longlong_t rc = 0; 347 char *end = NULL; 348 char *ep = NULL; 349 350 if (num == NULL) { 351 FATAL(ep, ebuf, gettext("Unexpected end of command line," 352 " was expecting a number.\n")); 353 /* NOTREACHED */ 354 } 355 356 errno = 0; 357 rc = strtoull(num, &end, 0); 358 if (errno != 0 || end == num || *end != '\0') { 359 if (bail) { 360 FATAL1(ep, ebuf, gettext( 361 "Expecting a number, not \"%s\"!\n"), num); 362 } else { 363 /* 364 * -1, while not optimal, is sufficiently out of range 365 * for most of this function's applications when 366 * we don't just bail. 367 */ 368 return ((u_longlong_t)-1); 369 } 370 } 371 handle_errors(ep, NULL, B_FALSE, B_FALSE); 372 return (rc); 373 } 374 375 /* 376 * Parse and reverse parse a specific SA type (AH, ESP, etc.). 377 */ 378 static struct typetable { 379 char *type; 380 int token; 381 } type_table[] = { 382 {"all", SADB_SATYPE_UNSPEC}, 383 {"ah", SADB_SATYPE_AH}, 384 {"esp", SADB_SATYPE_ESP}, 385 {"tcpsig", SADB_X_SATYPE_TCPSIG}, 386 /* PF_KEY NOTE: More to come if net/pfkeyv2.h gets updated. */ 387 {NULL, 0} /* Token value is irrelevant for this entry. */ 388 }; 389 390 static int 391 parsesatype(char *type, char *ebuf) 392 { 393 struct typetable *tt = type_table; 394 char *ep = NULL; 395 396 if (type == NULL) 397 return (SADB_SATYPE_UNSPEC); 398 399 while (tt->type != NULL && strcasecmp(tt->type, type) != 0) 400 tt++; 401 402 /* 403 * New SA types (including ones keysock maintains for user-land 404 * protocols) may be added, so parse a numeric value if possible. 405 */ 406 if (tt->type == NULL) { 407 tt->token = (int)parsenum(type, B_FALSE, ebuf); 408 if (tt->token == -1) { 409 ERROR1(ep, ebuf, gettext( 410 "Unknown SA type (%s).\n"), type); 411 tt->token = SADB_SATYPE_UNSPEC; 412 } 413 } 414 handle_errors(ep, NULL, interactive ? B_TRUE : B_FALSE, B_FALSE); 415 return (tt->token); 416 } 417 418 #define NEXTEOF 0 419 #define NEXTNONE 1 420 #define NEXTNUM 2 421 #define NEXTSTR 3 422 #define NEXTNUMSTR 4 423 #define NEXTADDR 5 424 #define NEXTHEX 6 425 #define NEXTIDENT 7 426 #define NEXTADDR4 8 427 #define NEXTADDR6 9 428 #define NEXTLABEL 10 429 430 #define TOK_EOF 0 431 #define TOK_UNKNOWN 1 432 #define TOK_SPI 2 433 #define TOK_REPLAY 3 434 #define TOK_STATE 4 435 #define TOK_AUTHALG 5 436 #define TOK_ENCRALG 6 437 #define TOK_FLAGS 7 438 #define TOK_SOFT_ALLOC 8 439 #define TOK_SOFT_BYTES 9 440 #define TOK_SOFT_ADDTIME 10 441 #define TOK_SOFT_USETIME 11 442 #define TOK_HARD_ALLOC 12 443 #define TOK_HARD_BYTES 13 444 #define TOK_HARD_ADDTIME 14 445 #define TOK_HARD_USETIME 15 446 #define TOK_CURRENT_ALLOC 16 447 #define TOK_CURRENT_BYTES 17 448 #define TOK_CURRENT_ADDTIME 18 449 #define TOK_CURRENT_USETIME 19 450 #define TOK_SRCADDR 20 451 #define TOK_DSTADDR 21 452 #define TOK_PROXYADDR 22 453 #define TOK_AUTHKEY 23 454 #define TOK_ENCRKEY 24 455 #define TOK_SRCIDTYPE 25 456 #define TOK_DSTIDTYPE 26 457 #define TOK_DPD 27 458 #define TOK_SENS_LEVEL 28 459 #define TOK_SENS_MAP 29 460 #define TOK_INTEG_LEVEL 30 461 #define TOK_INTEG_MAP 31 462 #define TOK_SRCADDR6 32 463 #define TOK_DSTADDR6 33 464 #define TOK_PROXYADDR6 34 465 #define TOK_SRCPORT 35 466 #define TOK_DSTPORT 36 467 #define TOK_PROTO 37 468 #define TOK_ENCAP 38 469 #define TOK_NATLOC 39 470 #define TOK_NATREM 40 471 #define TOK_NATLPORT 41 472 #define TOK_NATRPORT 42 473 #define TOK_IPROTO 43 474 #define TOK_IDSTADDR 44 475 #define TOK_IDSTADDR6 45 476 #define TOK_ISRCPORT 46 477 #define TOK_IDSTPORT 47 478 #define TOK_PAIR_SPI 48 479 #define TOK_FLAG_INBOUND 49 480 #define TOK_FLAG_OUTBOUND 50 481 #define TOK_REPLAY_VALUE 51 482 #define TOK_IDLE_ADDTIME 52 483 #define TOK_IDLE_USETIME 53 484 #define TOK_RESERVED 54 485 #define TOK_LABEL 55 486 #define TOK_OLABEL 56 487 #define TOK_IMPLABEL 57 488 #define TOK_AUTHSTR 58 489 490 struct toktable { 491 char *string; 492 int token; 493 int next; 494 }; 495 496 static struct toktable tokens[] = { 497 /* "String", token value, next arg is */ 498 {"spi", TOK_SPI, NEXTNUM}, 499 {"pair-spi", TOK_PAIR_SPI, NEXTNUM}, 500 {"replay", TOK_REPLAY, NEXTNUM}, 501 {"state", TOK_STATE, NEXTNUMSTR}, 502 {"auth_alg", TOK_AUTHALG, NEXTNUMSTR}, 503 {"authalg", TOK_AUTHALG, NEXTNUMSTR}, 504 {"encr_alg", TOK_ENCRALG, NEXTNUMSTR}, 505 {"encralg", TOK_ENCRALG, NEXTNUMSTR}, 506 {"flags", TOK_FLAGS, NEXTNUM}, 507 {"soft_alloc", TOK_SOFT_ALLOC, NEXTNUM}, 508 {"soft_bytes", TOK_SOFT_BYTES, NEXTNUM}, 509 {"soft_addtime", TOK_SOFT_ADDTIME, NEXTNUM}, 510 {"soft_usetime", TOK_SOFT_USETIME, NEXTNUM}, 511 {"hard_alloc", TOK_HARD_ALLOC, NEXTNUM}, 512 {"hard_bytes", TOK_HARD_BYTES, NEXTNUM}, 513 {"hard_addtime", TOK_HARD_ADDTIME, NEXTNUM}, 514 {"hard_usetime", TOK_HARD_USETIME, NEXTNUM}, 515 {"current_alloc", TOK_CURRENT_ALLOC, NEXTNUM}, 516 {"current_bytes", TOK_CURRENT_BYTES, NEXTNUM}, 517 {"current_addtime", TOK_CURRENT_ADDTIME, NEXTNUM}, 518 {"current_usetime", TOK_CURRENT_USETIME, NEXTNUM}, 519 520 {"saddr", TOK_SRCADDR, NEXTADDR}, 521 {"srcaddr", TOK_SRCADDR, NEXTADDR}, 522 {"src", TOK_SRCADDR, NEXTADDR}, 523 {"daddr", TOK_DSTADDR, NEXTADDR}, 524 {"dstaddr", TOK_DSTADDR, NEXTADDR}, 525 {"dst", TOK_DSTADDR, NEXTADDR}, 526 {"proxyaddr", TOK_PROXYADDR, NEXTADDR}, 527 {"proxy", TOK_PROXYADDR, NEXTADDR}, 528 {"innersrc", TOK_PROXYADDR, NEXTADDR}, 529 {"isrc", TOK_PROXYADDR, NEXTADDR}, 530 {"innerdst", TOK_IDSTADDR, NEXTADDR}, 531 {"idst", TOK_IDSTADDR, NEXTADDR}, 532 533 {"sport", TOK_SRCPORT, NEXTNUM}, 534 {"dport", TOK_DSTPORT, NEXTNUM}, 535 {"innersport", TOK_ISRCPORT, NEXTNUM}, 536 {"isport", TOK_ISRCPORT, NEXTNUM}, 537 {"innerdport", TOK_IDSTPORT, NEXTNUM}, 538 {"idport", TOK_IDSTPORT, NEXTNUM}, 539 {"proto", TOK_PROTO, NEXTNUM}, 540 {"ulp", TOK_PROTO, NEXTNUM}, 541 {"iproto", TOK_IPROTO, NEXTNUM}, 542 {"iulp", TOK_IPROTO, NEXTNUM}, 543 544 {"saddr6", TOK_SRCADDR6, NEXTADDR}, 545 {"srcaddr6", TOK_SRCADDR6, NEXTADDR}, 546 {"src6", TOK_SRCADDR6, NEXTADDR}, 547 {"daddr6", TOK_DSTADDR6, NEXTADDR}, 548 {"dstaddr6", TOK_DSTADDR6, NEXTADDR}, 549 {"dst6", TOK_DSTADDR6, NEXTADDR}, 550 {"proxyaddr6", TOK_PROXYADDR6, NEXTADDR}, 551 {"proxy6", TOK_PROXYADDR6, NEXTADDR}, 552 {"innersrc6", TOK_PROXYADDR6, NEXTADDR}, 553 {"isrc6", TOK_PROXYADDR6, NEXTADDR}, 554 {"innerdst6", TOK_IDSTADDR6, NEXTADDR}, 555 {"idst6", TOK_IDSTADDR6, NEXTADDR}, 556 557 {"authkey", TOK_AUTHKEY, NEXTHEX}, 558 {"authstring", TOK_AUTHSTR, NEXTNUMSTR}, 559 {"encrkey", TOK_ENCRKEY, NEXTHEX}, 560 {"srcidtype", TOK_SRCIDTYPE, NEXTIDENT}, 561 {"dstidtype", TOK_DSTIDTYPE, NEXTIDENT}, 562 {"dpd", TOK_DPD, NEXTNUM}, 563 {"sens_level", TOK_SENS_LEVEL, NEXTNUM}, 564 {"sens_map", TOK_SENS_MAP, NEXTHEX}, 565 {"integ_level", TOK_INTEG_LEVEL, NEXTNUM}, 566 {"integ_map", TOK_INTEG_MAP, NEXTHEX}, 567 {"nat_loc", TOK_NATLOC, NEXTADDR}, 568 {"nat_rem", TOK_NATREM, NEXTADDR}, 569 {"nat_lport", TOK_NATLPORT, NEXTNUM}, 570 {"nat_rport", TOK_NATRPORT, NEXTNUM}, 571 {"encap", TOK_ENCAP, NEXTNUMSTR}, 572 573 {"outbound", TOK_FLAG_OUTBOUND, 0}, 574 {"inbound", TOK_FLAG_INBOUND, 0}, 575 576 {"reserved_bits", TOK_RESERVED, NEXTNUM}, 577 {"replay_value", TOK_REPLAY_VALUE, NEXTNUM}, 578 {"idle_addtime", TOK_IDLE_ADDTIME, NEXTNUM}, 579 {"idle_usetime", TOK_IDLE_USETIME, NEXTNUM}, 580 581 {"label", TOK_LABEL, NEXTLABEL}, 582 {"outer-label", TOK_OLABEL, NEXTLABEL}, 583 {"implicit-label", TOK_IMPLABEL, NEXTLABEL}, 584 585 {NULL, TOK_UNKNOWN, NEXTEOF} 586 }; 587 588 static struct toktable tcpkey_tokens[] = { 589 /* "String", token value, next arg is */ 590 {"src", TOK_SRCADDR, NEXTADDR}, 591 {"src6", TOK_SRCADDR6, NEXTADDR}, 592 {"dst", TOK_DSTADDR, NEXTADDR}, 593 {"dst6", TOK_DSTADDR6, NEXTADDR}, 594 595 {"sport", TOK_SRCPORT, NEXTNUM}, 596 {"dport", TOK_DSTPORT, NEXTNUM}, 597 598 {"authalg", TOK_AUTHALG, NEXTNUMSTR}, 599 {"authstring", TOK_AUTHSTR, NEXTNUMSTR}, 600 601 {NULL, TOK_UNKNOWN, NEXTEOF} 602 }; 603 604 /* 605 * Q: Do I need stuff for proposals, combinations, supported algorithms, 606 * or SPI ranges? 607 * 608 * A: Probably not, but you never know. 609 * 610 * Parse out extension header type values. 611 */ 612 static int 613 parseextval(char *value, int *next) 614 { 615 struct toktable *tp; 616 617 if (value == NULL) 618 return (TOK_EOF); 619 620 tp = tcpkey ? tcpkey_tokens : tokens; 621 622 for (; tp->string != NULL; tp++) 623 if (strcmp(value, tp->string) == 0) 624 break; 625 626 /* 627 * Since the OS controls what extensions are available, we don't have 628 * to parse numeric values here. 629 */ 630 631 *next = tp->next; 632 return (tp->token); 633 } 634 635 /* 636 * Parse possible state values. 637 */ 638 static uint8_t 639 parsestate(char *state, char *ebuf) 640 { 641 struct states { 642 char *state; 643 uint8_t retval; 644 } states[] = { 645 {"larval", SADB_SASTATE_LARVAL}, 646 {"mature", SADB_SASTATE_MATURE}, 647 {"dying", SADB_SASTATE_DYING}, 648 {"dead", SADB_SASTATE_DEAD}, 649 {NULL, 0} 650 }; 651 struct states *sp; 652 char *ep = NULL; 653 654 if (state == NULL) { 655 FATAL(ep, ebuf, "Unexpected end of command line " 656 "was expecting a state.\n"); 657 } 658 659 for (sp = states; sp->state != NULL; sp++) { 660 if (strcmp(sp->state, state) == 0) 661 return (sp->retval); 662 } 663 ERROR1(ep, ebuf, gettext("Unknown state type \"%s\"\n"), state); 664 handle_errors(ep, NULL, B_FALSE, B_FALSE); 665 return (0); 666 } 667 668 /* 669 * Return the numerical algorithm identifier corresponding to the specified 670 * algorithm name. 671 */ 672 static uint8_t 673 parsealg(char *alg, int proto_num, char *ebuf) 674 { 675 u_longlong_t invalue; 676 struct ipsecalgent *algent; 677 char *ep = NULL; 678 679 if (alg == NULL) { 680 FATAL(ep, ebuf, gettext("Unexpected end of command line, " 681 "was expecting an algorithm name.\n")); 682 } 683 684 algent = getipsecalgbyname(alg, proto_num, NULL); 685 if (algent != NULL) { 686 uint8_t alg_num; 687 688 alg_num = algent->a_alg_num; 689 if (ALG_FLAG_COUNTERMODE & algent->a_alg_flags) 690 WARN1(ep, ebuf, gettext( 691 "Using manual keying with a Counter mode algorithm " 692 "such as \"%s\" may be insecure!\n"), 693 algent->a_names[0]); 694 freeipsecalgent(algent); 695 696 return (alg_num); 697 } 698 699 /* 700 * Since algorithms can be loaded during kernel run-time, check for 701 * numeric algorithm values too. PF_KEY can catch bad ones with EINVAL. 702 */ 703 invalue = parsenum(alg, B_FALSE, ebuf); 704 if (invalue != (u_longlong_t)-1 && 705 (u_longlong_t)(invalue & (u_longlong_t)0xff) == invalue) 706 return ((uint8_t)invalue); 707 708 if (proto_num == IPSEC_PROTO_ESP) { 709 ERROR1(ep, ebuf, gettext( 710 "Unknown encryption algorithm type \"%s\"\n"), alg); 711 } else { 712 ERROR1(ep, ebuf, gettext( 713 "Unknown authentication algorithm type \"%s\"\n"), alg); 714 } 715 handle_errors(ep, NULL, B_FALSE, B_FALSE); 716 return (0); 717 } 718 719 static uint8_t 720 parsetcpalg(char *alg, char *ebuf) 721 { 722 char *ep = NULL; 723 uint8_t algnum; 724 725 if (alg == NULL) { 726 FATAL(ep, ebuf, gettext("Unexpected end of command line, " 727 "was expecting an algorithm name.\n")); 728 } 729 730 algnum = gettcpsigalgbyname(alg); 731 if (algnum > 0) 732 return (algnum); 733 734 ERROR1(ep, ebuf, 735 gettext("Unknown tcpsig authentication algorithm type \"%s\"\n"), 736 alg); 737 handle_errors(ep, NULL, B_FALSE, B_FALSE); 738 return (0); 739 } 740 741 /* 742 * Parse and reverse parse out a source/destination ID type. 743 */ 744 static struct idtypes { 745 char *idtype; 746 uint8_t retval; 747 } idtypes[] = { 748 {"prefix", SADB_IDENTTYPE_PREFIX}, 749 {"fqdn", SADB_IDENTTYPE_FQDN}, 750 {"domain", SADB_IDENTTYPE_FQDN}, 751 {"domainname", SADB_IDENTTYPE_FQDN}, 752 {"user_fqdn", SADB_IDENTTYPE_USER_FQDN}, 753 {"mailbox", SADB_IDENTTYPE_USER_FQDN}, 754 {"der_dn", SADB_X_IDENTTYPE_DN}, 755 {"der_gn", SADB_X_IDENTTYPE_GN}, 756 {NULL, 0} 757 }; 758 759 static uint16_t 760 parseidtype(char *type, char *ebuf) 761 { 762 struct idtypes *idp; 763 u_longlong_t invalue; 764 char *ep = NULL; 765 766 if (type == NULL) { 767 /* Shouldn't reach here, see callers for why. */ 768 FATAL(ep, ebuf, gettext("Unexpected end of command line, " 769 "was expecting a type.\n")); 770 } 771 772 for (idp = idtypes; idp->idtype != NULL; idp++) { 773 if (strcasecmp(idp->idtype, type) == 0) 774 return (idp->retval); 775 } 776 /* 777 * Since identity types are almost arbitrary, check for numeric 778 * algorithm values too. PF_KEY can catch bad ones with EINVAL. 779 */ 780 invalue = parsenum(type, B_FALSE, ebuf); 781 if (invalue != (u_longlong_t)-1 && 782 (u_longlong_t)(invalue & (u_longlong_t)0xffff) == invalue) 783 return ((uint16_t)invalue); 784 785 786 ERROR1(ep, ebuf, gettext("Unknown identity type \"%s\"\n"), type); 787 788 handle_errors(ep, NULL, B_FALSE, B_FALSE); 789 return (0); 790 } 791 792 /* 793 * Parse an address off the command line. Return length of sockaddr, 794 * and either return a hostent pointer (caller frees). The new 795 * getipnodebyname() call does the Right Thing (TM), even with 796 * raw addresses (colon-separated IPv6 or dotted decimal IPv4). 797 */ 798 799 static struct { 800 struct hostent he; 801 char *addtl[2]; 802 } dummy; 803 static union { 804 struct in6_addr ipv6; 805 struct in_addr ipv4; 806 uint64_t aligner; 807 } addr1; 808 809 static int 810 parseaddr(char *addr, struct hostent **hpp, boolean_t v6only, char *ebuf) 811 { 812 int hp_errno; 813 struct hostent *hp = NULL; 814 char *ep = NULL; 815 816 if (addr == NULL) { 817 FATAL(ep, ebuf, gettext("Unexpected end of command line, " 818 "was expecting an address.\n")); 819 } 820 821 if (!nflag) { 822 /* 823 * Try name->address first. Assume AF_INET6, and 824 * get IPv4's, plus IPv6's if and only if IPv6 is configured. 825 * This means to add IPv6 SAs, you must have IPv6 826 * up-and-running. (AI_DEFAULT works here.) 827 */ 828 hp = getipnodebyname(addr, AF_INET6, 829 (v6only ? AI_ADDRCONFIG : (AI_DEFAULT | AI_ALL)), 830 &hp_errno); 831 } else { 832 /* 833 * Try a normal address conversion only. Use "dummy" 834 * to construct a fake hostent. Caller will know not 835 * to free this one. 836 */ 837 if (inet_pton(AF_INET6, addr, &addr1) == 1) { 838 dummy.he.h_addr_list = dummy.addtl; 839 dummy.addtl[0] = (char *)&addr1; 840 dummy.addtl[1] = NULL; 841 hp = &dummy.he; 842 dummy.he.h_addrtype = AF_INET6; 843 dummy.he.h_length = sizeof (struct in6_addr); 844 } else if (inet_pton(AF_INET, addr, &addr1) == 1) { 845 /* 846 * Remap to AF_INET6 anyway. 847 */ 848 dummy.he.h_addr_list = dummy.addtl; 849 dummy.addtl[0] = (char *)&addr1; 850 dummy.addtl[1] = NULL; 851 hp = &dummy.he; 852 dummy.he.h_addrtype = AF_INET6; 853 dummy.he.h_length = sizeof (struct in6_addr); 854 /* 855 * NOTE: If macro changes to disallow in-place 856 * conversion, rewhack this. 857 */ 858 IN6_INADDR_TO_V4MAPPED(&addr1.ipv4, &addr1.ipv6); 859 } else { 860 hp = NULL; 861 } 862 } 863 864 if (hp == NULL) 865 WARN1(ep, ebuf, gettext("Unknown address %s."), addr); 866 867 *hpp = hp; 868 /* Always return sockaddr_in6 for now. */ 869 handle_errors(ep, NULL, B_FALSE, B_FALSE); 870 return (sizeof (struct sockaddr_in6)); 871 } 872 873 /* 874 * Parse a hex character for a key. A string will take the form: 875 * xxxxxxxxx/nn 876 * where 877 * xxxxxxxxx == a string of hex characters ([0-9][a-f][A-F]) 878 * nn == an optional decimal "mask". If it is not present, it 879 * is assumed that the hex string will be rounded to the nearest 880 * byte, where odd nibbles, like 123 will become 0x0123. 881 * 882 * NOTE:Unlike the expression of IP addresses, I will not allow an 883 * excessive "mask". For example 2112/50 is very illegal. 884 * NOTE2: This key should be in canonical order. Consult your man 885 * pages per algorithm about said order. 886 */ 887 888 #define hd2num(hd) (((hd) >= '0' && (hd) <= '9') ? ((hd) - '0') : \ 889 (((hd) >= 'a' && (hd) <= 'f') ? ((hd) - 'a' + 10) : ((hd) - 'A' + 10))) 890 891 static struct sadb_key * 892 parsekey(char *input, char *ebuf, uint_t reserved_bits) 893 { 894 struct sadb_key *retval; 895 uint_t i, hexlen = 0, bits, alloclen; 896 uint8_t *key; 897 char *ep = NULL; 898 899 if (input == NULL) { 900 FATAL(ep, ebuf, gettext("Unexpected end of command line, " 901 "was expecting a key.\n")); 902 } 903 /* Allow hex values prepended with 0x convention */ 904 if ((strnlen(input, sizeof (hexlen)) > 2) && 905 (strncasecmp(input, "0x", 2) == 0)) 906 input += 2; 907 908 for (i = 0; input[i] != '\0' && input[i] != '/'; i++) 909 hexlen++; 910 911 if (input[i] == '\0') { 912 bits = 0; 913 } else { 914 /* Have /nn. */ 915 input[i] = '\0'; 916 if (sscanf((input + i + 1), "%u", &bits) != 1) { 917 FATAL1(ep, ebuf, gettext( 918 "\"%s\" is not a bit specifier.\n"), 919 (input + i + 1)); 920 } 921 /* hexlen in nibbles */ 922 if (((bits + 3) >> 2) > hexlen) { 923 ERROR2(ep, ebuf, gettext( 924 "bit length %d is too big for %s.\n"), bits, input); 925 } 926 /* 927 * Adjust hexlen down if user gave us too small of a bit 928 * count. 929 */ 930 if ((hexlen << 2) > bits + 3) { 931 WARN2(ep, ebuf, gettext( 932 "WARNING: Lower bits will be truncated " 933 "for:\n\t%s/%d.\n"), input, bits); 934 hexlen = (bits + 3) >> 2; 935 input[hexlen] = '\0'; 936 } 937 } 938 939 /* 940 * Allocate. Remember, hexlen is in nibbles. 941 */ 942 943 alloclen = sizeof (*retval) + roundup((hexlen/2 + (hexlen & 0x1)), 8); 944 retval = malloc(alloclen); 945 946 if (retval == NULL) 947 Bail("malloc(parsekey)"); 948 retval->sadb_key_len = SADB_8TO64(alloclen); 949 950 retval->sadb_key_reserved = reserved_bits; 951 952 if (bits == 0) 953 retval->sadb_key_bits = (hexlen + (hexlen & 0x1)) << 2; 954 else 955 retval->sadb_key_bits = bits; 956 957 /* 958 * Read in nibbles. Read in odd-numbered as shifted high. 959 * (e.g. 123 becomes 0x1230). 960 */ 961 962 key = (uint8_t *)(retval + 1); 963 for (i = 0; input[i] != '\0'; i += 2) { 964 boolean_t second = (input[i + 1] != '\0'); 965 966 if (!isxdigit(input[i]) || 967 (!isxdigit(input[i + 1]) && second)) { 968 ERROR1(ep, ebuf, gettext( 969 "string '%s' not a hex value.\n"), input); 970 free(retval); 971 retval = NULL; 972 break; 973 } 974 *key = (hd2num(input[i]) << 4); 975 if (second) 976 *key |= hd2num(input[i + 1]); 977 else 978 break; /* out of for loop. */ 979 key++; 980 } 981 982 /* bzero the remaining bits if we're a non-octet amount. */ 983 if (bits & 0x7) 984 *((input[i] == '\0') ? key - 1 : key) &= 985 0xff << (8 - (bits & 0x7)); 986 987 handle_errors(ep, NULL, B_FALSE, B_FALSE); 988 return (retval); 989 } 990 991 static struct sadb_key * 992 parseauthstr(char *input, char *ebuf) 993 { 994 struct sadb_key *retval; 995 size_t alloclen, keylen; 996 char *ep = NULL; 997 998 if (input == NULL) { 999 FATAL(ep, ebuf, gettext("Unexpected end of command line, " 1000 "was expecting an authentication string.\n")); 1001 } 1002 1003 keylen = strlen(input); 1004 1005 if (keylen > TCPSIG_MD5_KEY_LEN) { 1006 FATAL(ep, ebuf, gettext("Authentication string is too long, " 1007 "must be < " QUOTE(TCPSIG_MD5_KEY_LEN) " characters.\n")); 1008 } 1009 1010 alloclen = sizeof (*retval) + roundup(keylen, sizeof (uint64_t)); 1011 retval = malloc(alloclen); 1012 1013 if (retval == NULL) 1014 Bail("malloc(parseauthstr)"); 1015 retval->sadb_key_bits = SADB_8TO1(keylen); 1016 retval->sadb_key_len = SADB_8TO64(alloclen); 1017 retval->sadb_key_reserved = 0; 1018 bcopy(input, (void *)(retval + 1), keylen); 1019 1020 handle_errors(ep, NULL, B_FALSE, B_FALSE); 1021 return (retval); 1022 } 1023 1024 #include <tsol/label.h> 1025 1026 #define PARSELABEL_BAD_TOKEN ((struct sadb_sens *)-1) 1027 1028 static struct sadb_sens * 1029 parselabel(int token, char *label) 1030 { 1031 bslabel_t *sl = NULL; 1032 int err, len; 1033 sadb_sens_t *sens; 1034 int doi = 1; /* XXX XXX DEFAULT_DOI XXX XXX */ 1035 1036 err = str_to_label(label, &sl, MAC_LABEL, L_DEFAULT, NULL); 1037 if (err < 0) 1038 return (NULL); 1039 1040 len = ipsec_convert_sl_to_sens(doi, sl, NULL); 1041 1042 sens = malloc(len); 1043 if (sens == NULL) { 1044 Bail("malloc parsed label"); 1045 /* Should exit before reaching here... */ 1046 return (NULL); 1047 } 1048 1049 (void) ipsec_convert_sl_to_sens(doi, sl, sens); 1050 1051 switch (token) { 1052 case TOK_LABEL: 1053 break; 1054 1055 case TOK_OLABEL: 1056 sens->sadb_sens_exttype = SADB_X_EXT_OUTER_SENS; 1057 break; 1058 1059 case TOK_IMPLABEL: 1060 sens->sadb_sens_exttype = SADB_X_EXT_OUTER_SENS; 1061 sens->sadb_x_sens_flags = SADB_X_SENS_IMPLICIT; 1062 break; 1063 1064 default: 1065 free(sens); 1066 /* 1067 * Return a different return code for a bad label, but really, 1068 * this would be a caller error. 1069 */ 1070 return (PARSELABEL_BAD_TOKEN); 1071 } 1072 1073 return (sens); 1074 } 1075 1076 /* 1077 * Write a message to the PF_KEY socket. If verbose, print the message 1078 * heading into the kernel. 1079 */ 1080 static int 1081 key_write(int fd, void *msg, size_t len) 1082 { 1083 if (vflag) { 1084 (void) printf( 1085 gettext("VERBOSE ON: Message to kernel looks like:\n")); 1086 (void) printf("==========================================\n"); 1087 print_samsg(stdout, msg, B_FALSE, vflag, nflag); 1088 (void) printf("==========================================\n"); 1089 } 1090 1091 return (write(fd, msg, len)); 1092 } 1093 1094 /* 1095 * SIGALRM handler for time_critical_enter. 1096 */ 1097 static void 1098 time_critical_catch(int signal) 1099 { 1100 if (signal == SIGALRM) { 1101 errx(1, gettext("Reply message from PF_KEY timed out.")); 1102 } else { 1103 errx(1, gettext("Caught signal %d while trying to receive" 1104 "PF_KEY reply message"), signal); 1105 } 1106 /* errx() calls exit. */ 1107 } 1108 1109 #define TIME_CRITICAL_TIME 10 /* In seconds */ 1110 1111 /* 1112 * Enter a "time critical" section where key is waiting for a return message. 1113 */ 1114 static void 1115 time_critical_enter(void) 1116 { 1117 (void) signal(SIGALRM, time_critical_catch); 1118 (void) alarm(TIME_CRITICAL_TIME); 1119 } 1120 1121 /* 1122 * Exit the "time critical" section after getting an appropriate return 1123 * message. 1124 */ 1125 static void 1126 time_critical_exit(void) 1127 { 1128 (void) alarm(0); 1129 (void) signal(SIGALRM, SIG_DFL); 1130 } 1131 1132 /* 1133 * Construct a PF_KEY FLUSH message for the SA type specified. 1134 */ 1135 static void 1136 doflush(int satype) 1137 { 1138 struct sadb_msg msg; 1139 int rc; 1140 1141 msg_init(&msg, SADB_FLUSH, (uint8_t)satype); 1142 rc = key_write(keysock, &msg, sizeof (msg)); 1143 if (rc == -1) 1144 Bail("write() to PF_KEY socket failed (in doflush)"); 1145 1146 time_critical_enter(); 1147 do { 1148 rc = read(keysock, &msg, sizeof (msg)); 1149 if (rc == -1) 1150 Bail("read (in doflush)"); 1151 } while (msg.sadb_msg_seq != seq || msg.sadb_msg_pid != mypid); 1152 time_critical_exit(); 1153 1154 /* 1155 * I should _never_ hit the following unless: 1156 * 1157 * 1. There is a kernel bug. 1158 * 2. There is another process filling in its pid with mine, and 1159 * issuing a different message that would cause a different result. 1160 */ 1161 if (msg.sadb_msg_type != SADB_FLUSH || 1162 msg.sadb_msg_satype != (uint8_t)satype) { 1163 syslog((LOG_NOTICE|LOG_AUTH), 1164 gettext("doflush: Return message not of type SADB_FLUSH!")); 1165 Bail("doflush: Return message not of type SADB_FLUSH!"); 1166 } 1167 1168 if (msg.sadb_msg_errno != 0) { 1169 errno = msg.sadb_msg_errno; 1170 if (errno == EINVAL) { 1171 print_diagnostic(stderr, msg.sadb_x_msg_diagnostic); 1172 warnx(gettext("Cannot flush SA type %d."), satype); 1173 } 1174 Bail("return message (in doflush)"); 1175 } 1176 } 1177 1178 /* 1179 * save_XXX functions are used when "saving" the SA tables to either a 1180 * file or standard output. They use the dump_XXX functions where needed, 1181 * but mostly they use the rparseXXX functions. 1182 */ 1183 1184 /* 1185 * Because "save" and "dump" both use the SADB_DUMP message, fold both 1186 * into the same function. 1187 */ 1188 static void 1189 dodump(int satype, FILE *ofile) 1190 { 1191 struct sadb_msg *msg = (struct sadb_msg *)get_buffer; 1192 int rc; 1193 1194 if (ofile != NULL) { 1195 (void) fprintf(ofile, 1196 gettext("# This key file was generated by the")); 1197 (void) fprintf(ofile, 1198 gettext(" %s(8) command's 'save' feature.\n\n"), 1199 progname); 1200 } 1201 msg_init(msg, SADB_DUMP, (uint8_t)satype); 1202 rc = key_write(keysock, msg, sizeof (*msg)); 1203 if (rc == -1) 1204 Bail("write to PF_KEY socket failed (in dodump)"); 1205 1206 do { 1207 /* 1208 * For DUMP, do only the read as a time critical section. 1209 */ 1210 time_critical_enter(); 1211 rc = read(keysock, get_buffer, sizeof (get_buffer)); 1212 time_critical_exit(); 1213 if (rc == -1) 1214 Bail("read (in dodump)"); 1215 if (msg->sadb_msg_pid == mypid && 1216 msg->sadb_msg_type == SADB_DUMP && 1217 msg->sadb_msg_seq != 0 && 1218 msg->sadb_msg_errno == 0) { 1219 if (ofile == NULL) { 1220 print_samsg(stdout, get_buffer, B_FALSE, vflag, 1221 nflag); 1222 (void) putchar('\n'); 1223 } else { 1224 save_assoc(get_buffer, ofile); 1225 } 1226 } 1227 } while (msg->sadb_msg_pid != mypid || 1228 (msg->sadb_msg_errno == 0 && msg->sadb_msg_seq != 0)); 1229 1230 if (ofile != NULL && ofile != stdout) 1231 (void) fclose(ofile); 1232 1233 if (msg->sadb_msg_errno == 0) { 1234 if (ofile == NULL) 1235 (void) printf( 1236 gettext("Dump succeeded for SA type %d.\n"), 1237 satype); 1238 } else { 1239 print_diagnostic(stderr, msg->sadb_x_msg_diagnostic); 1240 errno = msg->sadb_msg_errno; 1241 Bail("Dump failed"); 1242 } 1243 } 1244 1245 #define SCOPE_UNSPEC 0 1246 #define SCOPE_LINKLOCAL 1 1247 #define SCOPE_SITELOCAL 2 1248 #define SCOPE_GLOBAL 3 1249 #define SCOPE_V4COMPAT 4 1250 #define SCOPE_LOOPBACK 5 /* Pedantic, yes, but necessary. */ 1251 1252 static int 1253 ipv6_addr_scope(struct in6_addr *addr) 1254 { 1255 /* Don't return anything regarding multicast for now... */ 1256 1257 if (IN6_IS_ADDR_UNSPECIFIED(addr)) 1258 return (SCOPE_UNSPEC); 1259 1260 if (IN6_IS_ADDR_LINKLOCAL(addr)) 1261 return (SCOPE_LINKLOCAL); 1262 1263 if (IN6_IS_ADDR_SITELOCAL(addr)) 1264 return (SCOPE_SITELOCAL); 1265 1266 if (IN6_IS_ADDR_V4COMPAT(addr)) 1267 return (SCOPE_V4COMPAT); 1268 1269 if (IN6_IS_ADDR_LOOPBACK(addr)) 1270 return (SCOPE_LOOPBACK); 1271 1272 /* For now, return global by default. */ 1273 return (SCOPE_GLOBAL); 1274 } 1275 1276 /* 1277 * doaddresses(): 1278 * 1279 * Used by doaddup() and dodelget() to create new SAs based on the 1280 * provided source and destination addresses hostent. 1281 * 1282 * sadb_msg_type: expected PF_KEY reply message type 1283 * sadb_msg_satype: expected PF_KEY reply satype 1284 * cmd: user command 1285 * srchp: hostent for the source address(es) 1286 * dsthp: hostent for the destination address(es) 1287 * src: points to the SADB source address extension 1288 * dst: points to the SADB destination address extension 1289 * unspec_src: indicates an unspecified source address. 1290 * buffer: pointer to the SADB buffer to use with PF_KEY 1291 * buffer_size: size of buffer 1292 * spi: spi for this message (set by caller) 1293 * srcport: source port if specified 1294 * dstport: destination port if specified 1295 * proto: IP protocol number if specified 1296 * iproto: Inner (tunnel mode) IP protocol number if specified 1297 * NATT note: we are going to assume a semi-sane world where NAT 1298 * boxen don't explode to multiple addresses. 1299 */ 1300 static void 1301 doaddresses(uint8_t sadb_msg_type, uint8_t sadb_msg_satype, int cmd, 1302 struct hostent *srchp, struct hostent *dsthp, 1303 struct sadb_address *src, struct sadb_address *dst, 1304 boolean_t unspec_src, uint64_t *buffer, int buffer_size, uint32_t spi, 1305 char *ebuf) 1306 { 1307 boolean_t last_dst; 1308 struct sockaddr_in6 *sin6; 1309 struct sadb_msg *msgp; 1310 int i, rc; 1311 char **walker; /* For the SRC and PROXY walking functions. */ 1312 char *first_match; 1313 uint64_t savebuf[MAX_GET_SIZE]; 1314 uint16_t srcport = 0, dstport = 0; 1315 char *ep = NULL; 1316 1317 /* 1318 * Okay, now we have "src", "dst", and maybe "proxy" reassigned 1319 * to point into the buffer to be written to PF_KEY, we can do 1320 * potentially several writes based on destination address. 1321 * 1322 * First, obtain port numbers from passed-in extensions. 1323 */ 1324 1325 if (src != NULL) { 1326 sin6 = (struct sockaddr_in6 *)(src + 1); 1327 srcport = ntohs(sin6->sin6_port); 1328 } 1329 if (dst != NULL) { 1330 sin6 = (struct sockaddr_in6 *)(dst + 1); 1331 dstport = ntohs(sin6->sin6_port); 1332 } 1333 1334 /* 1335 * The rules for ADD, GET, and UPDATE: (NOTE: This assumes IPsec. 1336 * If other consumers of PF_KEY happen, this will have to be 1337 * rewhacked.): 1338 * 1339 * Do a message for every possible DST address. 1340 * 1341 * If a source or proxy address explodes, keep unspecified 1342 * (and mention unspecified). 1343 * 1344 * DELETE is different, because you can leave either "src" or "dst" 1345 * blank! You need to explode if one of them is full, and not assume 1346 * that the other is set. 1347 */ 1348 1349 if (dsthp == NULL) { 1350 /* 1351 * No destination address specified. 1352 * With extended diagnostics, we don't have to bail the 1353 * non-DELETE cases here. The EINVAL diagnostics will be 1354 * enough to inform the user(s) what happened. 1355 */ 1356 i = 0; 1357 do { 1358 if (srchp == &dummy.he) { 1359 /* Just to be sure... */ 1360 srchp->h_addr_list[1] = NULL; 1361 } else if (srchp != NULL) { 1362 /* Degenerate case, h_addr_list[0] == NULL. */ 1363 if (srchp->h_addr_list[i] == NULL) 1364 Bail("Empty source address list"); 1365 1366 /* 1367 * Fill in the src sockaddr. 1368 */ 1369 sin6 = (struct sockaddr_in6 *)(src + 1); 1370 bzero(sin6, sizeof (*sin6)); 1371 bcopy(srchp->h_addr_list[i], &sin6->sin6_addr, 1372 sizeof (struct in6_addr)); 1373 sin6->sin6_family = AF_INET6; 1374 sin6->sin6_port = htons(srcport); 1375 } 1376 1377 /* Save off a copy for later writing... */ 1378 msgp = (struct sadb_msg *)buffer; 1379 bcopy(buffer, savebuf, SADB_64TO8(msgp->sadb_msg_len)); 1380 1381 rc = key_write(keysock, buffer, 1382 SADB_64TO8(msgp->sadb_msg_len)); 1383 if (rc == -1) 1384 Bail("write() to PF_KEY socket " 1385 "(in doaddresses)"); 1386 /* 1387 * Sends the message to the Solaris Cluster daemon 1388 */ 1389 1390 if (in_cluster_mode) { 1391 (void) sendto(cluster_socket, buffer, 1392 SADB_64TO8(msgp->sadb_msg_len), 0, 1393 (struct sockaddr *)&cli_addr, 1394 sizeof (cli_addr)); 1395 } 1396 1397 time_critical_enter(); 1398 do { 1399 rc = read(keysock, buffer, buffer_size); 1400 if (rc == -1) 1401 Bail("read (in doaddresses)"); 1402 } while (msgp->sadb_msg_seq != seq || 1403 msgp->sadb_msg_pid != mypid); 1404 time_critical_exit(); 1405 1406 if (msgp->sadb_msg_type != sadb_msg_type || 1407 msgp->sadb_msg_satype != sadb_msg_satype) { 1408 syslog((LOG_NOTICE|LOG_AUTH), gettext( 1409 "doaddresses: Unexpected returned message " 1410 "(%d exp %d)\n"), msgp->sadb_msg_type, 1411 sadb_msg_type); 1412 Bail("doaddresses: Unexpected returned " 1413 "message"); 1414 } 1415 1416 errno = msgp->sadb_msg_errno; 1417 if (errno != 0) { 1418 if (errno == EINVAL) { 1419 WARN(ep, ebuf, gettext( 1420 "One of the entered " 1421 "values is incorrect.")); 1422 print_diagnostic(stderr, 1423 msgp->sadb_x_msg_diagnostic); 1424 } else { 1425 Bail("return message (in doaddresses)"); 1426 } 1427 } 1428 1429 /* ...and then restore the saved buffer. */ 1430 msgp = (struct sadb_msg *)savebuf; 1431 bcopy(savebuf, buffer, SADB_64TO8(msgp->sadb_msg_len)); 1432 } while (srchp != NULL && srchp->h_addr_list[++i] != NULL); 1433 return; 1434 } 1435 1436 /* 1437 * Go through the list of all dst addresses, trying to find matching 1438 * src address for each. If the first address is == dummy.he we will go 1439 * through the loop just once. If any other hp is == dummy.he, then we 1440 * don't have to apply any silly rules. 1441 */ 1442 for (i = 0; dsthp->h_addr_list[i] != NULL; i++) { 1443 if (dsthp == &dummy.he) { 1444 /* Just to be sure... */ 1445 dsthp->h_addr_list[1] = NULL; 1446 } else { 1447 /* 1448 * Fill in the dst sockaddr. 1449 */ 1450 sin6 = (struct sockaddr_in6 *)(dst + 1); 1451 bzero(sin6, sizeof (*sin6)); 1452 bcopy(dsthp->h_addr_list[i], &sin6->sin6_addr, 1453 sizeof (struct in6_addr)); 1454 sin6->sin6_family = AF_INET6; 1455 sin6->sin6_port = htons(dstport); 1456 } 1457 1458 last_dst = (dsthp->h_addr_list[i + 1] == NULL); 1459 1460 /* 1461 * Try and assign src, if there's any ambiguity. 1462 */ 1463 if (!unspec_src && srchp != &dummy.he) { 1464 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1465 /* 1466 * IPv4 address. Find an IPv4 address, then 1467 * keep looking for a second one. If a second 1468 * exists, print a message, and fill in the 1469 * unspecified address. 1470 */ 1471 first_match = NULL; 1472 1473 for (walker = srchp->h_addr_list; 1474 *walker != NULL; walker++) { 1475 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1476 if (IN6_IS_ADDR_V4MAPPED( 1477 (struct in6_addr *)*walker)) { 1478 if (first_match != NULL) 1479 break; 1480 else 1481 first_match = *walker; 1482 } 1483 } 1484 sin6 = (struct sockaddr_in6 *)(src + 1); 1485 bzero(sin6, sizeof (*sin6)); 1486 1487 if (first_match == NULL) { 1488 /* 1489 * No IPv4 hits. Is this the last 1490 * destination address in the list ? 1491 */ 1492 ERROR1(ep, ebuf, gettext( 1493 "No IPv4 source address " 1494 "for name %s.\n"), srchp->h_name); 1495 if (last_dst) { 1496 FATAL(ep, ebuf, gettext( 1497 "No match for destination " 1498 "IP address.\n")); 1499 } else { 1500 /* Continue, but do I print? */ 1501 continue; /* for loop */ 1502 } 1503 1504 /* I should never reach here. */ 1505 } 1506 1507 sin6->sin6_family = AF_INET6; 1508 sin6->sin6_port = htons(srcport); 1509 if (*walker != NULL) { 1510 /* 1511 * Early loop exit. It must've been 1512 * multiple hits... 1513 * 1514 * Issue a null-source warning? 1515 */ 1516 WARN1(ep, ebuf, gettext( 1517 "Multiple IPv4 source addresses " 1518 "for %s, using unspecified source " 1519 "instead."), srchp->h_name); 1520 } else { 1521 /* 1522 * If I reach here w/o hitting the 1523 * previous if statements, I have a 1524 * single source address for this 1525 * destination. 1526 */ 1527 bcopy(first_match, &sin6->sin6_addr, 1528 sizeof (struct in6_addr)); 1529 } 1530 } else { 1531 /* 1532 * IPv6 address. Find an IPv6 address. 1533 * Unlike IPv4 addresses, things can get a 1534 * little more sticky with scopes, etc. 1535 */ 1536 int dst_scope, src_scope; 1537 1538 dst_scope = ipv6_addr_scope(&sin6->sin6_addr); 1539 1540 first_match = NULL; 1541 for (walker = srchp->h_addr_list; 1542 *walker != NULL; walker++) { 1543 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1544 if (!IN6_IS_ADDR_V4MAPPED( 1545 (struct in6_addr *)*walker)) { 1546 /* 1547 * Set first-match, etc. 1548 * Take into account scopes, 1549 * and other IPv6 thingies. 1550 */ 1551 src_scope = ipv6_addr_scope( 1552 /* LINTED E_BAD_PTR_CAST */ 1553 (struct in6_addr *)*walker); 1554 if (src_scope == SCOPE_UNSPEC || 1555 src_scope == dst_scope) { 1556 if (first_match != 1557 NULL) 1558 break; 1559 else 1560 first_match = 1561 *walker; 1562 } 1563 } 1564 } 1565 1566 sin6 = (struct sockaddr_in6 *)(src + 1); 1567 bzero(sin6, sizeof (*sin6)); 1568 sin6->sin6_port = htons(srcport); 1569 if (first_match == NULL) { 1570 /* 1571 * No IPv6 hits. Is this the last 1572 * destination address in the list ? 1573 */ 1574 ERROR1(ep, ebuf, gettext( 1575 "No IPv6 source address of " 1576 "matching scope for name %s.\n"), 1577 srchp->h_name); 1578 if (last_dst) { 1579 FATAL(ep, ebuf, gettext( 1580 "No match for IPV6 " 1581 "destination " 1582 "address.\n")); 1583 } else { 1584 /* Continue, but do I print? */ 1585 continue; /* for loop */ 1586 } 1587 1588 /* I should never reach here. */ 1589 } 1590 sin6->sin6_family = AF_INET6; 1591 if (*walker != NULL) { 1592 /* 1593 * Early loop exit. Issue a 1594 * null-source warning? 1595 */ 1596 WARN1(ep, ebuf, gettext( 1597 "Multiple IPv6 source addresses " 1598 "for %s of the same scope, using " 1599 "unspecified source instead.\n"), 1600 srchp->h_name); 1601 } else { 1602 /* 1603 * If I reach here w/o hitting the 1604 * previous if statements, I have a 1605 * single source address for this 1606 * destination. 1607 */ 1608 bcopy(first_match, &sin6->sin6_addr, 1609 sizeof (struct in6_addr)); 1610 } 1611 } 1612 } 1613 1614 /* 1615 * If there are errors at this point there is no 1616 * point sending anything to PF_KEY. 1617 */ 1618 handle_errors(ep, ebuf, B_TRUE, B_FALSE); 1619 1620 /* Save off a copy for later writing... */ 1621 msgp = (struct sadb_msg *)buffer; 1622 bcopy(buffer, savebuf, SADB_64TO8(msgp->sadb_msg_len)); 1623 1624 rc = key_write(keysock, buffer, SADB_64TO8(msgp->sadb_msg_len)); 1625 if (rc == -1) 1626 Bail("write() to PF_KEY socket (in doaddresses)"); 1627 1628 if (in_cluster_mode) { 1629 (void) sendto(cluster_socket, buffer, 1630 SADB_64TO8(msgp->sadb_msg_len), 0, 1631 (struct sockaddr *)&cli_addr, 1632 sizeof (cli_addr)); 1633 } 1634 /* Blank the key for paranoia's sake. */ 1635 explicit_bzero(buffer, buffer_size); 1636 time_critical_enter(); 1637 do { 1638 rc = read(keysock, buffer, buffer_size); 1639 if (rc == -1) 1640 Bail("read (in doaddresses)"); 1641 } while (msgp->sadb_msg_seq != seq || 1642 msgp->sadb_msg_pid != mypid); 1643 time_critical_exit(); 1644 1645 /* 1646 * I should _never_ hit the following unless: 1647 * 1648 * 1. There is a kernel bug. 1649 * 2. Another process is mistakenly using my pid in a PF_KEY 1650 * message. 1651 */ 1652 if (msgp->sadb_msg_type != sadb_msg_type || 1653 msgp->sadb_msg_satype != sadb_msg_satype) { 1654 syslog((LOG_NOTICE|LOG_AUTH), gettext( 1655 "doaddresses: Unexpected returned message " 1656 "(%d exp %d)\n"), msgp->sadb_msg_type, 1657 sadb_msg_type); 1658 Bail("doaddresses: Unexpected returned message"); 1659 } 1660 1661 if (msgp->sadb_msg_errno != 0) { 1662 char addrprint[INET6_ADDRSTRLEN]; 1663 int on_errno = 0; 1664 char *on_errno_msg; 1665 1666 /* 1667 * Print different error messages depending 1668 * on the SADB message type being processed. 1669 * If we get a ESRCH error for a GET/DELETE 1670 * messages, we report that the SA does not 1671 * exist. If we get a EEXIST error for a 1672 * ADD/UPDATE message, we report that the 1673 * SA already exists. 1674 */ 1675 if (sadb_msg_type == SADB_GET || 1676 sadb_msg_type == SADB_DELETE) { 1677 on_errno = ESRCH; 1678 on_errno_msg = "does not exist"; 1679 } else if (sadb_msg_type == SADB_ADD || 1680 sadb_msg_type == SADB_UPDATE) { 1681 on_errno = EEXIST; 1682 on_errno_msg = "already exists"; 1683 } 1684 1685 errno = msgp->sadb_msg_errno; 1686 if (errno == on_errno) { 1687 ERROR2(ep, ebuf, gettext( 1688 "Association (type = %s) " 1689 "with spi 0x%x and addr\n"), 1690 rparsesatype(msgp->sadb_msg_satype), 1691 ntohl(spi)); 1692 ERROR2(ep, ebuf, "%s %s.\n", 1693 do_inet_ntop(dsthp->h_addr_list[i], 1694 addrprint, sizeof (addrprint)), 1695 on_errno_msg); 1696 msgp = (struct sadb_msg *)savebuf; 1697 bcopy(savebuf, buffer, 1698 SADB_64TO8(msgp->sadb_msg_len)); 1699 continue; 1700 } else { 1701 if (errno == EINVAL || errno == ESRCH) { 1702 ERROR2(ep, ebuf, gettext( 1703 "PF_KEY Diagnostic code %u: %s.\n"), 1704 msgp->sadb_x_msg_diagnostic, 1705 keysock_diag( 1706 msgp->sadb_x_msg_diagnostic)); 1707 } else { 1708 Bail("return message (in doaddresses)"); 1709 } 1710 } 1711 } 1712 1713 if (cmd == CMD_GET) { 1714 if (msgp->sadb_msg_len > MAX_GET_SIZE) { 1715 WARN1(ep, ebuf, gettext("WARNING: " 1716 "SA information bigger than %d bytes.\n"), 1717 SADB_64TO8(MAX_GET_SIZE)); 1718 } 1719 print_samsg(stdout, buffer, B_FALSE, vflag, nflag); 1720 } 1721 1722 handle_errors(ep, ebuf, B_TRUE, B_FALSE); 1723 1724 /* ...and then restore the saved buffer. */ 1725 msgp = (struct sadb_msg *)savebuf; 1726 bcopy(savebuf, buffer, SADB_64TO8(msgp->sadb_msg_len)); 1727 lines_added++; 1728 } 1729 1730 /* Degenerate case, h_addr_list[0] == NULL. */ 1731 if (i == 0) 1732 Bail("Empty destination address list"); 1733 1734 /* 1735 * free(ebuf) even if there are no errors. 1736 * handle_errors() won't return here. 1737 */ 1738 handle_errors(ep, ebuf, B_TRUE, B_TRUE); 1739 } 1740 1741 /* 1742 * Perform an add or an update. ADD and UPDATE are similar in the extensions 1743 * they need. 1744 */ 1745 static void 1746 doaddup(int cmd, int satype, char *argv[], char *ebuf) 1747 { 1748 uint64_t *buffer, *nexthdr; 1749 struct sadb_msg msg; 1750 struct sadb_sa *assoc = NULL; 1751 struct sadb_x_pair *sadb_pair = NULL; 1752 struct sadb_address *src = NULL, *dst = NULL; 1753 struct sadb_address *isrc = NULL, *idst = NULL; 1754 struct sadb_address *natt_local = NULL, *natt_remote = NULL; 1755 struct sadb_key *encrypt = NULL, *auth = NULL; 1756 struct sadb_ident *srcid = NULL, *dstid = NULL; 1757 struct sadb_lifetime *hard = NULL, *soft = NULL; /* Current? */ 1758 struct sadb_lifetime *idle = NULL; 1759 struct sadb_x_replay_ctr *replay_ctr = NULL; 1760 struct sadb_sens *label = NULL, *olabel = NULL; 1761 struct sockaddr_in6 *sin6; 1762 /* MLS TODO: Need sensitivity eventually. */ 1763 int next, token, sa_len, alloclen, totallen = sizeof (msg), prefix; 1764 uint32_t spi = 0; 1765 uint_t reserved_bits = 0; 1766 uint8_t sadb_msg_type; 1767 char *thiscmd, *pstr; 1768 boolean_t readstate = B_FALSE, unspec_src = B_FALSE; 1769 boolean_t alloc_inner = B_FALSE, use_natt = B_FALSE; 1770 struct hostent *srchp = NULL, *dsthp = NULL, *isrchp = NULL, 1771 *idsthp = NULL; 1772 struct hostent *natt_lhp = NULL, *natt_rhp = NULL; 1773 uint16_t srcport = 0, dstport = 0, natt_lport = 0, natt_rport = 0, 1774 isrcport = 0, idstport = 0; 1775 uint8_t proto = 0, iproto = 0; 1776 char *ep = NULL; 1777 1778 switch (cmd) { 1779 case CMD_ADD: 1780 thiscmd = "add"; 1781 sadb_msg_type = SADB_ADD; 1782 break; 1783 case CMD_UPDATE: 1784 thiscmd = "update"; 1785 sadb_msg_type = SADB_UPDATE; 1786 break; 1787 case CMD_UPDATE_PAIR: 1788 thiscmd = "update-pair"; 1789 sadb_msg_type = SADB_X_UPDATEPAIR; 1790 break; 1791 } 1792 1793 msg_init(&msg, sadb_msg_type, (uint8_t)satype); 1794 /* Assume last element in argv is set to NULL. */ 1795 do { 1796 token = parseextval(*argv, &next); 1797 argv++; 1798 switch (token) { 1799 case TOK_EOF: 1800 /* Do nothing, I'm done. */ 1801 break; 1802 case TOK_UNKNOWN: 1803 ERROR1(ep, ebuf, gettext( 1804 "Unknown extension field \"%s\" \n"), *(argv - 1)); 1805 break; 1806 case TOK_SPI: 1807 case TOK_PAIR_SPI: 1808 case TOK_REPLAY: 1809 case TOK_STATE: 1810 case TOK_AUTHALG: 1811 case TOK_ENCRALG: 1812 case TOK_ENCAP: 1813 /* 1814 * May want to place this chunk of code in a function. 1815 * 1816 * This code checks for duplicate entries on a command 1817 * line. 1818 */ 1819 1820 /* Allocate the SADB_EXT_SA extension. */ 1821 if (assoc == NULL) { 1822 assoc = malloc(sizeof (*assoc)); 1823 if (assoc == NULL) 1824 Bail("malloc(assoc)"); 1825 bzero(assoc, sizeof (*assoc)); 1826 assoc->sadb_sa_exttype = SADB_EXT_SA; 1827 assoc->sadb_sa_len = 1828 SADB_8TO64(sizeof (*assoc)); 1829 totallen += sizeof (*assoc); 1830 } 1831 switch (token) { 1832 case TOK_SPI: 1833 /* 1834 * If they type in "spi 0" then they 1835 * can type in another SPI. 1836 */ 1837 if (assoc->sadb_sa_spi != 0) { 1838 ERROR(ep, ebuf, gettext( 1839 "Can only specify " 1840 "single SPI value.\n")); 1841 break; 1842 } 1843 /* Must convert SPI to network order! */ 1844 assoc->sadb_sa_spi = 1845 htonl((uint32_t)parsenum(*argv, B_TRUE, 1846 ebuf)); 1847 if (assoc->sadb_sa_spi == 0) { 1848 ERROR(ep, ebuf, gettext( 1849 "Invalid SPI value \"0\" .\n")); 1850 } 1851 break; 1852 case TOK_PAIR_SPI: 1853 if (cmd == CMD_UPDATE_PAIR) { 1854 ERROR(ep, ebuf, gettext( 1855 "pair-spi can not be used with the " 1856 "\"update-pair\" command.\n")); 1857 } 1858 if (sadb_pair == NULL) { 1859 sadb_pair = malloc(sizeof (*sadb_pair)); 1860 if (assoc == NULL) 1861 Bail("malloc(assoc)"); 1862 bzero(sadb_pair, sizeof (*sadb_pair)); 1863 totallen += sizeof (*sadb_pair); 1864 } 1865 if (sadb_pair->sadb_x_pair_spi != 0) { 1866 ERROR(ep, ebuf, gettext( 1867 "Can only specify " 1868 "single pair SPI value.\n")); 1869 break; 1870 } 1871 /* Must convert SPI to network order! */ 1872 sadb_pair->sadb_x_pair_len = 1873 SADB_8TO64(sizeof (*sadb_pair)); 1874 sadb_pair->sadb_x_pair_exttype = 1875 SADB_X_EXT_PAIR; 1876 sadb_pair->sadb_x_pair_spi = 1877 htonl((uint32_t)parsenum(*argv, B_TRUE, 1878 ebuf)); 1879 if (sadb_pair->sadb_x_pair_spi == 0) { 1880 ERROR(ep, ebuf, gettext( 1881 "Invalid SPI value \"0\" .\n")); 1882 } 1883 assoc->sadb_sa_flags |= 1884 SADB_X_SAFLAGS_PAIRED; 1885 break; 1886 case TOK_REPLAY: 1887 /* 1888 * That same cretin can do the same with 1889 * replay. 1890 */ 1891 if (assoc->sadb_sa_replay != 0) { 1892 ERROR(ep, ebuf, gettext( 1893 "Can only specify " 1894 "single replay window size.\n")); 1895 break; 1896 } 1897 assoc->sadb_sa_replay = 1898 (uint8_t)parsenum(*argv, B_TRUE, ebuf); 1899 if (assoc->sadb_sa_replay != 0) { 1900 WARN(ep, ebuf, gettext( 1901 "WARNING: Replay with manual" 1902 " keying considered harmful.\n")); 1903 } 1904 break; 1905 case TOK_STATE: 1906 /* 1907 * 0 is an actual state value, LARVAL. This 1908 * means that one can type in the larval state 1909 * and then type in another state on the same 1910 * command line. 1911 */ 1912 if (assoc->sadb_sa_state != 0) { 1913 ERROR(ep, ebuf, gettext( 1914 "Can only specify " 1915 "single SA state.\n")); 1916 break; 1917 } 1918 assoc->sadb_sa_state = parsestate(*argv, 1919 ebuf); 1920 readstate = B_TRUE; 1921 break; 1922 case TOK_AUTHALG: 1923 if (assoc->sadb_sa_auth != 0) { 1924 ERROR(ep, ebuf, gettext( 1925 "Can only specify " 1926 "single auth algorithm.\n")); 1927 break; 1928 } 1929 if (satype == SADB_X_SATYPE_TCPSIG) { 1930 assoc->sadb_sa_auth = 1931 parsetcpalg(*argv, ebuf); 1932 assoc->sadb_sa_flags = 1933 SADB_X_SAFLAGS_TCPSIG; 1934 } else { 1935 assoc->sadb_sa_auth = parsealg(*argv, 1936 IPSEC_PROTO_AH, ebuf); 1937 } 1938 break; 1939 case TOK_ENCRALG: 1940 if (satype == SADB_SATYPE_AH) { 1941 ERROR(ep, ebuf, gettext("Cannot specify" 1942 " encryption with SA type ah.\n")); 1943 break; 1944 } 1945 if (satype == SADB_X_SATYPE_TCPSIG) { 1946 ERROR(ep, ebuf, gettext("Cannot specify" 1947 " encryption with SA type" 1948 " tcpsig.\n")); 1949 break; 1950 } 1951 if (assoc->sadb_sa_encrypt != 0) { 1952 ERROR(ep, ebuf, gettext( 1953 "Can only specify " 1954 "single encryption algorithm.\n")); 1955 break; 1956 } 1957 assoc->sadb_sa_encrypt = parsealg(*argv, 1958 IPSEC_PROTO_ESP, ebuf); 1959 break; 1960 case TOK_ENCAP: 1961 if (use_natt) { 1962 ERROR(ep, ebuf, gettext( 1963 "Can only specify single" 1964 " encapsulation.\n")); 1965 break; 1966 } 1967 if (strncmp(*argv, "udp", 3)) { 1968 ERROR(ep, ebuf, gettext( 1969 "Can only specify udp" 1970 " encapsulation.\n")); 1971 break; 1972 } 1973 use_natt = B_TRUE; 1974 /* set assoc flags later */ 1975 break; 1976 } 1977 argv++; 1978 break; 1979 case TOK_SRCPORT: 1980 if (srcport != 0) { 1981 ERROR(ep, ebuf, gettext("Can only specify " 1982 "single source port.\n")); 1983 break; 1984 } 1985 srcport = parsenum(*argv, B_TRUE, ebuf); 1986 argv++; 1987 break; 1988 case TOK_DSTPORT: 1989 if (dstport != 0) { 1990 ERROR(ep, ebuf, gettext("Can only specify " 1991 "single destination port.\n")); 1992 break; 1993 } 1994 dstport = parsenum(*argv, B_TRUE, ebuf); 1995 argv++; 1996 break; 1997 case TOK_ISRCPORT: 1998 alloc_inner = B_TRUE; 1999 if (isrcport != 0) { 2000 ERROR(ep, ebuf, gettext( 2001 "Can only specify " 2002 "single inner-source port.\n")); 2003 break; 2004 } 2005 isrcport = parsenum(*argv, B_TRUE, ebuf); 2006 argv++; 2007 break; 2008 case TOK_IDSTPORT: 2009 alloc_inner = B_TRUE; 2010 if (idstport != 0) { 2011 ERROR(ep, ebuf, gettext( 2012 "Can only specify " 2013 "single inner-destination port.\n")); 2014 break; 2015 } 2016 idstport = parsenum(*argv, B_TRUE, ebuf); 2017 argv++; 2018 break; 2019 case TOK_NATLPORT: 2020 if (natt_lport != 0) { 2021 ERROR(ep, ebuf, gettext( 2022 "Can only specify " 2023 "single NAT-T local port.\n")); 2024 break; 2025 } 2026 natt_lport = parsenum(*argv, B_TRUE, ebuf); 2027 argv++; 2028 break; 2029 case TOK_NATRPORT: 2030 if (natt_rport != 0) { 2031 ERROR(ep, ebuf, gettext( 2032 "Can only specify " 2033 "single NAT-T remote port.\n")); 2034 break; 2035 } 2036 natt_rport = parsenum(*argv, B_TRUE, ebuf); 2037 argv++; 2038 break; 2039 2040 case TOK_PROTO: 2041 if (proto != 0) { 2042 ERROR(ep, ebuf, gettext( 2043 "Can only specify " 2044 "single protocol.\n")); 2045 break; 2046 } 2047 proto = parsenum(*argv, B_TRUE, ebuf); 2048 argv++; 2049 break; 2050 case TOK_IPROTO: 2051 alloc_inner = B_TRUE; 2052 if (iproto != 0) { 2053 ERROR(ep, ebuf, gettext( 2054 "Can only specify " 2055 "single inner protocol.\n")); 2056 break; 2057 } 2058 iproto = parsenum(*argv, B_TRUE, ebuf); 2059 argv++; 2060 break; 2061 case TOK_SRCADDR: 2062 case TOK_SRCADDR6: 2063 if (src != NULL) { 2064 ERROR(ep, ebuf, gettext( 2065 "Can only specify " 2066 "single source address.\n")); 2067 break; 2068 } 2069 sa_len = parseaddr(*argv, &srchp, 2070 (token == TOK_SRCADDR6), ebuf); 2071 if (srchp == NULL) { 2072 ERROR1(ep, ebuf, gettext( 2073 "Unknown src address \"%s\"\n"), *argv); 2074 break; 2075 } 2076 argv++; 2077 /* 2078 * Round of the sockaddr length to an 8 byte 2079 * boundary to make PF_KEY happy. 2080 */ 2081 alloclen = sizeof (*src) + roundup(sa_len, 8); 2082 src = malloc(alloclen); 2083 if (src == NULL) 2084 Bail("malloc(src)"); 2085 totallen += alloclen; 2086 src->sadb_address_len = SADB_8TO64(alloclen); 2087 src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 2088 src->sadb_address_reserved = 0; 2089 src->sadb_address_prefixlen = 0; 2090 src->sadb_address_proto = 0; 2091 if (srchp == &dummy.he) { 2092 /* 2093 * Single address with -n flag. 2094 */ 2095 sin6 = (struct sockaddr_in6 *)(src + 1); 2096 bzero(sin6, sizeof (*sin6)); 2097 sin6->sin6_family = AF_INET6; 2098 bcopy(srchp->h_addr_list[0], &sin6->sin6_addr, 2099 sizeof (struct in6_addr)); 2100 } 2101 break; 2102 case TOK_DSTADDR: 2103 case TOK_DSTADDR6: 2104 if (dst != NULL) { 2105 ERROR(ep, ebuf, gettext( 2106 "Can only specify single " 2107 "destination address.\n")); 2108 break; 2109 } 2110 sa_len = parseaddr(*argv, &dsthp, 2111 (token == TOK_DSTADDR6), ebuf); 2112 if (dsthp == NULL) { 2113 ERROR1(ep, ebuf, gettext( 2114 "Unknown dst address \"%s\"\n"), *argv); 2115 break; 2116 } 2117 argv++; 2118 alloclen = sizeof (*dst) + roundup(sa_len, 8); 2119 dst = malloc(alloclen); 2120 if (dst == NULL) 2121 Bail("malloc(dst)"); 2122 totallen += alloclen; 2123 dst->sadb_address_len = SADB_8TO64(alloclen); 2124 dst->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 2125 dst->sadb_address_reserved = 0; 2126 dst->sadb_address_prefixlen = 0; 2127 dst->sadb_address_proto = 0; 2128 if (dsthp == &dummy.he) { 2129 /* 2130 * Single address with -n flag. 2131 */ 2132 sin6 = (struct sockaddr_in6 *)(dst + 1); 2133 bzero(sin6, sizeof (*sin6)); 2134 sin6->sin6_family = AF_INET6; 2135 bcopy(dsthp->h_addr_list[0], &sin6->sin6_addr, 2136 sizeof (struct in6_addr)); 2137 } 2138 break; 2139 case TOK_PROXYADDR: 2140 case TOK_PROXYADDR6: 2141 if (isrc != NULL) { 2142 ERROR(ep, ebuf, gettext( 2143 "Can only specify single " 2144 "proxy/inner-source address.\n")); 2145 break; 2146 } 2147 if ((pstr = strchr(*argv, '/')) != NULL) { 2148 /* Parse out the prefix. */ 2149 errno = 0; 2150 prefix = strtol(pstr + 1, NULL, 10); 2151 if (errno != 0) { 2152 ERROR1(ep, ebuf, gettext( 2153 "Invalid prefix %s."), pstr); 2154 break; 2155 } 2156 /* Recycle pstr */ 2157 alloclen = (int)(pstr - *argv); 2158 pstr = malloc(alloclen + 1); 2159 if (pstr == NULL) { 2160 Bail("malloc(pstr)"); 2161 } 2162 (void) strlcpy(pstr, *argv, alloclen + 1); 2163 } else { 2164 pstr = *argv; 2165 /* 2166 * Assume mapping to AF_INET6, and we're a host. 2167 * XXX some miscreants may still make classful 2168 * assumptions. If this is a problem, fix it 2169 * here. 2170 */ 2171 prefix = 128; 2172 } 2173 sa_len = parseaddr(pstr, &isrchp, 2174 (token == TOK_PROXYADDR6), ebuf); 2175 if (isrchp == NULL) { 2176 ERROR1(ep, ebuf, gettext( 2177 "Unknown proxy/inner-source address " 2178 "\"%s\"\n"), *argv); 2179 break; 2180 } 2181 if (pstr != *argv) 2182 free(pstr); 2183 argv++; 2184 alloclen = sizeof (*isrc) + roundup(sa_len, 8); 2185 isrc = malloc(alloclen); 2186 if (isrc == NULL) 2187 Bail("malloc(isrc)"); 2188 totallen += alloclen; 2189 isrc->sadb_address_len = SADB_8TO64(alloclen); 2190 isrc->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; 2191 isrc->sadb_address_reserved = 0; 2192 isrc->sadb_address_prefixlen = prefix; 2193 isrc->sadb_address_proto = 0; 2194 if (isrchp == &dummy.he || 2195 isrchp->h_addr_list[1] == NULL) { 2196 /* 2197 * Single address with -n flag or single name. 2198 */ 2199 sin6 = (struct sockaddr_in6 *)(isrc + 1); 2200 bzero(sin6, sizeof (*sin6)); 2201 sin6->sin6_family = AF_INET6; 2202 bcopy(isrchp->h_addr_list[0], &sin6->sin6_addr, 2203 sizeof (struct in6_addr)); 2204 /* 2205 * normalize prefixlen for IPv4-mapped 2206 * addresses. 2207 */ 2208 if (prefix <= 32 && 2209 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2210 isrc->sadb_address_prefixlen += 96; 2211 alloc_inner = B_TRUE; 2212 } else { 2213 /* 2214 * If the proxy/isrc address is vague, don't 2215 * bother. 2216 */ 2217 totallen -= alloclen; 2218 free(isrc); 2219 isrc = NULL; 2220 WARN1(ep, ebuf, gettext( 2221 "Proxy/inner-source address %s " 2222 "is vague, not using.\n"), isrchp->h_name); 2223 freehostent(isrchp); 2224 isrchp = NULL; 2225 break; 2226 } 2227 break; 2228 case TOK_IDSTADDR: 2229 case TOK_IDSTADDR6: 2230 if (idst != NULL) { 2231 ERROR(ep, ebuf, gettext( 2232 "Can only specify single " 2233 "inner-destination address.\n")); 2234 break; 2235 } 2236 if ((pstr = strchr(*argv, '/')) != NULL) { 2237 /* Parse out the prefix. */ 2238 errno = 0; 2239 prefix = strtol(pstr + 1, NULL, 10); 2240 if (errno != 0) { 2241 ERROR1(ep, ebuf, gettext( 2242 "Invalid prefix %s.\n"), pstr); 2243 break; 2244 } 2245 /* Recycle pstr */ 2246 alloclen = (int)(pstr - *argv); 2247 pstr = malloc(alloclen + 1); 2248 if (pstr == NULL) { 2249 Bail("malloc(pstr)"); 2250 } 2251 (void) strlcpy(pstr, *argv, alloclen + 1); 2252 } else { 2253 pstr = *argv; 2254 /* 2255 * Assume mapping to AF_INET6, and we're a host. 2256 * XXX some miscreants may still make classful 2257 * assumptions. If this is a problem, fix it 2258 * here. 2259 */ 2260 prefix = 128; 2261 } 2262 sa_len = parseaddr(pstr, &idsthp, 2263 (token == TOK_IDSTADDR6), ebuf); 2264 if (idsthp == NULL) { 2265 ERROR1(ep, ebuf, gettext( 2266 "Unknown Inner Src address " 2267 " \"%s\"\n"), *argv); 2268 break; 2269 } 2270 if (pstr != *argv) 2271 free(pstr); 2272 argv++; 2273 alloclen = sizeof (*idst) + roundup(sa_len, 8); 2274 idst = malloc(alloclen); 2275 if (idst == NULL) 2276 Bail("malloc(idst)"); 2277 totallen += alloclen; 2278 idst->sadb_address_len = SADB_8TO64(alloclen); 2279 idst->sadb_address_exttype = 2280 SADB_X_EXT_ADDRESS_INNER_DST; 2281 idst->sadb_address_reserved = 0; 2282 idst->sadb_address_prefixlen = prefix; 2283 idst->sadb_address_proto = 0; 2284 if (idsthp == &dummy.he || 2285 idsthp->h_addr_list[1] == NULL) { 2286 /* 2287 * Single address with -n flag or single name. 2288 */ 2289 sin6 = (struct sockaddr_in6 *)(idst + 1); 2290 bzero(sin6, sizeof (*sin6)); 2291 sin6->sin6_family = AF_INET6; 2292 bcopy(idsthp->h_addr_list[0], &sin6->sin6_addr, 2293 sizeof (struct in6_addr)); 2294 /* 2295 * normalize prefixlen for IPv4-mapped 2296 * addresses. 2297 */ 2298 if (prefix <= 32 && 2299 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2300 idst->sadb_address_prefixlen += 96; 2301 alloc_inner = B_TRUE; 2302 } else { 2303 /* 2304 * If the idst address is vague, don't bother. 2305 */ 2306 totallen -= alloclen; 2307 free(idst); 2308 idst = NULL; 2309 WARN1(ep, ebuf, gettext( 2310 "Inner destination address %s " 2311 "is vague, not using.\n"), idsthp->h_name); 2312 freehostent(idsthp); 2313 idsthp = NULL; 2314 break; 2315 } 2316 break; 2317 case TOK_NATLOC: 2318 if (natt_local != NULL) { 2319 ERROR(ep, ebuf, gettext( 2320 "Can only specify " 2321 "single NAT-T local address.\n")); 2322 break; 2323 } 2324 sa_len = parseaddr(*argv, &natt_lhp, 0, ebuf); 2325 if (natt_lhp == NULL) { 2326 ERROR1(ep, ebuf, gettext( 2327 "Unknown NAT-T local address \"%s\"\n"), 2328 *argv); 2329 break; 2330 } 2331 argv++; 2332 /* 2333 * Round of the sockaddr length to an 8 byte 2334 * boundary to make PF_KEY happy. 2335 */ 2336 alloclen = sizeof (*natt_local) + roundup(sa_len, 8); 2337 natt_local = malloc(alloclen); 2338 if (natt_local == NULL) 2339 Bail("malloc(natt_local)"); 2340 totallen += alloclen; 2341 natt_local->sadb_address_len = SADB_8TO64(alloclen); 2342 natt_local->sadb_address_exttype = 2343 SADB_X_EXT_ADDRESS_NATT_LOC; 2344 natt_local->sadb_address_reserved = 0; 2345 natt_local->sadb_address_prefixlen = 0; 2346 natt_local->sadb_address_proto = 0; 2347 if (natt_lhp == &dummy.he || 2348 natt_lhp->h_addr_list[1] == NULL) { 2349 /* 2350 * Single address with -n flag or single name. 2351 */ 2352 sin6 = (struct sockaddr_in6 *)(natt_local + 1); 2353 bzero(sin6, sizeof (*sin6)); 2354 sin6->sin6_family = AF_INET6; 2355 bcopy(natt_lhp->h_addr_list[0], 2356 &sin6->sin6_addr, sizeof (struct in6_addr)); 2357 } else { 2358 /* 2359 * If the nat-local address is vague, don't 2360 * bother. 2361 */ 2362 totallen -= alloclen; 2363 free(natt_local); 2364 natt_local = NULL; 2365 WARN1(ep, ebuf, gettext( 2366 "NAT-T local address %s " 2367 "is vague, not using.\n"), 2368 natt_lhp->h_name); 2369 freehostent(natt_lhp); 2370 natt_lhp = NULL; 2371 break; 2372 } 2373 break; 2374 case TOK_NATREM: 2375 if (natt_remote != NULL) { 2376 ERROR(ep, ebuf, gettext( 2377 "Can only specify " 2378 "single NAT-T remote address.\n")); 2379 break; 2380 } 2381 sa_len = parseaddr(*argv, &natt_rhp, 0, ebuf); 2382 if (natt_rhp == NULL) { 2383 ERROR1(ep, ebuf, gettext( 2384 "Unknown NAT-T remote address \"%s\"\n"), 2385 *argv); 2386 break; 2387 } 2388 argv++; 2389 /* 2390 * Round of the sockaddr length to an 8 byte 2391 * boundary to make PF_KEY happy. 2392 */ 2393 alloclen = sizeof (*natt_remote) + roundup(sa_len, 8); 2394 natt_remote = malloc(alloclen); 2395 if (natt_remote == NULL) 2396 Bail("malloc(natt_remote)"); 2397 totallen += alloclen; 2398 natt_remote->sadb_address_len = SADB_8TO64(alloclen); 2399 natt_remote->sadb_address_exttype = 2400 SADB_X_EXT_ADDRESS_NATT_REM; 2401 natt_remote->sadb_address_reserved = 0; 2402 natt_remote->sadb_address_prefixlen = 0; 2403 natt_remote->sadb_address_proto = 0; 2404 if (natt_rhp == &dummy.he || 2405 natt_rhp->h_addr_list[1] == NULL) { 2406 /* 2407 * Single address with -n flag or single name. 2408 */ 2409 sin6 = (struct sockaddr_in6 *)(natt_remote + 1); 2410 bzero(sin6, sizeof (*sin6)); 2411 sin6->sin6_family = AF_INET6; 2412 bcopy(natt_rhp->h_addr_list[0], 2413 &sin6->sin6_addr, sizeof (struct in6_addr)); 2414 } else { 2415 /* 2416 * If the nat-renote address is vague, don't 2417 * bother. 2418 */ 2419 totallen -= alloclen; 2420 free(natt_remote); 2421 natt_remote = NULL; 2422 WARN1(ep, ebuf, gettext( 2423 "NAT-T remote address %s " 2424 "is vague, not using.\n"), 2425 natt_rhp->h_name); 2426 freehostent(natt_rhp); 2427 natt_rhp = NULL; 2428 break; 2429 } 2430 break; 2431 case TOK_ENCRKEY: 2432 if (encrypt != NULL) { 2433 ERROR(ep, ebuf, gettext( 2434 "Can only specify a single" 2435 " encryption key.\n")); 2436 break; 2437 } 2438 if (assoc != NULL && 2439 assoc->sadb_sa_encrypt == SADB_EALG_NULL) { 2440 FATAL(ep, ebuf, gettext( 2441 "Cannot specify a key with NULL " 2442 "encryption algorithm.\n")); 2443 break; 2444 } 2445 encrypt = parsekey(*argv, ebuf, reserved_bits); 2446 argv++; 2447 if (encrypt == NULL) { 2448 ERROR(ep, ebuf, gettext( 2449 "Invalid encryption key.\n")); 2450 break; 2451 } 2452 totallen += SADB_64TO8(encrypt->sadb_key_len); 2453 encrypt->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; 2454 break; 2455 case TOK_AUTHKEY: 2456 if (auth != NULL) { 2457 ERROR(ep, ebuf, gettext( 2458 "Can only specify a single" 2459 " authentication key.\n")); 2460 break; 2461 } 2462 auth = parsekey(*argv, ebuf, 0); 2463 argv++; 2464 if (auth == NULL) { 2465 ERROR(ep, ebuf, gettext( 2466 "Invalid authentication key.\n")); 2467 break; 2468 } 2469 totallen += SADB_64TO8(auth->sadb_key_len); 2470 auth->sadb_key_exttype = SADB_EXT_KEY_AUTH; 2471 break; 2472 case TOK_AUTHSTR: 2473 if (satype != SADB_X_SATYPE_TCPSIG) { 2474 ERROR(ep, ebuf, gettext( 2475 "An authentication string can only be " 2476 "specified for SA type tcpsig.\n")); 2477 break; 2478 } 2479 if (auth != NULL) { 2480 ERROR(ep, ebuf, gettext( 2481 "Can only specify a single" 2482 " authentication key or string.\n")); 2483 break; 2484 } 2485 auth = parseauthstr(*argv, ebuf); 2486 argv++; 2487 if (auth == NULL) { 2488 ERROR(ep, ebuf, gettext( 2489 "Invalid authentication string.\n")); 2490 break; 2491 } 2492 totallen += SADB_64TO8(auth->sadb_key_len); 2493 auth->sadb_key_exttype = SADB_X_EXT_STR_AUTH; 2494 break; 2495 case TOK_SRCIDTYPE: 2496 if (*argv == NULL || *(argv + 1) == NULL) { 2497 FATAL(ep, ebuf, gettext( 2498 "Unexpected end of command " 2499 "line - Expecting Src Type.\n")); 2500 /* NOTREACHED */ 2501 break; 2502 } 2503 if (srcid != NULL) { 2504 ERROR(ep, ebuf, gettext( 2505 "Can only specify single" 2506 " source certificate identity.\n")); 2507 break; 2508 } 2509 alloclen = sizeof (*srcid) + 2510 roundup(strlen(*(argv + 1)) + 1, 8); 2511 srcid = malloc(alloclen); 2512 if (srcid == NULL) 2513 Bail("malloc(srcid)"); 2514 totallen += alloclen; 2515 srcid->sadb_ident_type = parseidtype(*argv, ebuf); 2516 argv++; 2517 srcid->sadb_ident_len = SADB_8TO64(alloclen); 2518 srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; 2519 srcid->sadb_ident_reserved = 0; 2520 srcid->sadb_ident_id = 0; /* Not useful here. */ 2521 (void) strlcpy((char *)(srcid + 1), *argv, alloclen); 2522 argv++; 2523 break; 2524 case TOK_DSTIDTYPE: 2525 if (*argv == NULL || *(argv + 1) == NULL) { 2526 ERROR(ep, ebuf, gettext( 2527 "Unexpected end of command" 2528 " line - expecting dst type.\n")); 2529 break; 2530 } 2531 if (dstid != NULL) { 2532 ERROR(ep, ebuf, gettext( 2533 "Can only specify single destination " 2534 "certificate identity.\n")); 2535 break; 2536 } 2537 alloclen = sizeof (*dstid) + 2538 roundup(strlen(*(argv + 1)) + 1, 8); 2539 dstid = malloc(alloclen); 2540 if (dstid == NULL) 2541 Bail("malloc(dstid)"); 2542 totallen += alloclen; 2543 dstid->sadb_ident_type = parseidtype(*argv, ebuf); 2544 argv++; 2545 dstid->sadb_ident_len = SADB_8TO64(alloclen); 2546 dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; 2547 dstid->sadb_ident_reserved = 0; 2548 dstid->sadb_ident_id = 0; /* Not useful here. */ 2549 (void) strlcpy((char *)(dstid + 1), *argv, alloclen); 2550 argv++; 2551 break; 2552 case TOK_HARD_ALLOC: 2553 case TOK_HARD_BYTES: 2554 case TOK_HARD_ADDTIME: 2555 case TOK_HARD_USETIME: 2556 if (hard == NULL) { 2557 hard = malloc(sizeof (*hard)); 2558 if (hard == NULL) 2559 Bail("malloc(hard_lifetime)"); 2560 bzero(hard, sizeof (*hard)); 2561 hard->sadb_lifetime_exttype = 2562 SADB_EXT_LIFETIME_HARD; 2563 hard->sadb_lifetime_len = 2564 SADB_8TO64(sizeof (*hard)); 2565 totallen += sizeof (*hard); 2566 } 2567 switch (token) { 2568 case TOK_HARD_ALLOC: 2569 if (hard->sadb_lifetime_allocations != 0) { 2570 ERROR(ep, ebuf, gettext( 2571 "Can only specify single" 2572 " hard allocation limit.\n")); 2573 break; 2574 } 2575 hard->sadb_lifetime_allocations = 2576 (uint32_t)parsenum(*argv, B_TRUE, ebuf); 2577 break; 2578 case TOK_HARD_BYTES: 2579 if (hard->sadb_lifetime_bytes != 0) { 2580 ERROR(ep, ebuf, gettext( 2581 "Can only specify " 2582 "single hard byte limit.\n")); 2583 break; 2584 } 2585 hard->sadb_lifetime_bytes = parsenum(*argv, 2586 B_TRUE, ebuf); 2587 break; 2588 case TOK_HARD_ADDTIME: 2589 if (hard->sadb_lifetime_addtime != 0) { 2590 ERROR(ep, ebuf, gettext( 2591 "Can only specify " 2592 "single past-add lifetime.\n")); 2593 break; 2594 } 2595 hard->sadb_lifetime_addtime = parsenum(*argv, 2596 B_TRUE, ebuf); 2597 break; 2598 case TOK_HARD_USETIME: 2599 if (hard->sadb_lifetime_usetime != 0) { 2600 ERROR(ep, ebuf, gettext( 2601 "Can only specify " 2602 "single past-use lifetime.\n")); 2603 break; 2604 } 2605 hard->sadb_lifetime_usetime = parsenum(*argv, 2606 B_TRUE, ebuf); 2607 break; 2608 } 2609 argv++; 2610 break; 2611 case TOK_SOFT_ALLOC: 2612 case TOK_SOFT_BYTES: 2613 case TOK_SOFT_ADDTIME: 2614 case TOK_SOFT_USETIME: 2615 if (soft == NULL) { 2616 soft = malloc(sizeof (*soft)); 2617 if (soft == NULL) 2618 Bail("malloc(soft_lifetime)"); 2619 bzero(soft, sizeof (*soft)); 2620 soft->sadb_lifetime_exttype = 2621 SADB_EXT_LIFETIME_SOFT; 2622 soft->sadb_lifetime_len = 2623 SADB_8TO64(sizeof (*soft)); 2624 totallen += sizeof (*soft); 2625 } 2626 switch (token) { 2627 case TOK_SOFT_ALLOC: 2628 if (soft->sadb_lifetime_allocations != 0) { 2629 ERROR(ep, ebuf, gettext( 2630 "Can only specify single" 2631 " soft allocation limit.\n")); 2632 break; 2633 } 2634 soft->sadb_lifetime_allocations = 2635 (uint32_t)parsenum(*argv, B_TRUE, ebuf); 2636 break; 2637 case TOK_SOFT_BYTES: 2638 if (soft->sadb_lifetime_bytes != 0) { 2639 ERROR(ep, ebuf, gettext( 2640 "Can only specify single" 2641 " soft byte limit.\n")); 2642 break; 2643 } 2644 soft->sadb_lifetime_bytes = parsenum(*argv, 2645 B_TRUE, ebuf); 2646 break; 2647 case TOK_SOFT_ADDTIME: 2648 if (soft->sadb_lifetime_addtime != 0) { 2649 ERROR(ep, ebuf, gettext( 2650 "Can only specify single" 2651 " past-add lifetime.\n")); 2652 break; 2653 } 2654 soft->sadb_lifetime_addtime = parsenum(*argv, 2655 B_TRUE, ebuf); 2656 break; 2657 case TOK_SOFT_USETIME: 2658 if (soft->sadb_lifetime_usetime != 0) { 2659 ERROR(ep, ebuf, gettext( 2660 "Can only specify single" 2661 " past-use lifetime.\n")); 2662 break; 2663 } 2664 soft->sadb_lifetime_usetime = parsenum(*argv, 2665 B_TRUE, ebuf); 2666 break; 2667 } 2668 argv++; 2669 break; 2670 case TOK_FLAG_INBOUND: 2671 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_INBOUND; 2672 break; 2673 case TOK_FLAG_OUTBOUND: 2674 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_OUTBOUND; 2675 break; 2676 case TOK_REPLAY_VALUE: 2677 if (replay_ctr != NULL) { 2678 ERROR(ep, ebuf, gettext( 2679 "Can only specify single " 2680 "replay value.")); 2681 break; 2682 } 2683 replay_ctr = calloc(1, sizeof (*replay_ctr)); 2684 if (replay_ctr == NULL) { 2685 Bail("malloc(replay value)"); 2686 } 2687 /* 2688 * We currently do not support a 64-bit 2689 * replay value. RFC 4301 will require one, 2690 * however, and we have a field in place when 2691 * 4301 is built. 2692 */ 2693 replay_ctr->sadb_x_rc_exttype = SADB_X_EXT_REPLAY_VALUE; 2694 replay_ctr->sadb_x_rc_len = 2695 SADB_8TO64(sizeof (*replay_ctr)); 2696 totallen += sizeof (*replay_ctr); 2697 replay_ctr->sadb_x_rc_replay32 = (uint32_t)parsenum( 2698 *argv, B_TRUE, ebuf); 2699 argv++; 2700 break; 2701 case TOK_IDLE_ADDTIME: 2702 case TOK_IDLE_USETIME: 2703 if (idle == NULL) { 2704 idle = calloc(1, sizeof (*idle)); 2705 if (idle == NULL) { 2706 Bail("malloc idle lifetime"); 2707 } 2708 idle->sadb_lifetime_exttype = 2709 SADB_X_EXT_LIFETIME_IDLE; 2710 idle->sadb_lifetime_len = 2711 SADB_8TO64(sizeof (*idle)); 2712 totallen += sizeof (*idle); 2713 } 2714 switch (token) { 2715 case TOK_IDLE_ADDTIME: 2716 idle->sadb_lifetime_addtime = 2717 (uint32_t)parsenum(*argv, 2718 B_TRUE, ebuf); 2719 break; 2720 case TOK_IDLE_USETIME: 2721 idle->sadb_lifetime_usetime = 2722 (uint32_t)parsenum(*argv, 2723 B_TRUE, ebuf); 2724 break; 2725 } 2726 argv++; 2727 break; 2728 case TOK_RESERVED: 2729 if (encrypt != NULL) 2730 ERROR(ep, ebuf, gettext( 2731 "Reserved bits need to be " 2732 "specified before key.\n")); 2733 reserved_bits = (uint_t)parsenum(*argv, 2734 B_TRUE, ebuf); 2735 argv++; 2736 break; 2737 case TOK_LABEL: 2738 label = parselabel(token, *argv); 2739 argv++; 2740 if (label == NULL) { 2741 ERROR(ep, ebuf, 2742 gettext("Malformed security label\n")); 2743 break; 2744 } else if (label == PARSELABEL_BAD_TOKEN) { 2745 Bail("Internal token value error"); 2746 } 2747 totallen += SADB_64TO8(label->sadb_sens_len); 2748 break; 2749 2750 case TOK_OLABEL: 2751 case TOK_IMPLABEL: 2752 olabel = parselabel(token, *argv); 2753 argv++; 2754 if (label == NULL) { 2755 ERROR(ep, ebuf, 2756 gettext("Malformed security label\n")); 2757 break; 2758 } else if (label == PARSELABEL_BAD_TOKEN) { 2759 Bail("Internal token value error"); 2760 } 2761 totallen += SADB_64TO8(olabel->sadb_sens_len); 2762 break; 2763 default: 2764 ERROR1(ep, ebuf, gettext( 2765 "Don't use extension %s for add/update.\n"), 2766 *(argv - 1)); 2767 break; 2768 } 2769 } while (token != TOK_EOF); 2770 2771 handle_errors(ep, ebuf, B_TRUE, B_FALSE); 2772 2773 #define PORT_ONLY_ALLOCATE(af, socktype, exttype, extvar, port) { \ 2774 alloclen = sizeof (sadb_address_t) + roundup(sizeof (socktype), 8); \ 2775 (extvar) = calloc(1, alloclen); \ 2776 if ((extvar) == NULL) { \ 2777 Bail("malloc(implicit port)"); \ 2778 } \ 2779 totallen += alloclen; \ 2780 (extvar)->sadb_address_len = SADB_8TO64(alloclen); \ 2781 (extvar)->sadb_address_exttype = (exttype); \ 2782 /* sin/sin6 has equivalent offsets for ports! */ \ 2783 sin6 = (struct sockaddr_in6 *)((extvar) + 1); \ 2784 sin6->sin6_family = (af); \ 2785 sin6->sin6_port = (port); \ 2786 } 2787 2788 /* 2789 * If we specify inner ports or NAT ports w/o addresses, we still need 2790 * to allocate. Also, if we have one inner address, we need the 2791 * other, even if we don't specify anything. 2792 */ 2793 if (use_natt) { 2794 if (natt_lport != 0 && natt_local == NULL) { 2795 PORT_ONLY_ALLOCATE(AF_INET, struct sockaddr_in, 2796 SADB_X_EXT_ADDRESS_NATT_LOC, natt_local, 2797 natt_lport); 2798 } 2799 2800 if (natt_rport != 0 && natt_remote == NULL) { 2801 PORT_ONLY_ALLOCATE(AF_INET, struct sockaddr_in, 2802 SADB_X_EXT_ADDRESS_NATT_REM, natt_remote, 2803 natt_rport); 2804 } 2805 } else { 2806 if (natt_lport != 0 || natt_rport != 0) { 2807 ERROR(ep, ebuf, gettext("Must specify 'encap udp' " 2808 "with any NAT-T port.\n")); 2809 } else if (natt_local != NULL || natt_remote != NULL) { 2810 ERROR(ep, ebuf, gettext("Must specify 'encap udp' " 2811 "with any NAT-T address.\n")); 2812 } 2813 } 2814 2815 if (alloc_inner && idst == NULL) { 2816 PORT_ONLY_ALLOCATE(AF_INET6, struct sockaddr_in6, 2817 SADB_X_EXT_ADDRESS_INNER_DST, idst, 0); 2818 } 2819 2820 if (alloc_inner && isrc == NULL) { 2821 PORT_ONLY_ALLOCATE(AF_INET6, struct sockaddr_in6, 2822 SADB_X_EXT_ADDRESS_INNER_SRC, isrc, 0); 2823 } 2824 #undef PORT_ONLY_ALLOCATE 2825 2826 /* 2827 * Okay, so now I have all of the potential extensions! 2828 * Allocate a single contiguous buffer. Keep in mind that it'll 2829 * be enough because the key itself will be yanked. 2830 */ 2831 2832 if (src == NULL && dst != NULL) { 2833 /* 2834 * Set explicit unspecified source address. 2835 */ 2836 size_t lenbytes = SADB_64TO8(dst->sadb_address_len); 2837 2838 unspec_src = B_TRUE; 2839 totallen += lenbytes; 2840 src = malloc(lenbytes); 2841 if (src == NULL) 2842 Bail("malloc(implicit src)"); 2843 /* Confusing, but we're copying from DST to SRC. :) */ 2844 bcopy(dst, src, lenbytes); 2845 src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 2846 sin6 = (struct sockaddr_in6 *)(src + 1); 2847 bzero(sin6, sizeof (*sin6)); 2848 sin6->sin6_family = AF_INET6; 2849 } 2850 2851 msg.sadb_msg_len = SADB_8TO64(totallen); 2852 2853 buffer = malloc(totallen); 2854 nexthdr = buffer; 2855 bcopy(&msg, nexthdr, sizeof (msg)); 2856 nexthdr += SADB_8TO64(sizeof (msg)); 2857 if (assoc != NULL) { 2858 if (satype != SADB_X_SATYPE_TCPSIG && assoc->sadb_sa_spi == 0) { 2859 ERROR1(ep, ebuf, gettext( 2860 "The SPI value is missing for " 2861 "the association you wish to %s.\n"), thiscmd); 2862 } 2863 if (assoc->sadb_sa_auth == 0 && assoc->sadb_sa_encrypt == 0 && 2864 cmd == CMD_ADD) { 2865 free(assoc); 2866 FATAL(ep, ebuf, gettext( 2867 "Select at least one algorithm " 2868 "for this add.\n")); 2869 } 2870 2871 /* Hack to let user specify NULL ESP implicitly. */ 2872 if (msg.sadb_msg_satype == SADB_SATYPE_ESP && 2873 assoc->sadb_sa_encrypt == 0) 2874 assoc->sadb_sa_encrypt = SADB_EALG_NULL; 2875 2876 /* 0 is an actual value. Print a warning if it was entered. */ 2877 if (assoc->sadb_sa_state == 0) { 2878 if (readstate) { 2879 ERROR(ep, ebuf, gettext( 2880 "WARNING: Cannot set LARVAL SA state.\n")); 2881 } 2882 assoc->sadb_sa_state = SADB_SASTATE_MATURE; 2883 } 2884 2885 if (use_natt) { 2886 if (natt_remote != NULL) 2887 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_NATT_REM; 2888 if (natt_local != NULL) 2889 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_NATT_LOC; 2890 } 2891 2892 if (alloc_inner) { 2893 /* 2894 * For now, assume RFC 3884's dream of transport-mode 2895 * SAs with inner IP address selectors will not 2896 * happen. 2897 */ 2898 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; 2899 if (proto != 0 && proto != IPPROTO_ENCAP && 2900 proto != IPPROTO_IPV6) { 2901 ERROR1(ep, ebuf, gettext( 2902 "WARNING: Protocol type %d not " 2903 "for use with Tunnel-Mode SA.\n"), proto); 2904 /* Continue and let PF_KEY scream... */ 2905 } 2906 } 2907 2908 bcopy(assoc, nexthdr, SADB_64TO8(assoc->sadb_sa_len)); 2909 nexthdr += assoc->sadb_sa_len; 2910 /* Save the SPI for the case of an error. */ 2911 spi = assoc->sadb_sa_spi; 2912 free(assoc); 2913 } else { 2914 if (satype != SADB_X_SATYPE_TCPSIG && spi == 0) 2915 ERROR1(ep, ebuf, gettext( 2916 "Need to define SPI for %s.\n"), thiscmd); 2917 ERROR1(ep, ebuf, gettext( 2918 "Need SA parameters for %s.\n"), thiscmd); 2919 } 2920 2921 if (sadb_pair != NULL) { 2922 if (sadb_pair->sadb_x_pair_spi == 0) { 2923 ERROR1(ep, ebuf, gettext( 2924 "The SPI value is missing for the " 2925 "association you wish to %s.\n"), thiscmd); 2926 } 2927 bcopy(sadb_pair, nexthdr, 2928 SADB_64TO8(sadb_pair->sadb_x_pair_len)); 2929 nexthdr += sadb_pair->sadb_x_pair_len; 2930 free(sadb_pair); 2931 } 2932 2933 if (hard != NULL) { 2934 bcopy(hard, nexthdr, SADB_64TO8(hard->sadb_lifetime_len)); 2935 nexthdr += hard->sadb_lifetime_len; 2936 free(hard); 2937 } 2938 2939 if (soft != NULL) { 2940 bcopy(soft, nexthdr, SADB_64TO8(soft->sadb_lifetime_len)); 2941 nexthdr += soft->sadb_lifetime_len; 2942 free(soft); 2943 } 2944 2945 if (idle != NULL) { 2946 bcopy(idle, nexthdr, SADB_64TO8(idle->sadb_lifetime_len)); 2947 nexthdr += idle->sadb_lifetime_len; 2948 free(idle); 2949 } 2950 2951 if (encrypt == NULL && auth == NULL && cmd == CMD_ADD) { 2952 ERROR(ep, ebuf, gettext( 2953 "Must have at least one key for an add.\n")); 2954 } 2955 2956 if (encrypt != NULL) { 2957 bcopy(encrypt, nexthdr, SADB_64TO8(encrypt->sadb_key_len)); 2958 nexthdr += encrypt->sadb_key_len; 2959 explicit_bzero(encrypt, SADB_64TO8(encrypt->sadb_key_len)); 2960 free(encrypt); 2961 } 2962 2963 if (auth != NULL) { 2964 bcopy(auth, nexthdr, SADB_64TO8(auth->sadb_key_len)); 2965 nexthdr += auth->sadb_key_len; 2966 explicit_bzero(auth, SADB_64TO8(auth->sadb_key_len)); 2967 free(auth); 2968 } 2969 2970 if (srcid != NULL) { 2971 bcopy(srcid, nexthdr, SADB_64TO8(srcid->sadb_ident_len)); 2972 nexthdr += srcid->sadb_ident_len; 2973 free(srcid); 2974 } 2975 2976 if (dstid != NULL) { 2977 bcopy(dstid, nexthdr, SADB_64TO8(dstid->sadb_ident_len)); 2978 nexthdr += dstid->sadb_ident_len; 2979 free(dstid); 2980 } 2981 2982 if (dst != NULL) { 2983 bcopy(dst, nexthdr, SADB_64TO8(dst->sadb_address_len)); 2984 free(dst); 2985 dst = (struct sadb_address *)nexthdr; 2986 dst->sadb_address_proto = proto; 2987 ((struct sockaddr_in6 *)(dst + 1))->sin6_port = htons(dstport); 2988 nexthdr += dst->sadb_address_len; 2989 } else { 2990 FATAL1(ep, ebuf, gettext( 2991 "Need destination address for %s.\n"), thiscmd); 2992 } 2993 2994 if (use_natt) { 2995 if (natt_remote == NULL && natt_local == NULL) { 2996 ERROR(ep, ebuf, gettext( 2997 "Must specify NAT-T remote or local address " 2998 "for UDP encapsulation.\n")); 2999 } 3000 3001 if (natt_remote != NULL) { 3002 bcopy(natt_remote, nexthdr, 3003 SADB_64TO8(natt_remote->sadb_address_len)); 3004 free(natt_remote); 3005 natt_remote = (struct sadb_address *)nexthdr; 3006 nexthdr += natt_remote->sadb_address_len; 3007 ((struct sockaddr_in6 *)(natt_remote + 1))->sin6_port = 3008 htons(natt_rport); 3009 } 3010 3011 if (natt_local != NULL) { 3012 bcopy(natt_local, nexthdr, 3013 SADB_64TO8(natt_local->sadb_address_len)); 3014 free(natt_local); 3015 natt_local = (struct sadb_address *)nexthdr; 3016 nexthdr += natt_local->sadb_address_len; 3017 ((struct sockaddr_in6 *)(natt_local + 1))->sin6_port = 3018 htons(natt_lport); 3019 } 3020 } 3021 3022 handle_errors(ep, ebuf, B_TRUE, B_FALSE); 3023 3024 /* 3025 * PF_KEY requires a source address extension, even if the source 3026 * address itself is unspecified. (See "Set explicit unspecified..." 3027 * code fragment above. Destination reality check was above.) 3028 */ 3029 bcopy(src, nexthdr, SADB_64TO8(src->sadb_address_len)); 3030 free(src); 3031 src = (struct sadb_address *)nexthdr; 3032 src->sadb_address_proto = proto; 3033 ((struct sockaddr_in6 *)(src + 1))->sin6_port = htons(srcport); 3034 nexthdr += src->sadb_address_len; 3035 3036 if (isrc != NULL) { 3037 bcopy(isrc, nexthdr, SADB_64TO8(isrc->sadb_address_len)); 3038 free(isrc); 3039 isrc = (struct sadb_address *)nexthdr; 3040 isrc->sadb_address_proto = iproto; 3041 ((struct sockaddr_in6 *)(isrc + 1))->sin6_port = 3042 htons(isrcport); 3043 nexthdr += isrc->sadb_address_len; 3044 } 3045 3046 if (idst != NULL) { 3047 bcopy(idst, nexthdr, SADB_64TO8(idst->sadb_address_len)); 3048 free(idst); 3049 idst = (struct sadb_address *)nexthdr; 3050 idst->sadb_address_proto = iproto; 3051 ((struct sockaddr_in6 *)(idst + 1))->sin6_port = 3052 htons(idstport); 3053 nexthdr += idst->sadb_address_len; 3054 } 3055 3056 if (replay_ctr != NULL) { 3057 bcopy(replay_ctr, nexthdr, 3058 SADB_64TO8(replay_ctr->sadb_x_rc_len)); 3059 nexthdr += replay_ctr->sadb_x_rc_len; 3060 free(replay_ctr); 3061 } 3062 3063 if (label != NULL) { 3064 bcopy(label, nexthdr, SADB_64TO8(label->sadb_sens_len)); 3065 nexthdr += label->sadb_sens_len; 3066 free(label); 3067 label = NULL; 3068 } 3069 3070 if (olabel != NULL) { 3071 bcopy(olabel, nexthdr, SADB_64TO8(olabel->sadb_sens_len)); 3072 nexthdr += olabel->sadb_sens_len; 3073 free(olabel); 3074 olabel = NULL; 3075 } 3076 3077 if (cflag) { 3078 /* 3079 * Assume the checked cmd would have worked if it was actually 3080 * used. doaddresses() will increment lines_added if it 3081 * succeeds. 3082 */ 3083 lines_added++; 3084 } else { 3085 doaddresses(sadb_msg_type, satype, 3086 cmd, srchp, dsthp, src, dst, unspec_src, buffer, totallen, 3087 spi, ebuf); 3088 } 3089 3090 if (isrchp != NULL && isrchp != &dummy.he) 3091 freehostent(isrchp); 3092 if (idsthp != NULL && idsthp != &dummy.he) 3093 freehostent(idsthp); 3094 if (srchp != NULL && srchp != &dummy.he) 3095 freehostent(srchp); 3096 if (dsthp != NULL && dsthp != &dummy.he) 3097 freehostent(dsthp); 3098 if (natt_lhp != NULL && natt_lhp != &dummy.he) 3099 freehostent(natt_lhp); 3100 if (natt_rhp != NULL && natt_rhp != &dummy.he) 3101 freehostent(natt_rhp); 3102 free(ebuf); 3103 free(buffer); 3104 } 3105 3106 /* 3107 * DELETE and GET are similar, in that they only need the extensions 3108 * required to _find_ an SA, and then either delete it or obtain its 3109 * information. 3110 */ 3111 static void 3112 dodelget(int cmd, int satype, char *argv[], char *ebuf) 3113 { 3114 struct sadb_msg *msg = (struct sadb_msg *)get_buffer; 3115 uint64_t *nextext; 3116 struct sadb_sa *assoc = NULL; 3117 struct sadb_address *src = NULL, *dst = NULL; 3118 int next, token, sa_len; 3119 char *thiscmd; 3120 uint32_t spi = 0; 3121 uint8_t sadb_msg_type; 3122 struct hostent *srchp = NULL, *dsthp = NULL; 3123 struct sockaddr_in6 *sin6; 3124 boolean_t unspec_src = B_TRUE; 3125 uint16_t srcport = 0, dstport = 0; 3126 uint8_t proto = 0; 3127 char *ep = NULL; 3128 uint32_t sa_flags = 0; 3129 3130 /* Set the first extension header to right past the base message. */ 3131 nextext = (uint64_t *)(msg + 1); 3132 bzero(nextext, sizeof (get_buffer) - sizeof (*msg)); 3133 3134 switch (cmd) { 3135 case CMD_GET: 3136 thiscmd = "get"; 3137 sadb_msg_type = SADB_GET; 3138 break; 3139 case CMD_DELETE: 3140 thiscmd = "delete"; 3141 sadb_msg_type = SADB_DELETE; 3142 break; 3143 case CMD_DELETE_PAIR: 3144 thiscmd = "delete-pair"; 3145 sadb_msg_type = SADB_X_DELPAIR; 3146 break; 3147 } 3148 3149 msg_init(msg, sadb_msg_type, (uint8_t)satype); 3150 3151 #define ALLOC_ADDR_EXT(ext, exttype) \ 3152 (ext) = (struct sadb_address *)nextext; \ 3153 nextext = (uint64_t *)((ext) + 1); \ 3154 nextext += SADB_8TO64(roundup(sa_len, 8)); \ 3155 (ext)->sadb_address_exttype = exttype; \ 3156 (ext)->sadb_address_len = nextext - ((uint64_t *)ext); 3157 3158 /* Assume last element in argv is set to NULL. */ 3159 do { 3160 token = parseextval(*argv, &next); 3161 argv++; 3162 switch (token) { 3163 case TOK_EOF: 3164 /* Do nothing, I'm done. */ 3165 break; 3166 case TOK_UNKNOWN: 3167 ERROR1(ep, ebuf, gettext( 3168 "Unknown extension field \"%s\"\n"), *(argv - 1)); 3169 break; 3170 case TOK_SPI: 3171 if (assoc != NULL) { 3172 ERROR(ep, ebuf, gettext( 3173 "Can only specify single SPI value.\n")); 3174 break; 3175 } 3176 assoc = (struct sadb_sa *)nextext; 3177 nextext = (uint64_t *)(assoc + 1); 3178 assoc->sadb_sa_len = SADB_8TO64(sizeof (*assoc)); 3179 assoc->sadb_sa_exttype = SADB_EXT_SA; 3180 assoc->sadb_sa_spi = htonl((uint32_t)parsenum(*argv, 3181 B_TRUE, ebuf)); 3182 spi = assoc->sadb_sa_spi; 3183 argv++; 3184 break; 3185 case TOK_SRCPORT: 3186 if (srcport != 0) { 3187 ERROR(ep, ebuf, gettext( 3188 "Can only specify single source port.\n")); 3189 break; 3190 } 3191 srcport = parsenum(*argv, B_TRUE, ebuf); 3192 argv++; 3193 break; 3194 case TOK_DSTPORT: 3195 if (dstport != 0) { 3196 ERROR(ep, ebuf, gettext( 3197 "Can only " 3198 "specify single destination port.\n")); 3199 break; 3200 } 3201 dstport = parsenum(*argv, B_TRUE, ebuf); 3202 argv++; 3203 break; 3204 case TOK_PROTO: 3205 if (proto != 0) { 3206 ERROR(ep, ebuf, gettext( 3207 "Can only specify single protocol.\n")); 3208 break; 3209 } 3210 proto = parsenum(*argv, B_TRUE, ebuf); 3211 argv++; 3212 break; 3213 case TOK_SRCADDR: 3214 case TOK_SRCADDR6: 3215 if (src != NULL) { 3216 ERROR(ep, ebuf, gettext( 3217 "Can only specify single source addr.\n")); 3218 break; 3219 } 3220 sa_len = parseaddr(*argv, &srchp, 3221 (token == TOK_SRCADDR6), ebuf); 3222 if (srchp == NULL) { 3223 ERROR1(ep, ebuf, gettext( 3224 "Unknown source address \"%s\"\n"), *argv); 3225 break; 3226 } 3227 argv++; 3228 3229 unspec_src = B_FALSE; 3230 3231 ALLOC_ADDR_EXT(src, SADB_EXT_ADDRESS_SRC); 3232 3233 if (srchp == &dummy.he) { 3234 /* 3235 * Single address with -n flag. 3236 */ 3237 sin6 = (struct sockaddr_in6 *)(src + 1); 3238 bzero(sin6, sizeof (*sin6)); 3239 sin6->sin6_family = AF_INET6; 3240 bcopy(srchp->h_addr_list[0], &sin6->sin6_addr, 3241 sizeof (struct in6_addr)); 3242 } 3243 /* The rest is pre-bzeroed for us. */ 3244 break; 3245 case TOK_DSTADDR: 3246 case TOK_DSTADDR6: 3247 if (dst != NULL) { 3248 ERROR(ep, ebuf, gettext( 3249 "Can only specify single destination " 3250 "address.\n")); 3251 break; 3252 } 3253 sa_len = parseaddr(*argv, &dsthp, 3254 (token == TOK_SRCADDR6), ebuf); 3255 if (dsthp == NULL) { 3256 ERROR1(ep, ebuf, gettext( 3257 "Unknown destination address \"%s\"\n"), 3258 *argv); 3259 break; 3260 } 3261 argv++; 3262 3263 ALLOC_ADDR_EXT(dst, SADB_EXT_ADDRESS_DST); 3264 3265 if (dsthp == &dummy.he) { 3266 /* 3267 * Single address with -n flag. 3268 */ 3269 sin6 = (struct sockaddr_in6 *)(dst + 1); 3270 bzero(sin6, sizeof (*sin6)); 3271 sin6->sin6_family = AF_INET6; 3272 bcopy(dsthp->h_addr_list[0], &sin6->sin6_addr, 3273 sizeof (struct in6_addr)); 3274 } 3275 /* The rest is pre-bzeroed for us. */ 3276 break; 3277 case TOK_FLAG_INBOUND: 3278 sa_flags |= SADB_X_SAFLAGS_INBOUND; 3279 break; 3280 case TOK_FLAG_OUTBOUND: 3281 sa_flags |= SADB_X_SAFLAGS_OUTBOUND; 3282 break; 3283 default: 3284 ERROR2(ep, ebuf, gettext( 3285 "Don't use extension %s for '%s' command.\n"), 3286 *(argv - 1), thiscmd); 3287 break; 3288 } 3289 } while (token != TOK_EOF); 3290 3291 handle_errors(ep, ebuf, B_TRUE, B_FALSE); 3292 3293 if (assoc == NULL && satype != SADB_X_SATYPE_TCPSIG) { 3294 FATAL1(ep, ebuf, gettext( 3295 "Need SA parameters for %s.\n"), thiscmd); 3296 } 3297 3298 if (assoc != NULL) { 3299 /* We can set the flags now with valid assoc in hand. */ 3300 assoc->sadb_sa_flags |= sa_flags; 3301 } 3302 3303 if (srcport != 0) { 3304 if (src == NULL) { 3305 ALLOC_ADDR_EXT(src, SADB_EXT_ADDRESS_SRC); 3306 sin6 = (struct sockaddr_in6 *)(src + 1); 3307 src->sadb_address_proto = proto; 3308 bzero(sin6, sizeof (*sin6)); 3309 sin6->sin6_family = AF_INET6; 3310 } else { 3311 sin6 = (struct sockaddr_in6 *)(src + 1); 3312 } 3313 sin6->sin6_port = htons(srcport); 3314 } 3315 3316 if (dstport != 0) { 3317 if (dst == NULL) { 3318 ALLOC_ADDR_EXT(dst, SADB_EXT_ADDRESS_DST); 3319 sin6 = (struct sockaddr_in6 *)(dst + 1); 3320 src->sadb_address_proto = proto; 3321 bzero(sin6, sizeof (*sin6)); 3322 sin6->sin6_family = AF_INET6; 3323 } else { 3324 sin6 = (struct sockaddr_in6 *)(dst + 1); 3325 } 3326 sin6->sin6_port = htons(dstport); 3327 } 3328 3329 /* So I have enough of the message to send it down! */ 3330 msg->sadb_msg_len = nextext - get_buffer; 3331 3332 if (cflag) { 3333 /* 3334 * Assume the checked cmd would have worked if it was actually 3335 * used. doaddresses() will increment lines_added if it 3336 * succeeds. 3337 */ 3338 lines_added++; 3339 } else { 3340 doaddresses(sadb_msg_type, satype, 3341 cmd, srchp, dsthp, src, dst, unspec_src, get_buffer, 3342 sizeof (get_buffer), spi, NULL); 3343 } 3344 3345 if (srchp != NULL && srchp != &dummy.he) 3346 freehostent(srchp); 3347 if (dsthp != NULL && dsthp != &dummy.he) 3348 freehostent(dsthp); 3349 } 3350 3351 /* 3352 * "ipseckey monitor" should exit very gracefully if ^C is tapped provided 3353 * it is not running in interactive mode. 3354 */ 3355 static void 3356 monitor_catch(int signal) 3357 { 3358 if (!interactive) 3359 errx(signal, gettext("Bailing on signal %d."), signal); 3360 } 3361 3362 /* 3363 * Loop forever, listening on PF_KEY messages. 3364 */ 3365 static void 3366 domonitor(boolean_t passive) 3367 { 3368 struct sadb_msg *samsg; 3369 struct sigaction newsig, oldsig; 3370 int rc; 3371 3372 /* Catch ^C. */ 3373 newsig.sa_handler = monitor_catch; 3374 newsig.sa_flags = 0; 3375 (void) sigemptyset(&newsig.sa_mask); 3376 (void) sigaddset(&newsig.sa_mask, SIGINT); 3377 (void) sigaction(SIGINT, &newsig, &oldsig); 3378 3379 samsg = (struct sadb_msg *)get_buffer; 3380 if (!passive) { 3381 (void) printf(gettext("Actively")); 3382 msg_init(samsg, SADB_X_PROMISC, 1); /* Turn ON promisc. */ 3383 rc = key_write(keysock, samsg, sizeof (*samsg)); 3384 if (rc == -1) 3385 Bail("write (SADB_X_PROMISC)"); 3386 } else { 3387 (void) printf(gettext("Passively")); 3388 } 3389 (void) printf(gettext(" monitoring the PF_KEY socket.\n")); 3390 3391 for (; ; ) { 3392 /* 3393 * I assume that read() is non-blocking, and will never 3394 * return 0. 3395 */ 3396 rc = read(keysock, samsg, sizeof (get_buffer)); 3397 if (rc == -1) { 3398 if (errno == EINTR && interactive) 3399 goto out; 3400 else 3401 Bail("read (in domonitor)"); 3402 } 3403 (void) printf(gettext("Read %d bytes.\n"), rc); 3404 /* 3405 * Q: Should I use the same method of printing as GET does? 3406 * A: For now, yes. 3407 */ 3408 print_samsg(stdout, get_buffer, B_TRUE, vflag, nflag); 3409 (void) putchar('\n'); 3410 } 3411 3412 out: 3413 if (interactive) 3414 /* restore SIGINT behavior */ 3415 (void) sigaction(SIGINT, &oldsig, NULL); 3416 } 3417 3418 /* 3419 * Either mask or unmask all relevant signals. 3420 */ 3421 static void 3422 mask_signals(boolean_t unmask) 3423 { 3424 sigset_t set; 3425 static sigset_t oset; 3426 3427 if (unmask) { 3428 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 3429 } else { 3430 (void) sigfillset(&set); 3431 (void) sigprocmask(SIG_SETMASK, &set, &oset); 3432 } 3433 } 3434 3435 /* 3436 * Assorted functions to print help text. 3437 */ 3438 #define puts_tr(s) (void) puts(gettext(s)) 3439 3440 static void 3441 doattrhelp() 3442 { 3443 struct toktable *tp; 3444 int i; 3445 3446 puts_tr("\nSA attributes:"); 3447 3448 tp = tcpkey ? tcpkey_tokens : tokens; 3449 3450 for (i = 0; tp->string != NULL; tp++, i++) { 3451 if (i % 3 == 0) 3452 (void) printf("\n"); 3453 (void) printf(" %-15.15s", tp->string); 3454 } 3455 (void) printf("\n"); 3456 } 3457 3458 static void 3459 dohelpcmd(char *cmds) 3460 { 3461 int cmd; 3462 3463 if (strcmp(cmds, "attr") == 0) { 3464 doattrhelp(); 3465 return; 3466 } 3467 3468 cmd = parsecmd(cmds); 3469 switch (cmd) { 3470 case CMD_UPDATE: 3471 puts_tr("update - Update an existing SA"); 3472 break; 3473 case CMD_UPDATE_PAIR: 3474 puts_tr("update-pair - Update an existing pair of SAs"); 3475 break; 3476 case CMD_ADD: 3477 puts_tr("add - Add a new security association (SA)"); 3478 break; 3479 case CMD_DELETE: 3480 puts_tr("delete - Delete an SA"); 3481 break; 3482 case CMD_DELETE_PAIR: 3483 puts_tr("delete-pair - Delete a pair of SAs"); 3484 break; 3485 case CMD_GET: 3486 puts_tr("get - Display an SA"); 3487 break; 3488 case CMD_FLUSH: 3489 puts_tr("flush - Delete all SAs"); 3490 if (!tcpkey) { 3491 puts_tr(""); 3492 puts_tr("Optional arguments:"); 3493 puts_tr("all delete all SAs"); 3494 puts_tr("esp delete just ESP SAs"); 3495 puts_tr("ah delete just AH SAs"); 3496 puts_tr("<number> delete just SAs with type " 3497 "given by number"); 3498 puts_tr(""); 3499 } 3500 break; 3501 case CMD_DUMP: 3502 puts_tr("dump - Display all SAs"); 3503 if (!tcpkey) { 3504 puts_tr(""); 3505 puts_tr("Optional arguments:"); 3506 puts_tr("all display all SAs"); 3507 puts_tr("esp display just ESP SAs"); 3508 puts_tr("ah display just AH SAs"); 3509 puts_tr("<number> display just SAs with type " 3510 "given by number"); 3511 puts_tr(""); 3512 } 3513 break; 3514 case CMD_MONITOR: 3515 puts_tr("monitor - Monitor all PF_KEY reply messages."); 3516 break; 3517 case CMD_PMONITOR: 3518 puts_tr( 3519 "pmonitor, passive_monitor - Monitor PF_KEY messages that"); 3520 puts_tr( 3521 " reply to all PF_KEY sockets."); 3522 break; 3523 3524 case CMD_QUIT: 3525 puts_tr("quit, exit - Exit the program"); 3526 break; 3527 case CMD_SAVE: 3528 puts_tr("save - Saves all SAs to a file"); 3529 break; 3530 case CMD_HELP: 3531 puts_tr("help - Display list of commands"); 3532 puts_tr("help <cmd> - Display help for command"); 3533 puts_tr("help attr - Display possible SA attributes"); 3534 break; 3535 default: 3536 (void) printf(gettext("%s: Unknown command\n"), cmds); 3537 break; 3538 } 3539 } 3540 3541 static void 3542 dohelp_tcpkey(void) 3543 { 3544 puts_tr(""); 3545 puts_tr("The following commands are of the form:"); 3546 puts_tr(" <command> {SA type} {attribute value}*"); 3547 puts_tr(""); 3548 puts_tr("add (interactive only) - Add a new security association (SA)"); 3549 puts_tr("delete - Delete an SA"); 3550 puts_tr("get - Display an SA"); 3551 puts_tr("flush - Delete all SAs"); 3552 puts_tr("dump - Display all SAs"); 3553 puts_tr("save - Saves all SAs to a file"); 3554 } 3555 3556 static void 3557 dohelp(char *cmds) 3558 { 3559 if (cmds != NULL) { 3560 dohelpcmd(cmds); 3561 return; 3562 } 3563 puts_tr("Commands"); 3564 puts_tr("--------"); 3565 puts_tr("?, help - Display this list"); 3566 puts_tr("help <cmd> - Display help for command"); 3567 puts_tr("help attr - Display possible SA attributes"); 3568 puts_tr("quit, exit - Exit the program"); 3569 3570 if (tcpkey) { 3571 dohelp_tcpkey(); 3572 return; 3573 } 3574 3575 puts_tr("monitor - Monitor all PF_KEY reply messages."); 3576 puts_tr("pmonitor, passive_monitor - Monitor PF_KEY messages that"); 3577 puts_tr(" reply to all PF_KEY sockets."); 3578 puts_tr(""); 3579 puts_tr("The following commands are of the form:"); 3580 puts_tr(" <command> {SA type} {attribute value}*"); 3581 puts_tr(""); 3582 puts_tr("add (interactive only) - Add a new security association (SA)"); 3583 puts_tr("update (interactive only) - Update an existing SA"); 3584 puts_tr("update-pair (interactive only) - Update an existing SA pair"); 3585 puts_tr("delete - Delete an SA"); 3586 puts_tr("delete-pair - Delete an SA pair"); 3587 puts_tr("get - Display an SA"); 3588 puts_tr("flush - Delete all SAs"); 3589 puts_tr("dump - Display all SAs"); 3590 puts_tr("save - Saves all SAs to a file"); 3591 } 3592 3593 /* 3594 * "Parse" a command line from argv. 3595 */ 3596 static void 3597 parseit(int argc, char *argv[], char *ebuf, boolean_t read_cmdfile) 3598 { 3599 int cmd, satype; 3600 char *cmdstr; 3601 char *ep = NULL; 3602 3603 if (argc == 0) 3604 return; 3605 cmdstr = argv[0]; 3606 cmd = parsecmd(*argv++); 3607 3608 /* 3609 * Some commands loop forever and should only be run from the command 3610 * line, they should never be run from a command file as this may 3611 * be used at boot time. 3612 */ 3613 switch (cmd) { 3614 case CMD_HELP: 3615 if (read_cmdfile) 3616 ERROR(ep, ebuf, gettext("Help not appropriate in " 3617 "config file.")); 3618 else 3619 dohelp(*argv); 3620 return; 3621 case CMD_MONITOR: 3622 if (read_cmdfile) 3623 ERROR(ep, ebuf, gettext("Monitor not appropriate in " 3624 "config file.")); 3625 else { 3626 domonitor(B_FALSE); 3627 /* 3628 * Return from the function in interactive mode to 3629 * avoid error message in the next switch statement. 3630 * Also print newline to prevent prompt clobbering. 3631 * The same is done for CMD_PMONITOR. 3632 */ 3633 if (interactive) { 3634 (void) printf("\n"); 3635 return; 3636 } 3637 } 3638 break; 3639 case CMD_PMONITOR: 3640 if (read_cmdfile) 3641 ERROR(ep, ebuf, gettext("Monitor not appropriate in " 3642 "config file.")); 3643 else { 3644 domonitor(B_TRUE); 3645 if (interactive) { 3646 (void) printf("\n"); 3647 return; 3648 } 3649 } 3650 break; 3651 case CMD_QUIT: 3652 EXIT_OK(NULL); 3653 } 3654 3655 handle_errors(ep, ebuf, B_FALSE, B_FALSE); 3656 3657 if (tcpkey) { 3658 satype = SADB_X_SATYPE_TCPSIG; 3659 } else { 3660 satype = parsesatype(*argv, ebuf); 3661 if (satype != SADB_SATYPE_UNSPEC) { 3662 argv++; 3663 } else { 3664 /* 3665 * You must specify either "all" or a specific SA type 3666 * for the "save" command. 3667 */ 3668 if (cmd == CMD_SAVE) { 3669 if (*argv == NULL) { 3670 FATAL(ep, ebuf, gettext( 3671 "Must specify a specific " 3672 "SA type for save.\n")); 3673 } else { 3674 argv++; 3675 } 3676 } 3677 } 3678 } 3679 3680 switch (cmd) { 3681 case CMD_FLUSH: 3682 if (argc > 2) { 3683 ERROR(ep, ebuf, gettext("Too many arguments for " 3684 "flush command")); 3685 handle_errors(ep, ebuf, 3686 interactive ? B_TRUE : B_FALSE, B_FALSE); 3687 } 3688 if (!cflag) 3689 doflush(satype); 3690 /* 3691 * If this was called because of an entry in a cmd file 3692 * then this action needs to be counted to prevent 3693 * do_interactive() treating this as an error. 3694 */ 3695 lines_added++; 3696 break; 3697 case CMD_ADD: 3698 case CMD_UPDATE: 3699 case CMD_UPDATE_PAIR: 3700 /* 3701 * NOTE: Shouldn't allow ADDs or UPDATEs with keying material 3702 * from the command line. 3703 */ 3704 if (!interactive) { 3705 errx(1, gettext( 3706 "can't do ADD or UPDATE from the command line.\n")); 3707 } 3708 if (satype == SADB_SATYPE_UNSPEC) { 3709 FATAL(ep, ebuf, gettext( 3710 "Must specify a specific SA type.")); 3711 /* NOTREACHED */ 3712 } 3713 /* Parse for extensions, including keying material. */ 3714 doaddup(cmd, satype, argv, ebuf); 3715 break; 3716 case CMD_DELETE: 3717 case CMD_DELETE_PAIR: 3718 case CMD_GET: 3719 if (satype == SADB_SATYPE_UNSPEC) { 3720 FATAL(ep, ebuf, gettext( 3721 "Must specify a single SA type.")); 3722 /* NOTREACHED */ 3723 } 3724 /* Parse for bare minimum to locate an SA. */ 3725 dodelget(cmd, satype, argv, ebuf); 3726 break; 3727 case CMD_DUMP: 3728 if (read_cmdfile) 3729 ERROR(ep, ebuf, gettext("Dump not appropriate in " 3730 "config file.")); 3731 else { 3732 if (argc > 2) { 3733 ERROR(ep, ebuf, gettext("Too many arguments " 3734 "for dump command")); 3735 handle_errors(ep, ebuf, 3736 interactive ? B_TRUE : B_FALSE, B_FALSE); 3737 } 3738 dodump(satype, NULL); 3739 } 3740 break; 3741 case CMD_SAVE: 3742 if (read_cmdfile) { 3743 ERROR(ep, ebuf, gettext("Save not appropriate in " 3744 "config file.")); 3745 } else { 3746 mask_signals(B_FALSE); /* Mask signals */ 3747 dodump(satype, opensavefile(argv[0])); 3748 mask_signals(B_TRUE); /* Unmask signals */ 3749 } 3750 break; 3751 default: 3752 warnx(gettext("Unknown command (%s).\n"), cmdstr); 3753 usage(); 3754 } 3755 handle_errors(ep, ebuf, B_FALSE, B_FALSE); 3756 } 3757 3758 int 3759 main(int argc, char *argv[]) 3760 { 3761 int ch; 3762 FILE *infile = stdin, *savefile; 3763 boolean_t dosave = B_FALSE, readfile = B_FALSE; 3764 char *configfile = NULL; 3765 struct stat sbuf; 3766 int bootflags; 3767 int satype = SADB_SATYPE_UNSPEC; 3768 char *prompt = "ipseckey> "; 3769 3770 (void) setlocale(LC_ALL, ""); 3771 #if !defined(TEXT_DOMAIN) 3772 #define TEXT_DOMAIN "SYS_TEST" 3773 #endif 3774 (void) textdomain(TEXT_DOMAIN); 3775 3776 /* 3777 * Check to see if the command is being run from smf(7). 3778 */ 3779 my_fmri = getenv("SMF_FMRI"); 3780 3781 /* 3782 * Check to see if the command is being run as tcpkey(8). If it is we 3783 * will expose a more limited interface and only manage the TCPSIG 3784 * SADB. 3785 */ 3786 progname = getprogname(); 3787 tcpkey = strcmp(progname, "tcpkey") == 0; 3788 3789 if (tcpkey) { 3790 satype = SADB_X_SATYPE_TCPSIG; 3791 prompt = "tcpkey> "; 3792 } 3793 3794 openlog(progname, LOG_CONS, LOG_AUTH); 3795 if (!priv_ineffect(PRIV_SYS_IP_CONFIG)) 3796 errx(1, "Insufficient privileges to run %s.", progname); 3797 3798 /* umask me to paranoid, I only want to create files read-only */ 3799 (void) umask((mode_t)00377); 3800 3801 while ((ch = getopt(argc, argv, "pnvf:s:c:")) != EOF) 3802 switch (ch) { 3803 case 'p': 3804 pflag = B_TRUE; 3805 break; 3806 case 'n': 3807 nflag = B_TRUE; 3808 break; 3809 case 'v': 3810 vflag = B_TRUE; 3811 break; 3812 case 'c': 3813 cflag = B_TRUE; 3814 /* FALLTHRU */ 3815 case 'f': 3816 if (dosave) 3817 usage(); 3818 3819 /* 3820 * Use stat() to check and see if the user inadvertently 3821 * passed in a bad pathname, or the name of a directory. 3822 * We should also check to see if the filename is a 3823 * pipe. We use stat() here because fopen() will block 3824 * unless the other end of the pipe is open. This would 3825 * be undesirable, especially if this is called at boot 3826 * time. If we ever need to support reading from a pipe 3827 * or special file, this should be revisited. 3828 */ 3829 if (stat(optarg, &sbuf) == -1) { 3830 EXIT_BADCONFIG2("Invalid pathname: %s\n", 3831 optarg); 3832 } 3833 if (!(sbuf.st_mode & S_IFREG)) { 3834 EXIT_BADCONFIG2("%s - Not a regular file\n", 3835 optarg); 3836 } 3837 infile = fopen(optarg, "r"); 3838 if (infile == NULL) { 3839 EXIT_BADCONFIG2("Unable to open configuration " 3840 "file: %s\n", optarg); 3841 } 3842 /* 3843 * The input file contains keying information, because 3844 * this is sensitive, we should only accept data from 3845 * this file if the file is root owned and only readable 3846 * by privileged users. If the command is being run by 3847 * the administrator, issue a warning, if this is run by 3848 * smf(7) (IE: boot time) and the permissions are too 3849 * open, we will fail, the SMF service will end up in 3850 * maintenace mode. The check is made with fstat() to 3851 * eliminate any possible TOT to TOU window. 3852 */ 3853 if (fstat(fileno(infile), &sbuf) == -1) { 3854 (void) fclose(infile); 3855 EXIT_BADCONFIG2("Unable to stat configuration " 3856 "file: %s\n", optarg); 3857 } 3858 if (INSECURE_PERMS(sbuf)) { 3859 if (my_fmri != NULL) { 3860 (void) fclose(infile); 3861 EXIT_BADCONFIG2("Config file " 3862 "%s has insecure permissions.", 3863 optarg); 3864 } else { 3865 (void) fprintf(stderr, gettext( 3866 "Config file %s has insecure " 3867 "permissions, will be rejected in " 3868 "permanent config.\n"), optarg); 3869 } 3870 } 3871 configfile = strdup(optarg); 3872 readfile = B_TRUE; 3873 break; 3874 case 's': 3875 if (readfile) 3876 usage(); 3877 dosave = B_TRUE; 3878 savefile = opensavefile(optarg); 3879 break; 3880 default: 3881 usage(); 3882 } 3883 3884 argc -= optind; 3885 argv += optind; 3886 3887 mypid = getpid(); 3888 3889 keysock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); 3890 3891 if (keysock == -1) { 3892 if (errno == EPERM) { 3893 EXIT_BADPERM("Insufficient privileges to open " 3894 "PF_KEY socket.\n"); 3895 } else { 3896 /* some other reason */ 3897 EXIT_FATAL("Opening PF_KEY socket"); 3898 } 3899 } 3900 3901 if ((_cladm(CL_INITIALIZE, CL_GET_BOOTFLAG, &bootflags) != 0) || 3902 (bootflags & CLUSTER_BOOTED)) { 3903 in_cluster_mode = B_TRUE; 3904 cluster_socket = socket(AF_INET, SOCK_DGRAM, 0); 3905 cli_addr.sin_family = AF_INET; 3906 cli_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3907 cli_addr.sin_port = htons(CLUSTER_UDP_PORT); 3908 } 3909 3910 if (dosave) { 3911 mask_signals(B_FALSE); /* Mask signals */ 3912 dodump(satype, savefile); 3913 mask_signals(B_TRUE); /* Unmask signals */ 3914 EXIT_OK(NULL); 3915 } 3916 3917 /* 3918 * When run from smf(7) flush any existing SAs first 3919 * otherwise you will end up in maintenance mode. 3920 */ 3921 if (my_fmri != NULL && readfile) { 3922 (void) fprintf(stdout, gettext( 3923 "Flushing existing SAs before adding new SAs\n")); 3924 (void) fflush(stdout); 3925 doflush(satype); 3926 } 3927 if (infile != stdin || argc == 0) { 3928 /* Go into interactive mode here. */ 3929 do_interactive(infile, configfile, prompt, my_fmri, 3930 parseit, no_match); 3931 } 3932 parseit(argc, argv, NULL, B_FALSE); 3933 3934 return (0); 3935 } 3936