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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <strings.h> 32 #include <stropts.h> 33 #include <fcntl.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <arpa/inet.h> 39 #include <locale.h> 40 #include <syslog.h> 41 #include <pwd.h> 42 #include <sys/param.h> 43 #include <sys/sysmacros.h> /* MIN, MAX */ 44 #include <sys/sockio.h> 45 #include <net/pfkeyv2.h> 46 #include <net/pfpolicy.h> 47 #include <inet/ipsec_impl.h> 48 #include <signal.h> 49 #include <errno.h> 50 #include <netdb.h> 51 #include <sys/socket.h> 52 #include <sys/systeminfo.h> 53 #include <nss_dbdefs.h> /* NSS_BUFLEN_HOSTS */ 54 #include <netinet/in.h> 55 #include <assert.h> 56 #include <inet/ip.h> 57 #include <ipsec_util.h> 58 #include <netinet/in_systm.h> 59 #include <netinet/ip_icmp.h> 60 #include <netinet/icmp6.h> 61 62 /* 63 * Globals 64 */ 65 int lfd; 66 char *my_fmri; 67 FILE *debugfile = stderr; 68 69 #define USAGE() if (!smf_managed) usage() 70 /* 71 * Buffer length to read in pattern/properties. 72 */ 73 #define MAXLEN 1024 74 75 /* Max length of tunnel interface string identifier */ 76 #define TUNNAMEMAXLEN LIFNAMSIZ 77 78 /* 79 * Used by parse_one and parse/parse_action to communicate 80 * the errors. -1 is failure, which is not defined here. 81 */ 82 enum parse_errors {PARSE_SUCCESS, PARSE_EOF}; 83 84 /* 85 * For spdsock_get_ext() diagnostics. 86 */ 87 #define SPDSOCK_DIAG_BUF_LEN 128 88 static char spdsock_diag_buf[SPDSOCK_DIAG_BUF_LEN]; 89 90 /* 91 * Define CURL here so that while you are reading 92 * this code, it does not affect "vi" in pattern 93 * matching. 94 */ 95 #define CURL_BEGIN '{' 96 #define CURL_END '}' 97 #define MAXARGS 20 98 #define NOERROR 0 99 100 /* 101 * IPSEC_CONF_ADD should start with 1, so that when multiple commands 102 * are given, we can fail the request. 103 */ 104 105 enum ipsec_cmds {IPSEC_CONF_ADD = 1, IPSEC_CONF_DEL, IPSEC_CONF_VIEW, 106 IPSEC_CONF_FLUSH, IPSEC_CONF_LIST, IPSEC_CONF_SUB}; 107 108 static const char policy_conf_file[] = "/var/run/ipsecpolicy.conf"; 109 static const char lock_file[] = "/var/run/ipsecconf.lock"; 110 static const char index_tag[] = "#INDEX"; 111 112 #define POLICY_CONF_FILE policy_conf_file 113 #define LOCK_FILE lock_file 114 #define INDEX_TAG index_tag 115 116 /* 117 * Valid algorithm length. 118 */ 119 #define VALID_ALG_LEN 40 120 121 /* Types of Error messages */ 122 typedef enum error_type {BAD_ERROR, DUP_ERROR, REQ_ERROR} error_type_t; 123 124 /* Error message human readable conversions */ 125 static char *sys_error_message(int); 126 static void error_message(error_type_t, int, int); 127 static int get_pf_pol_socket(void); 128 129 static int cmd; 130 static char *filename; 131 static char lo_buf[MAXLEN]; /* Leftover buffer */ 132 133 /* 134 * The new SPD_EXT_TUN_NAME extension has a tunnel name in it. Use the empty 135 * string ("", stored in the char value "all_polheads") for all policy heads 136 * (global and all tunnels). Set interface_name to NULL for global-only, or 137 * specify a name of an IP-in-IP tunnel. 138 */ 139 static char *interface_name; 140 static char all_polheads; /* So we can easily get "". */ 141 142 /* Error reporting stuff */ 143 #define CBUF_LEN 4096 /* Maximum size of the cmd */ 144 /* 145 * Following are used for reporting errors with arguments. 146 * We store the line numbers of each argument as we parse them, 147 * so that the error reporting is more specific. We can have only 148 * MAXARGS -1 for pattern and properties and one for action. 149 */ 150 #define ARG_BUF_LEN ((2 * (MAXARGS - 1)) + 1) 151 static int arg_indices[ARG_BUF_LEN]; 152 static int argindex; 153 static int linecount; 154 static char cbuf[CBUF_LEN]; /* Command buffer */ 155 static int cbuf_offset; 156 157 158 #define BYPASS_POLICY_BOOST 0x00800000 159 #define ESP_POLICY_BOOST 0x00400000 160 #define AH_POLICY_BOOST 0x00200000 161 #define INITIAL_BASE_PRIORITY 0x000fffff 162 163 /* 164 * the number used to order the 165 * rules starts at a certain base and 166 * goes down. i.e. rules earlier in 167 * the file are checked first 168 */ 169 static uint32_t priority = INITIAL_BASE_PRIORITY; 170 171 #define AH_AUTH 0 172 #define ESP_ENCR 1 173 #define ESP_AUTH 2 174 175 176 /* 177 * for deleting adds on error 178 */ 179 180 typedef struct d_list_s 181 { 182 struct d_list_s *next; 183 int index; 184 } d_list_t; 185 186 static d_list_t *d_list = NULL; 187 static d_list_t *d_tail = NULL; 188 189 190 /* 191 * Used for multi-homed source/dest hosts. 192 */ 193 static struct hostent *shp, *dhp; 194 static unsigned int splen, dplen; 195 static char tunif[TUNNAMEMAXLEN]; 196 static boolean_t has_saprefix, has_daprefix; 197 static uint32_t seq_cnt = 0; 198 199 /* lexxed out action and related properties */ 200 typedef struct ap_s 201 { 202 char *act; 203 char *prop[MAXARGS + 1]; 204 } ap_t; 205 206 207 /* one lexxed out rule */ 208 typedef struct act_prop_s { 209 char *pattern[MAXARGS+1]; 210 ap_t ap[MAXARGS + 1]; 211 } act_prop_t; 212 213 typedef struct 214 { 215 uint8_t alg_id; 216 uint32_t alg_minbits; 217 uint32_t alg_maxbits; 218 } algreq_t; 219 220 /* structure to hold all information for one act_prop_t */ 221 typedef struct ips_act_props_s { 222 struct ips_act_props_s *iap_next; 223 struct ips_conf_s *iap_head; 224 225 /* 226 * IPsec action types (in SPD_ATTR_TYPE attribute) 227 * SPD_ACTTYPE_DROP 0x0001 228 * SPD_ACTTYPE_PASS 0x0002 229 * SPD_ACTTYPE_IPSEC 0x0003 230 */ 231 uint16_t iap_action; 232 uint16_t iap_act_tok; 233 234 /* 235 * Action ATTR flags (in SPD_ATTR_FLAGS attribute) 236 * SPD_APPLY_AH 0x0001 237 * SPD_APPLY_ESP 0x0002 238 * SPD_APPLY_SE 0x0004 * self-encapsulation * 239 * SPD_APPLY_COMP 0x0008 * compression; NYI * 240 * SPD_APPLY_UNIQUE 0x0010 * unique per-flow SA * 241 * SPD_APPLY_BYPASS 0x0020 * bypass policy * 242 */ 243 uint16_t iap_attr; 244 uint16_t iap_attr_tok[5]; 245 246 algreq_t iap_aauth; 247 algreq_t iap_eencr; 248 algreq_t iap_eauth; 249 250 uint32_t iap_life_soft_time; 251 uint32_t iap_life_hard_time; 252 uint32_t iap_life_soft_bytes; 253 uint32_t iap_life_hard_bytes; 254 255 } ips_act_props_t; 256 257 #define V4_PART_OF_V6(v6) v6._S6_un._S6_u32[3] 258 259 typedef struct ips_conf_s { 260 /* selector */ 261 uint16_t patt_tok[8]; 262 uint8_t has_saddr; 263 uint8_t has_daddr; 264 uint8_t has_smask; 265 uint8_t has_dmask; 266 uint8_t has_type; 267 uint8_t has_code; 268 uint8_t has_negotiate; 269 uint8_t has_tunnel; 270 uint16_t swap; 271 272 struct in6_addr ips_src_addr_v6; 273 struct in6_addr ips_src_mask_v6; 274 struct in6_addr ips_dst_addr_v6; 275 struct in6_addr ips_dst_mask_v6; 276 uint8_t ips_src_mask_len; 277 uint8_t ips_dst_mask_len; 278 in_port_t ips_src_port_min; 279 in_port_t ips_src_port_max; 280 in_port_t ips_dst_port_min; 281 in_port_t ips_dst_port_max; 282 uint8_t ips_icmp_type; 283 uint8_t ips_icmp_type_end; 284 uint8_t ips_icmp_code; 285 uint8_t ips_icmp_code_end; 286 uint8_t ips_ulp_prot; 287 uint8_t ips_ipsec_prot; 288 uint8_t ips_isv4; 289 /* 290 * SPD_RULE_FLAG_INBOUND 0x0001 291 * SPD_RULE_FLAG_OUTBOUND 0x0002 292 */ 293 uint8_t ips_dir; 294 /* 295 * Keep track of tunnel separately due to explosion of ways to set 296 * inbound/outbound. 297 */ 298 boolean_t ips_tunnel; 299 uint64_t ips_policy_index; 300 uint32_t ips_act_cnt; 301 ips_act_props_t *ips_acts; 302 } ips_conf_t; 303 304 #define ips_src_addr V4_PART_OF_V6(ips_src_addr_v6) 305 #define ips_dst_addr V4_PART_OF_V6(ips_dst_addr_v6) 306 307 static int ipsecconf_nflag; /* Used only with -l option */ 308 static int ipsecconf_qflag; /* Used only with -a|-r option */ 309 310 typedef struct str_val { 311 const char *string; 312 int value; 313 } str_val_t; 314 315 typedef struct str_tval { 316 const char *string; 317 int tok_val; 318 int value; 319 } str_tval_t; 320 321 static int parse_int(const char *); 322 static int parse_index(const char *, char *); 323 static int attach_tunname(spd_if_t *); 324 static void usage(void); 325 static int ipsec_conf_del(int, boolean_t); 326 static int ipsec_conf_add(boolean_t, boolean_t); 327 static int ipsec_conf_sub(void); 328 static int ipsec_conf_flush(int); 329 static int ipsec_conf_view(void); 330 static int ipsec_conf_list(void); 331 static int lock(void); 332 static int unlock(int); 333 static int parse_one(FILE *, act_prop_t *); 334 static void reconfigure(); 335 static void in_prefixlentomask(unsigned int, uchar_t *); 336 static int in_getprefixlen(char *); 337 static int parse_address(int, char *); 338 #ifdef DEBUG_HEAVY 339 static void pfpol_msg_dump(spd_msg_t *msg, char *); 340 #endif /* DEBUG_HEAVY */ 341 static void print_pfpol_msg(spd_msg_t *); 342 static int pfp_delete_rule(uint64_t); 343 static void ipsec_conf_admin(uint8_t); 344 static void print_bit_range(int, int); 345 static void nuke_adds(); 346 347 #ifdef DEBUG 348 static void dump_conf(ips_conf_t *); 349 #endif 350 351 typedef struct 352 { 353 uint32_t id; 354 uint32_t minkeybits; 355 uint32_t maxkeybits; 356 uint32_t defkeybits; 357 uint32_t incr; 358 } alginfo_t; 359 360 static int ipsec_nalgs[3]; 361 static alginfo_t known_algs[3][256]; 362 363 #define IPS_SRC_MASK SPD_EXT_LCLADDR + 100 364 #define IPS_DST_MASK SPD_EXT_REMADDR + 100 365 366 /* 367 * if inbound, src=remote, dst=local 368 * if outbound, src=local, dst=remote 369 */ 370 371 #define TOK_saddr 1 372 #define TOK_daddr 2 373 #define TOK_sport 3 374 #define TOK_dport 4 375 #define TOK_smask 5 376 #define TOK_dmask 6 377 #define TOK_ulp 7 378 #define TOK_local 8 379 #define TOK_lport 9 380 #define TOK_remote 10 381 #define TOK_rport 11 382 #define TOK_dir 12 383 #define TOK_type 13 384 #define TOK_code 14 385 #define TOK_negotiate 15 386 #define TOK_tunnel 16 387 388 #define IPS_SA SPD_ATTR_END 389 #define IPS_DIR SPD_ATTR_EMPTY 390 #define IPS_NEG SPD_ATTR_NOP 391 392 393 static str_tval_t pattern_table[] = { 394 {"saddr", TOK_saddr, SPD_EXT_LCLADDR}, 395 {"src", TOK_saddr, SPD_EXT_LCLADDR}, 396 {"srcaddr", TOK_saddr, SPD_EXT_LCLADDR}, 397 {"daddr", TOK_daddr, SPD_EXT_REMADDR}, 398 {"dst", TOK_daddr, SPD_EXT_REMADDR}, 399 {"dstaddr", TOK_daddr, SPD_EXT_REMADDR}, 400 {"sport", TOK_sport, SPD_EXT_LCLPORT}, 401 {"dport", TOK_dport, SPD_EXT_REMPORT}, 402 {"smask", TOK_smask, IPS_SRC_MASK}, 403 {"dmask", TOK_dmask, IPS_DST_MASK}, 404 {"ulp", TOK_ulp, SPD_EXT_PROTO}, 405 {"proto", TOK_ulp, SPD_EXT_PROTO}, 406 {"local", TOK_local, SPD_EXT_LCLADDR}, 407 {"laddr", TOK_local, SPD_EXT_LCLADDR}, 408 {"lport", TOK_lport, SPD_EXT_LCLPORT}, 409 {"remote", TOK_remote, SPD_EXT_REMADDR}, 410 {"raddr", TOK_remote, SPD_EXT_REMADDR}, 411 {"rport", TOK_rport, SPD_EXT_REMPORT}, 412 {"dir", TOK_dir, IPS_DIR}, 413 {"type", TOK_type, SPD_EXT_ICMP_TYPECODE}, 414 {"code", TOK_code, SPD_EXT_ICMP_TYPECODE}, 415 {"negotiate", TOK_negotiate, IPS_NEG}, 416 {"tunnel", TOK_tunnel, SPD_EXT_TUN_NAME}, 417 {NULL, 0, 0}, 418 }; 419 420 #define TOK_apply 1 421 #define TOK_permit 2 422 #define TOK_ipsec 3 423 #define TOK_bypass 4 424 #define TOK_drop 5 425 #define TOK_or 6 426 427 static str_tval_t action_table[] = { 428 {"apply", TOK_apply, SPD_ACTTYPE_IPSEC}, 429 {"permit", TOK_permit, SPD_ACTTYPE_IPSEC}, 430 {"ipsec", TOK_ipsec, SPD_ACTTYPE_IPSEC}, 431 {"bypass", TOK_bypass, SPD_ACTTYPE_PASS}, 432 {"pass", TOK_bypass, SPD_ACTTYPE_PASS}, 433 {"drop", TOK_drop, SPD_ACTTYPE_DROP}, 434 {"or", TOK_or, 0}, 435 {NULL, 0, 0}, 436 }; 437 438 static str_val_t property_table[] = { 439 {"auth_algs", SPD_ATTR_AH_AUTH}, 440 {"encr_algs", SPD_ATTR_ESP_ENCR}, 441 {"encr_auth_algs", SPD_ATTR_ESP_AUTH}, 442 {"sa", IPS_SA}, 443 {"dir", IPS_DIR}, 444 {NULL, 0}, 445 }; 446 447 static str_val_t icmp_type_table[] = { 448 {"unreach", ICMP_UNREACH}, 449 {"echo", ICMP_ECHO}, 450 {"echorep", ICMP_ECHOREPLY}, 451 {"squench", ICMP_SOURCEQUENCH}, 452 {"redir", ICMP_REDIRECT}, 453 {"timex", ICMP_TIMXCEED}, 454 {"paramprob", ICMP_PARAMPROB}, 455 {"timest", ICMP_TSTAMP}, 456 {"timestrep", ICMP_TSTAMPREPLY}, 457 {"inforeq", ICMP_IREQ}, 458 {"inforep", ICMP_IREQREPLY}, 459 {"maskreq", ICMP_MASKREQ}, 460 {"maskrep", ICMP_MASKREPLY}, 461 {"unreach6", ICMP6_DST_UNREACH}, 462 {"pkttoobig6", ICMP6_PACKET_TOO_BIG}, 463 {"timex6", ICMP6_TIME_EXCEEDED}, 464 {"paramprob6", ICMP6_PARAM_PROB}, 465 {"echo6", ICMP6_ECHO_REQUEST}, 466 {"echorep6", ICMP6_ECHO_REPLY}, 467 {"router-sol6", ND_ROUTER_SOLICIT}, 468 {"router-ad6", ND_ROUTER_ADVERT}, 469 {"neigh-sol6", ND_NEIGHBOR_SOLICIT}, 470 {"neigh-ad6", ND_NEIGHBOR_ADVERT}, 471 {"redir6", ND_REDIRECT}, 472 {NULL, 0}, 473 }; 474 475 static str_val_t icmp_code_table[] = { 476 {"net-unr", ICMP_UNREACH_NET}, 477 {"host-unr", ICMP_UNREACH_HOST}, 478 {"proto-unr", ICMP_UNREACH_PROTOCOL}, 479 {"port-unr", ICMP_UNREACH_PORT}, 480 {"needfrag", ICMP_UNREACH_NEEDFRAG}, 481 {"srcfail", ICMP_UNREACH_SRCFAIL}, 482 {"net-unk", ICMP_UNREACH_NET_UNKNOWN}, 483 {"host-unk", ICMP_UNREACH_HOST_UNKNOWN}, 484 {"isolate", ICMP_UNREACH_ISOLATED}, 485 {"net-prohib", ICMP_UNREACH_NET_PROHIB}, 486 {"host-prohib", ICMP_UNREACH_HOST_PROHIB}, 487 {"net-tos", ICMP_UNREACH_TOSNET}, 488 {"host-tos", ICMP_UNREACH_TOSHOST}, 489 {"filter-prohib", ICMP_UNREACH_FILTER_PROHIB}, 490 {"host-preced", ICMP_UNREACH_HOST_PRECEDENCE}, 491 {"cutoff-preced", ICMP_UNREACH_PRECEDENCE_CUTOFF}, 492 {"no-route6", ICMP6_DST_UNREACH_NOROUTE}, 493 {"adm-prohib6", ICMP6_DST_UNREACH_ADMIN}, 494 {"addr-unr6", ICMP6_DST_UNREACH_ADDR}, 495 {"port-unr6", ICMP6_DST_UNREACH_NOPORT}, 496 {"hop-limex6", ICMP6_TIME_EXCEED_TRANSIT}, 497 {"frag-re-timex6", ICMP6_TIME_EXCEED_REASSEMBLY}, 498 {"err-head6", ICMP6_PARAMPROB_HEADER}, 499 {"unrec-head6", ICMP6_PARAMPROB_NEXTHEADER}, 500 {"unreq-opt6", ICMP6_PARAMPROB_OPTION}, 501 {NULL, 0}, 502 }; 503 504 static sigset_t set, oset; 505 506 507 static boolean_t 508 add_index(int index) 509 { 510 d_list_t *temp = malloc(sizeof (d_list_t)); 511 512 if (temp == NULL) { 513 warn("malloc"); 514 return (B_TRUE); 515 } 516 517 temp->index = index; 518 temp->next = NULL; 519 520 if (d_tail == NULL) { 521 d_list = d_tail = temp; 522 return (B_FALSE); 523 } 524 525 d_tail->next = temp; 526 d_tail = temp; 527 528 return (B_FALSE); 529 } 530 531 static int 532 block_all_signals() 533 { 534 if (sigfillset(&set) == -1) { 535 warn("sigfillset"); 536 return (-1); 537 } 538 if (sigprocmask(SIG_SETMASK, &set, &oset) == -1) { 539 warn("sigprocmask"); 540 return (-1); 541 } 542 return (0); 543 } 544 545 static int 546 restore_all_signals() 547 { 548 if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) { 549 warn("sigprocmask"); 550 return (-1); 551 } 552 return (0); 553 } 554 555 /* allocate an ips_act_props_t and link it in correctly */ 556 static ips_act_props_t * 557 alloc_iap(ips_conf_t *parent) 558 { 559 ips_act_props_t *ret; 560 ips_act_props_t *next = parent->ips_acts; 561 ips_act_props_t *current = NULL; 562 563 ret = (ips_act_props_t *)calloc(sizeof (ips_act_props_t), 1); 564 565 if (ret == NULL) 566 return (NULL); 567 568 ret->iap_head = parent; 569 570 while (next != NULL) { 571 current = next; 572 next = next->iap_next; 573 } 574 575 if (current != NULL) 576 current->iap_next = ret; 577 else 578 parent->ips_acts = ret; 579 580 parent->ips_act_cnt++; 581 582 return (ret); 583 } 584 585 /* 586 * This function exit()s if it fails. 587 */ 588 static void 589 fetch_algorithms() 590 { 591 struct spd_msg msg; 592 struct spd_ext_actions *actp; 593 struct spd_attribute *attr, *endattr; 594 spd_ext_t *exts[SPD_EXT_MAX+1]; 595 uint64_t reply_buf[256]; 596 int sfd; 597 int cnt, retval; 598 uint64_t *start, *end; 599 alginfo_t alg = {0, 0, 0, 0, 0}; 600 uint_t algtype; 601 static boolean_t has_run = B_FALSE; 602 603 if (has_run) 604 return; 605 else 606 has_run = B_TRUE; 607 608 sfd = get_pf_pol_socket(); 609 if (sfd < 0) { 610 err(-1, gettext("unable to open policy socket")); 611 } 612 613 (void) memset(&msg, 0, sizeof (msg)); 614 msg.spd_msg_version = PF_POLICY_V1; 615 msg.spd_msg_type = SPD_ALGLIST; 616 msg.spd_msg_len = SPD_8TO64(sizeof (msg)); 617 618 cnt = write(sfd, &msg, sizeof (msg)); 619 if (cnt != sizeof (msg)) { 620 if (cnt < 0) { 621 err(-1, gettext("alglist failed: write")); 622 } else { 623 errx(-1, gettext("alglist failed: short write")); 624 } 625 } 626 627 cnt = read(sfd, reply_buf, sizeof (reply_buf)); 628 629 retval = spdsock_get_ext(exts, (spd_msg_t *)reply_buf, SPD_8TO64(cnt), 630 spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN); 631 632 if (retval == KGE_LEN && exts[0]->spd_ext_len == 0) { 633 /* 634 * No algorithms are defined in the kernel, which caused 635 * the extension length to be zero, and spdsock_get_ext() 636 * to fail with a KGE_LEN error. This is not an error 637 * condition, so we return nicely. 638 */ 639 return; 640 } else if (retval != 0) { 641 if (strlen(spdsock_diag_buf) != 0) 642 warnx(spdsock_diag_buf); 643 err(1, gettext("fetch_algorithms failed")); 644 } 645 646 if (!exts[SPD_EXT_ACTION]) { 647 errx(1, gettext("fetch_algorithms: action missing?!")); 648 } 649 650 actp = (struct spd_ext_actions *)exts[SPD_EXT_ACTION]; 651 start = (uint64_t *)actp; 652 end = (start + actp->spd_actions_len); 653 endattr = (struct spd_attribute *)end; 654 attr = (struct spd_attribute *)&actp[1]; 655 656 algtype = 0; 657 658 while (attr < endattr) { 659 switch (attr->spd_attr_tag) { 660 case SPD_ATTR_NOP: 661 case SPD_ATTR_EMPTY: 662 break; 663 case SPD_ATTR_END: 664 attr = endattr; 665 /* FALLTHRU */ 666 case SPD_ATTR_NEXT: 667 known_algs[algtype][ipsec_nalgs[algtype]] = alg; 668 ipsec_nalgs[algtype]++; 669 break; 670 671 case SPD_ATTR_ENCR_MINBITS: 672 case SPD_ATTR_AH_MINBITS: 673 case SPD_ATTR_ESPA_MINBITS: 674 alg.minkeybits = attr->spd_attr_value; 675 break; 676 677 case SPD_ATTR_ENCR_MAXBITS: 678 case SPD_ATTR_AH_MAXBITS: 679 case SPD_ATTR_ESPA_MAXBITS: 680 alg.maxkeybits = attr->spd_attr_value; 681 break; 682 683 case SPD_ATTR_ENCR_DEFBITS: 684 case SPD_ATTR_AH_DEFBITS: 685 case SPD_ATTR_ESPA_DEFBITS: 686 alg.defkeybits = attr->spd_attr_value; 687 break; 688 689 case SPD_ATTR_ENCR_INCRBITS: 690 case SPD_ATTR_AH_INCRBITS: 691 case SPD_ATTR_ESPA_INCRBITS: 692 alg.incr = attr->spd_attr_value; 693 break; 694 695 case SPD_ATTR_AH_AUTH: 696 case SPD_ATTR_ESP_AUTH: 697 case SPD_ATTR_ESP_ENCR: 698 alg.id = attr->spd_attr_value; 699 algtype = attr->spd_attr_tag - SPD_ATTR_AH_AUTH; 700 break; 701 } 702 attr++; 703 } 704 705 (void) close(sfd); 706 } 707 708 /* data dependant transform (act_cnt) */ 709 #define ATTR(ap, tag, value) \ 710 do { (ap)->spd_attr_tag = (tag); \ 711 (ap)->spd_attr_value = (value); \ 712 ap++; } while (0) 713 714 static struct spd_attribute * 715 emit_alg(struct spd_attribute *ap, int type, const algreq_t *ar, 716 int algattr, int minbitattr, int maxbitattr) 717 { 718 int id = ar->alg_id; 719 int minbits, i; 720 721 if (id != 0) { 722 /* LINTED E_CONST_COND */ 723 ATTR(ap, algattr, ar->alg_id); 724 725 minbits = ar->alg_minbits; 726 if (minbits == 0) { 727 for (i = 0; i < ipsec_nalgs[type]; i++) { 728 if (known_algs[type][i].id == id) 729 break; 730 } 731 if (i < ipsec_nalgs[type]) 732 minbits = known_algs[type][i].defkeybits; 733 } 734 if (minbits != 0) 735 /* LINTED E_CONST_COND */ 736 ATTR(ap, minbitattr, minbits); 737 if (ar->alg_maxbits != SPD_MAX_MAXBITS) 738 /* LINTED E_CONST_COND */ 739 ATTR(ap, maxbitattr, ar->alg_maxbits); 740 } 741 742 return (ap); 743 } 744 745 746 747 static struct spd_attribute * 748 ips_act_props_to_action(struct spd_attribute *ap, uint32_t *rule_priorityp, 749 const ips_act_props_t *act_ptr) 750 { 751 uint32_t rule_priority = *rule_priorityp; 752 753 /* LINTED E_CONST_COND */ 754 ATTR(ap, SPD_ATTR_EMPTY, 0); 755 756 /* type */ 757 /* LINTED E_CONST_COND */ 758 ATTR(ap, SPD_ATTR_TYPE, act_ptr->iap_action); 759 760 if (act_ptr->iap_action == SPD_ACTTYPE_PASS) 761 rule_priority |= BYPASS_POLICY_BOOST; 762 763 /* flags */ 764 if (act_ptr->iap_attr != 0) 765 /* LINTED E_CONST_COND */ 766 ATTR(ap, SPD_ATTR_FLAGS, act_ptr->iap_attr); 767 768 /* esp */ 769 if (act_ptr->iap_attr & SPD_APPLY_ESP) { 770 rule_priority |= ESP_POLICY_BOOST; 771 772 /* encr */ 773 ap = emit_alg(ap, ESP_ENCR, &act_ptr->iap_eencr, 774 SPD_ATTR_ESP_ENCR, 775 SPD_ATTR_ENCR_MINBITS, SPD_ATTR_ENCR_MAXBITS); 776 777 /* auth */ 778 ap = emit_alg(ap, ESP_AUTH, &act_ptr->iap_eauth, 779 SPD_ATTR_ESP_AUTH, 780 SPD_ATTR_ESPA_MINBITS, SPD_ATTR_ESPA_MAXBITS); 781 } 782 783 /* ah */ 784 if (act_ptr->iap_attr & SPD_APPLY_AH) { 785 rule_priority |= AH_POLICY_BOOST; 786 /* auth */ 787 ap = emit_alg(ap, AH_AUTH, &act_ptr->iap_aauth, 788 SPD_ATTR_AH_AUTH, 789 SPD_ATTR_AH_MINBITS, SPD_ATTR_AH_MAXBITS); 790 } 791 792 /* lifetimes */ 793 if (act_ptr->iap_life_soft_time != 0) 794 /* LINTED E_CONST_COND */ 795 ATTR(ap, SPD_ATTR_LIFE_SOFT_TIME, act_ptr->iap_life_soft_time); 796 if (act_ptr->iap_life_hard_time != 0) 797 /* LINTED E_CONST_COND */ 798 ATTR(ap, SPD_ATTR_LIFE_HARD_TIME, act_ptr->iap_life_hard_time); 799 if (act_ptr->iap_life_soft_bytes != 0) 800 /* LINTED E_CONST_COND */ 801 ATTR(ap, SPD_ATTR_LIFE_SOFT_BYTES, 802 act_ptr->iap_life_soft_bytes); 803 if (act_ptr->iap_life_hard_bytes != 0) 804 /* LINTED E_CONST_COND */ 805 ATTR(ap, SPD_ATTR_LIFE_HARD_BYTES, 806 act_ptr->iap_life_hard_bytes); 807 808 /* LINTED E_CONST_COND */ 809 ATTR(ap, SPD_ATTR_NEXT, 0); 810 811 *rule_priorityp = rule_priority; 812 813 return (ap); 814 } 815 816 static boolean_t 817 alg_rangecheck(uint_t type, uint_t algid, const algreq_t *ar) 818 { 819 int i; 820 uint_t minbits = ar->alg_minbits; 821 uint_t maxbits = ar->alg_maxbits; 822 823 for (i = 0; i < ipsec_nalgs[type]; i++) { 824 if (known_algs[type][i].id == algid) 825 break; 826 } 827 828 if (i >= ipsec_nalgs[type]) { 829 /* 830 * The kernel (where we populate known_algs from) doesn't 831 * return the id's associated with NONE algorithms so we 832 * test here if this was the reason the algorithm wasn't 833 * found before wrongly failing. 834 */ 835 if (((type == ESP_ENCR) && (algid == SADB_EALG_NONE)) || 836 ((type == ESP_AUTH) && (algid == SADB_AALG_NONE)) || 837 ((type == AH_AUTH) && (algid == SADB_AALG_NONE))) { 838 return (B_TRUE); 839 } else { 840 return (B_FALSE); /* not found */ 841 } 842 } 843 844 if ((minbits == 0) && (maxbits == 0)) 845 return (B_TRUE); 846 847 minbits = MAX(minbits, known_algs[type][i].minkeybits); 848 maxbits = MIN(maxbits, known_algs[type][i].maxkeybits); 849 850 /* we could also check key increments here.. */ 851 return (minbits <= maxbits); /* non-null intersection */ 852 } 853 854 /* 855 * Inspired by uts/common/inet/spd.c:ipsec_act_wildcard_expand() 856 */ 857 858 static struct spd_attribute * 859 ips_act_wild_props_to_action(struct spd_attribute *ap, 860 uint32_t *rule_priorityp, uint16_t *act_cntp, 861 const ips_act_props_t *act_ptr) 862 { 863 ips_act_props_t tact = *act_ptr; 864 boolean_t use_ah, use_esp, use_espa; 865 boolean_t wild_auth, wild_encr, wild_eauth; 866 uint_t auth_alg, auth_idx, auth_min, auth_max; 867 uint_t eauth_alg, eauth_idx, eauth_min, eauth_max; 868 uint_t encr_alg, encr_idx, encr_min, encr_max; 869 870 use_ah = !!(act_ptr->iap_attr & SPD_APPLY_AH); 871 use_esp = !!(act_ptr->iap_attr & SPD_APPLY_ESP); 872 use_espa = !!(act_ptr->iap_attr & SPD_APPLY_ESPA); 873 auth_alg = act_ptr->iap_aauth.alg_id; 874 eauth_alg = act_ptr->iap_eauth.alg_id; 875 encr_alg = act_ptr->iap_eencr.alg_id; 876 877 wild_auth = use_ah && (auth_alg == SADB_AALG_NONE); 878 wild_eauth = use_espa && (eauth_alg == SADB_AALG_NONE); 879 wild_encr = use_esp && (encr_alg == SADB_EALG_NONE); 880 881 auth_min = auth_max = auth_alg; 882 eauth_min = eauth_max = eauth_alg; 883 encr_min = encr_max = encr_alg; 884 885 /* 886 * set up for explosion.. for each dimension, expand output 887 * size by the explosion factor. 888 */ 889 if (wild_auth) { 890 auth_min = 0; 891 auth_max = ipsec_nalgs[AH_AUTH] - 1; 892 } 893 if (wild_eauth) { 894 eauth_min = 0; 895 eauth_max = ipsec_nalgs[ESP_AUTH] - 1; 896 } 897 if (wild_encr) { 898 encr_min = 0; 899 encr_max = ipsec_nalgs[ESP_ENCR] - 1; 900 } 901 902 #define WHICH_ALG(type, wild, idx) ((wild)?(known_algs[type][idx].id):(idx)) 903 904 for (encr_idx = encr_min; encr_idx <= encr_max; encr_idx++) { 905 encr_alg = WHICH_ALG(ESP_ENCR, wild_encr, encr_idx); 906 907 if (use_esp && 908 !alg_rangecheck(ESP_ENCR, encr_alg, &act_ptr->iap_eencr)) 909 continue; 910 911 for (auth_idx = auth_min; auth_idx <= auth_max; auth_idx++) { 912 auth_alg = WHICH_ALG(AH_AUTH, wild_auth, auth_idx); 913 914 if (use_ah && 915 !alg_rangecheck(AH_AUTH, auth_alg, 916 &act_ptr->iap_aauth)) 917 continue; 918 919 920 for (eauth_idx = eauth_min; eauth_idx <= eauth_max; 921 eauth_idx++) { 922 eauth_alg = WHICH_ALG(ESP_AUTH, wild_eauth, 923 eauth_idx); 924 925 if (use_espa && 926 !alg_rangecheck(ESP_AUTH, eauth_alg, 927 &act_ptr->iap_eauth)) 928 continue; 929 930 tact.iap_eencr.alg_id = encr_alg; 931 tact.iap_eauth.alg_id = eauth_alg; 932 tact.iap_aauth.alg_id = auth_alg; 933 934 (*act_cntp)++; 935 ap = ips_act_props_to_action(ap, 936 rule_priorityp, &tact); 937 } 938 } 939 } 940 941 #undef WHICH_ALG 942 943 return (ap); 944 } 945 946 /* huge, but not safe since no length checking is done */ 947 #define MAX_POL_MSG_LEN 16384 948 949 950 /* 951 * hand in some ips_conf_t's, get back an 952 * iovec of pfpol messages. 953 * this function converts the internal ips_conf_t into 954 * a form that pf_pol can use. 955 * return 0 on success, 1 on failure 956 */ 957 static int 958 ips_conf_to_pfpol_msg(int ipsec_cmd, ips_conf_t *inConf, int num_ips, 959 struct iovec *msg) 960 { 961 int i; 962 ips_conf_t *conf; 963 uint64_t *scratch = NULL; 964 965 for (i = 0; i < num_ips; i++) { 966 uint16_t *msg_len; 967 uint16_t act_cnt = 0; 968 uint64_t *next = NULL; 969 spd_msg_t *spd_msg; 970 spd_address_t *spd_address; 971 struct spd_rule *spd_rule; 972 struct spd_proto *spd_proto; 973 struct spd_portrange *spd_portrange; 974 struct spd_ext_actions *spd_ext_actions; 975 struct spd_attribute *ap; 976 struct spd_typecode *spd_typecode; 977 spd_if_t *spd_if; 978 ips_act_props_t *act_ptr; 979 uint32_t rule_priority = 0; 980 981 scratch = calloc(1, MAX_POL_MSG_LEN); 982 msg[i].iov_base = (char *)scratch; 983 if (scratch == NULL) { 984 warn(gettext("memory")); 985 return (1); 986 } 987 conf = &(inConf[i]); 988 989 spd_msg = (spd_msg_t *)scratch; 990 next = (uint64_t *)&(spd_msg[1]); 991 992 msg_len = &(spd_msg->spd_msg_len); 993 994 spd_msg->spd_msg_version = PF_POLICY_V1; 995 spd_msg->spd_msg_pid = getpid(); 996 spd_msg->spd_msg_seq = ++seq_cnt; 997 998 switch (ipsec_cmd) { 999 case SPD_ADDRULE: 1000 spd_msg->spd_msg_type = SPD_ADDRULE; 1001 break; 1002 1003 default: 1004 warnx("%s %d", gettext("bad command:"), ipsec_cmd); 1005 spd_msg->spd_msg_type = SPD_ADDRULE; 1006 break; 1007 } 1008 1009 /* 1010 * SELECTOR 1011 */ 1012 1013 spd_msg->spd_msg_spdid = SPD_STANDBY; 1014 1015 /* rule */ 1016 spd_rule = (struct spd_rule *)next; 1017 1018 spd_rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule)); 1019 spd_rule->spd_rule_type = SPD_EXT_RULE; 1020 spd_rule->spd_rule_flags = conf->ips_dir; 1021 if (conf->ips_tunnel) 1022 spd_rule->spd_rule_flags |= SPD_RULE_FLAG_TUNNEL; 1023 1024 next = (uint64_t *)&(spd_rule[1]); 1025 1026 /* proto */ 1027 if (conf->ips_ulp_prot != 0) { 1028 spd_proto = (struct spd_proto *)next; 1029 spd_proto->spd_proto_len = 1030 SPD_8TO64(sizeof (struct spd_proto)); 1031 spd_proto->spd_proto_exttype = SPD_EXT_PROTO; 1032 spd_proto->spd_proto_number = conf->ips_ulp_prot; 1033 next = (uint64_t *)&(spd_proto[1]); 1034 } 1035 1036 /* tunnel */ 1037 if (conf->has_tunnel != 0) { 1038 spd_if = (spd_if_t *)next; 1039 spd_if->spd_if_len = 1040 SPD_8TO64(P2ROUNDUP(strlen(tunif) + 1, 8) + 1041 sizeof (spd_if_t)); 1042 spd_if->spd_if_exttype = SPD_EXT_TUN_NAME; 1043 (void) strlcpy((char *)spd_if->spd_if_name, tunif, 1044 TUNNAMEMAXLEN); 1045 next = (uint64_t *)(spd_if) + spd_if->spd_if_len; 1046 } 1047 1048 /* icmp type/code */ 1049 if (conf->ips_ulp_prot == IPPROTO_ICMP || 1050 conf->ips_ulp_prot == IPPROTO_ICMPV6) { 1051 if (conf->has_type) { 1052 spd_typecode = (struct spd_typecode *)next; 1053 spd_typecode->spd_typecode_len = 1054 SPD_8TO64(sizeof (struct spd_typecode)); 1055 spd_typecode->spd_typecode_exttype = 1056 SPD_EXT_ICMP_TYPECODE; 1057 spd_typecode->spd_typecode_type = 1058 conf->ips_icmp_type; 1059 spd_typecode->spd_typecode_type_end = 1060 conf->ips_icmp_type_end; 1061 if (conf->has_code) { 1062 spd_typecode->spd_typecode_code = 1063 conf->ips_icmp_code; 1064 spd_typecode->spd_typecode_code_end = 1065 conf->ips_icmp_code_end; 1066 } else { 1067 spd_typecode->spd_typecode_code = 255; 1068 spd_typecode->spd_typecode_code_end 1069 = 255; 1070 } 1071 next = (uint64_t *)&(spd_typecode[1]); 1072 } 1073 } 1074 1075 /* src port */ 1076 if (conf->ips_src_port_min != 0 || 1077 conf->ips_src_port_max != 0) { 1078 spd_portrange = (struct spd_portrange *)next; 1079 spd_portrange->spd_ports_len = 1080 SPD_8TO64(sizeof (struct spd_portrange)); 1081 spd_portrange->spd_ports_exttype = 1082 (conf->swap)?SPD_EXT_REMPORT:SPD_EXT_LCLPORT; 1083 spd_portrange->spd_ports_minport = 1084 conf->ips_src_port_min; 1085 spd_portrange->spd_ports_maxport = 1086 conf->ips_src_port_max; 1087 next = (uint64_t *)&(spd_portrange[1]); 1088 } 1089 /* dst port */ 1090 if (conf->ips_dst_port_min != 0 || 1091 conf->ips_dst_port_max != 0) { 1092 spd_portrange = (struct spd_portrange *)next; 1093 spd_portrange->spd_ports_len = 1094 SPD_8TO64(sizeof (struct spd_portrange)); 1095 spd_portrange->spd_ports_exttype = 1096 (conf->swap)?SPD_EXT_LCLPORT:SPD_EXT_REMPORT; 1097 spd_portrange->spd_ports_minport = 1098 conf->ips_dst_port_min; 1099 spd_portrange->spd_ports_maxport = 1100 conf->ips_dst_port_max; 1101 next = (uint64_t *)&(spd_portrange[1]); 1102 } 1103 1104 /* saddr */ 1105 if (conf->has_saddr) { 1106 spd_address = (spd_address_t *)next; 1107 next = (uint64_t *)(spd_address + 1); 1108 1109 spd_address->spd_address_exttype = 1110 (conf->swap)?SPD_EXT_REMADDR:SPD_EXT_LCLADDR; 1111 spd_address->spd_address_prefixlen = 1112 conf->ips_src_mask_len; 1113 1114 if (conf->ips_isv4) { 1115 spd_address->spd_address_af = AF_INET; 1116 (void) memcpy(next, &(conf->ips_src_addr), 1117 sizeof (ipaddr_t)); 1118 spd_address->spd_address_len = 2; 1119 next += SPD_8TO64(sizeof (ipaddr_t) + 4); 1120 if (!conf->has_smask) 1121 spd_address->spd_address_prefixlen = 32; 1122 } else { 1123 spd_address->spd_address_af = AF_INET6; 1124 (void) memcpy(next, &(conf->ips_src_addr_v6), 1125 sizeof (in6_addr_t)); 1126 spd_address->spd_address_len = 3; 1127 next += SPD_8TO64(sizeof (in6_addr_t)); 1128 if (!conf->has_smask) 1129 spd_address->spd_address_prefixlen 1130 = 128; 1131 } 1132 } 1133 1134 /* daddr */ 1135 if (conf->has_daddr) { 1136 spd_address = (spd_address_t *)next; 1137 1138 next = (uint64_t *)(spd_address + 1); 1139 1140 spd_address->spd_address_exttype = 1141 (conf->swap)?SPD_EXT_LCLADDR:SPD_EXT_REMADDR; 1142 spd_address->spd_address_prefixlen = 1143 conf->ips_dst_mask_len; 1144 1145 if (conf->ips_isv4) { 1146 spd_address->spd_address_af = AF_INET; 1147 (void) memcpy(next, &conf->ips_dst_addr, 1148 sizeof (ipaddr_t)); 1149 spd_address->spd_address_len = 2; 1150 /* "+ 4" below is for padding. */ 1151 next += SPD_8TO64(sizeof (ipaddr_t) + 4); 1152 if (!conf->has_dmask) 1153 spd_address->spd_address_prefixlen = 32; 1154 } else { 1155 spd_address->spd_address_af = AF_INET6; 1156 (void) memcpy(next, &(conf->ips_dst_addr_v6), 1157 sizeof (in6_addr_t)); 1158 spd_address->spd_address_len = 3; 1159 next += SPD_8TO64(sizeof (in6_addr_t)); 1160 if (!conf->has_dmask) 1161 spd_address->spd_address_prefixlen 1162 = 128; 1163 } 1164 } 1165 1166 /* actions */ 1167 spd_ext_actions = (struct spd_ext_actions *)next; 1168 1169 spd_ext_actions->spd_actions_exttype = SPD_EXT_ACTION; 1170 1171 act_ptr = conf->ips_acts; 1172 ap = (struct spd_attribute *)(&spd_ext_actions[1]); 1173 1174 rule_priority = priority--; 1175 1176 for (act_ptr = conf->ips_acts; act_ptr != NULL; 1177 act_ptr = act_ptr->iap_next) { 1178 ap = ips_act_wild_props_to_action(ap, &rule_priority, 1179 &act_cnt, act_ptr); 1180 } 1181 ap[-1].spd_attr_tag = SPD_ATTR_END; 1182 1183 next = (uint64_t *)ap; 1184 1185 spd_rule->spd_rule_priority = rule_priority; 1186 1187 msg[i].iov_len = (uintptr_t)next - (uintptr_t)msg[i].iov_base; 1188 *msg_len = (uint16_t)SPD_8TO64(msg[i].iov_len); 1189 spd_ext_actions->spd_actions_count = act_cnt; 1190 spd_ext_actions->spd_actions_len = 1191 SPD_8TO64((uintptr_t)next - (uintptr_t)spd_ext_actions); 1192 #ifdef DEBUG_HEAVY 1193 printf("pfpol msg len in uint64_t's = %d\n", *msg_len); 1194 printf("pfpol test_len in bytes = %d\n", msg[i].iov_len); 1195 pfpol_msg_dump((spd_msg_t *)scratch, 1196 "ips_conf_to_pfpol_msg"); 1197 #endif 1198 } 1199 1200 #undef ATTR 1201 return (0); 1202 } 1203 1204 static int 1205 get_pf_pol_socket(void) 1206 { 1207 int s = socket(PF_POLICY, SOCK_RAW, PF_POLICY_V1); 1208 if (s < 0) { 1209 if (errno == EPERM) { 1210 EXIT_BADPERM("Insufficient privileges to open " 1211 "PF_POLICY socket."); 1212 } else { 1213 warn(gettext("(loading pf_policy) socket:")); 1214 } 1215 } 1216 1217 return (s); 1218 } 1219 1220 1221 static int 1222 send_pf_pol_message(int ipsec_cmd, ips_conf_t *conf, int *diag) 1223 { 1224 int retval; 1225 int cnt; 1226 int total_len; 1227 struct iovec polmsg; 1228 spd_msg_t *return_buf; 1229 spd_ext_t *exts[SPD_EXT_MAX+1]; 1230 int fd = get_pf_pol_socket(); 1231 1232 *diag = 0; 1233 1234 if (fd < 0) 1235 return (EBADF); 1236 1237 retval = ips_conf_to_pfpol_msg(ipsec_cmd, conf, 1, &polmsg); 1238 1239 if (retval) { 1240 (void) close(fd); 1241 return (ENOMEM); 1242 } 1243 1244 total_len = polmsg.iov_len; 1245 1246 cnt = writev(fd, &polmsg, 1); 1247 1248 #ifdef DEBUG_HEAVY 1249 (void) printf("cnt = %d\n", cnt); 1250 #endif 1251 if (cnt < 0) { 1252 warn(gettext("pf_pol write")); 1253 } else { 1254 return_buf = (spd_msg_t *)calloc(total_len, 1); 1255 1256 if (return_buf == NULL) { 1257 warn(gettext("memory")); 1258 } else { 1259 cnt = read(fd, (void*)return_buf, total_len); 1260 #ifdef DEBUG_HEAVY 1261 (void) printf("pf_pol read: cnt = %d(%d)\n", cnt, 1262 total_len); 1263 #endif 1264 1265 if (cnt > 8 && return_buf->spd_msg_errno) { 1266 *diag = return_buf->spd_msg_diagnostic; 1267 if (!ipsecconf_qflag) { 1268 warnx("%s: %s", 1269 gettext("Kernel returned"), 1270 sys_error_message( 1271 return_buf->spd_msg_errno)); 1272 } 1273 if (*diag != 0) 1274 (void) printf(gettext( 1275 "\t(spdsock diagnostic: %s)\n"), 1276 spdsock_diag(*diag)); 1277 #ifdef DEBUG_HEAVY 1278 pfpol_msg_dump((spd_msg_t *)polmsg.iov_base, 1279 "message in"); 1280 pfpol_msg_dump(return_buf, 1281 "send_pf_pol_message"); 1282 #endif 1283 retval = return_buf->spd_msg_errno; 1284 free(return_buf); 1285 free(polmsg.iov_base); 1286 (void) close(fd); 1287 return (retval); 1288 } 1289 1290 retval = spdsock_get_ext(exts, return_buf, 1291 return_buf->spd_msg_len, NULL, 0); 1292 /* ignore retval */ 1293 1294 if (exts[SPD_EXT_RULE]) { 1295 conf->ips_policy_index = 1296 ((struct spd_rule *) 1297 exts[SPD_EXT_RULE])->spd_rule_index; 1298 1299 if (add_index(conf->ips_policy_index)) { 1300 free(return_buf); 1301 free(polmsg.iov_base); 1302 (void) close(fd); 1303 return (ENOMEM); 1304 } 1305 } 1306 1307 free(return_buf); 1308 } 1309 } 1310 1311 free(polmsg.iov_base); 1312 (void) close(fd); 1313 1314 return (0); 1315 1316 } 1317 1318 int 1319 main(int argc, char *argv[]) 1320 { 1321 int ret, flushret; 1322 int c; 1323 int index; 1324 boolean_t smf_managed; 1325 boolean_t just_check = B_FALSE; 1326 1327 char *smf_warning = gettext( 1328 "\n\tIPsec policy should be managed using smf(5). Modifying\n" 1329 "\tthe IPsec policy from the command line while the 'policy'\n" 1330 "\tservice is enabled could result in an inconsistent\n" 1331 "\tsecurity policy.\n\n"); 1332 1333 flushret = 0; 1334 1335 (void) setlocale(LC_ALL, ""); 1336 #if !defined(TEXT_DOMAIN) 1337 #define TEXT_DOMAIN "SYS_TEST" 1338 #endif 1339 (void) textdomain(TEXT_DOMAIN); 1340 1341 openlog("ipsecconf", LOG_CONS, LOG_AUTH); 1342 1343 /* 1344 * We don't immediately check for privilege here. This is done by IP 1345 * when we open /dev/ip below. 1346 */ 1347 1348 if (argc == 1) { 1349 cmd = IPSEC_CONF_VIEW; 1350 goto done; 1351 } 1352 my_fmri = getenv("SMF_FMRI"); 1353 if (my_fmri == NULL) 1354 smf_managed = B_FALSE; 1355 else 1356 smf_managed = B_TRUE; 1357 1358 while ((c = getopt(argc, argv, "nlfLFa:qd:r:i:c:")) != EOF) { 1359 switch (c) { 1360 case 'F': 1361 if (interface_name != NULL) { 1362 USAGE(); 1363 EXIT_FATAL("interface name not required."); 1364 } 1365 /* Apply to all policy heads - global and tunnels. */ 1366 interface_name = &all_polheads; 1367 /* FALLTHRU */ 1368 case 'f': 1369 /* Only one command at a time */ 1370 if (cmd != 0) { 1371 USAGE(); 1372 EXIT_FATAL("Multiple commands specified"); 1373 } 1374 cmd = IPSEC_CONF_FLUSH; 1375 break; 1376 case 'L': 1377 if (interface_name != NULL) { 1378 USAGE(); 1379 EXIT_FATAL("interface name not required."); 1380 } 1381 /* Apply to all policy heads - global and tunnels. */ 1382 interface_name = &all_polheads; 1383 /* FALLTHRU */ 1384 case 'l': 1385 /* Only one command at a time */ 1386 if (cmd != 0) { 1387 USAGE(); 1388 EXIT_FATAL("Multiple commands specified"); 1389 } 1390 cmd = IPSEC_CONF_LIST; 1391 break; 1392 case 'c': 1393 just_check = B_TRUE; 1394 ipsecconf_qflag++; 1395 /* FALLTHRU */ 1396 case 'a': 1397 /* Only one command at a time, and no interface name */ 1398 if (cmd != 0 || interface_name != NULL) { 1399 USAGE(); 1400 EXIT_FATAL("Multiple commands or interface " 1401 "not required."); 1402 } 1403 cmd = IPSEC_CONF_ADD; 1404 filename = optarg; 1405 break; 1406 case 'd': 1407 /* 1408 * Only one command at a time. Interface name is 1409 * optional. 1410 */ 1411 if (cmd != 0) { 1412 USAGE(); 1413 EXIT_FATAL("Multiple commands specified"); 1414 } 1415 cmd = IPSEC_CONF_DEL; 1416 index = parse_index(optarg, NULL); 1417 break; 1418 case 'n' : 1419 ipsecconf_nflag++; 1420 break; 1421 case 'q' : 1422 ipsecconf_qflag++; 1423 break; 1424 case 'r' : 1425 /* Only one command at a time, and no interface name */ 1426 if (cmd != 0 || interface_name != NULL) { 1427 USAGE(); 1428 EXIT_FATAL("Multiple commands or interface " 1429 "not required."); 1430 } 1431 cmd = IPSEC_CONF_SUB; 1432 filename = optarg; 1433 break; 1434 case 'i': 1435 if (interface_name != NULL) { 1436 EXIT_FATAL("Interface name already selected"); 1437 } 1438 interface_name = optarg; 1439 /* Check for some cretin using the all-polheads name. */ 1440 if (strlen(optarg) == 0) { 1441 USAGE(); 1442 EXIT_FATAL("Invalid interface name."); 1443 } 1444 break; 1445 default : 1446 USAGE(); 1447 EXIT_FATAL("Bad usage."); 1448 } 1449 } 1450 1451 done: 1452 ret = 0; 1453 lfd = lock(); 1454 1455 /* 1456 * ADD, FLUSH, DELETE needs to do two operations. 1457 * 1458 * 1) Update/delete/empty the POLICY_CONF_FILE. 1459 * 2) Make an ioctl and tell IP to update its state. 1460 * 1461 * We already lock()ed so that only one instance of this 1462 * program runs. We also need to make sure that the above 1463 * operations are atomic i.e we don't want to update the file 1464 * and get interrupted before we could tell IP. To make it 1465 * atomic we block all the signals and restore them. 1466 */ 1467 switch (cmd) { 1468 case IPSEC_CONF_LIST: 1469 fetch_algorithms(); 1470 ret = ipsec_conf_list(); 1471 break; 1472 case IPSEC_CONF_FLUSH: 1473 if ((ret = block_all_signals()) == -1) { 1474 break; 1475 } 1476 if (!smf_managed && !ipsecconf_qflag) 1477 (void) fprintf(stdout, "%s", smf_warning); 1478 ret = ipsec_conf_flush(SPD_ACTIVE); 1479 (void) restore_all_signals(); 1480 break; 1481 case IPSEC_CONF_VIEW: 1482 if (interface_name != NULL) { 1483 EXIT_FATAL("Cannot view for one interface only."); 1484 } 1485 ret = ipsec_conf_view(); 1486 break; 1487 case IPSEC_CONF_DEL: 1488 if (index == -1) { 1489 warnx(gettext("Invalid index")); 1490 ret = -1; 1491 break; 1492 } 1493 if ((ret = block_all_signals()) == -1) { 1494 break; 1495 } 1496 if (!smf_managed && !ipsecconf_qflag) 1497 (void) fprintf(stdout, "%s", smf_warning); 1498 ret = ipsec_conf_del(index, B_FALSE); 1499 (void) restore_all_signals(); 1500 flushret = ipsec_conf_flush(SPD_STANDBY); 1501 break; 1502 case IPSEC_CONF_ADD: 1503 /* 1504 * The IPsec kernel modules should only be loaded 1505 * if there is a policy to install, for this 1506 * reason ipsec_conf_add() calls fetch_algorithms() 1507 * and ipsec_conf_flush() only when appropriate. 1508 */ 1509 if ((ret = block_all_signals()) == -1) { 1510 break; 1511 } 1512 if (!smf_managed && !ipsecconf_qflag) 1513 (void) fprintf(stdout, "%s", smf_warning); 1514 ret = ipsec_conf_add(just_check, smf_managed); 1515 (void) restore_all_signals(); 1516 break; 1517 case IPSEC_CONF_SUB: 1518 fetch_algorithms(); 1519 if ((ret = block_all_signals()) == -1) { 1520 break; 1521 } 1522 if (!smf_managed && !ipsecconf_qflag) 1523 (void) fprintf(stdout, "%s", smf_warning); 1524 ret = ipsec_conf_sub(); 1525 (void) restore_all_signals(); 1526 flushret = ipsec_conf_flush(SPD_STANDBY); 1527 break; 1528 default : 1529 /* If no argument is given but a "-" */ 1530 USAGE(); 1531 EXIT_FATAL("Bad usage."); 1532 } 1533 1534 (void) unlock(lfd); 1535 if (ret != 0 || flushret != 0) 1536 ret = 1; 1537 return (ret); 1538 } 1539 1540 static void 1541 perm_check(void) 1542 { 1543 if (errno == EACCES) 1544 EXIT_BADPERM("Insufficient privilege to run ipsecconf."); 1545 else 1546 warn(gettext("Cannot open lock file %s"), LOCK_FILE); 1547 1548 EXIT_BADPERM(NULL); 1549 } 1550 1551 static int 1552 lock() 1553 { 1554 int fd; 1555 struct stat sbuf1; 1556 struct stat sbuf2; 1557 1558 /* 1559 * Open the file with O_CREAT|O_EXCL. If it exists already, it 1560 * will fail. If it already exists, check whether it looks like 1561 * the one we created. 1562 */ 1563 (void) umask(0077); 1564 if ((fd = open(LOCK_FILE, O_EXCL|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) 1565 == -1) { 1566 if (errno != EEXIST) { 1567 /* Some other problem. Will exit. */ 1568 perm_check(); 1569 } 1570 1571 /* 1572 * open() returned an EEXIST error. We don't fail yet 1573 * as it could be a residual from a previous 1574 * execution. 1575 * File exists. make sure it is OK. We need to lstat() 1576 * as fstat() stats the file pointed to by the symbolic 1577 * link. 1578 */ 1579 if (lstat(LOCK_FILE, &sbuf1) == -1) { 1580 EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE); 1581 } 1582 /* 1583 * Check whether it is a regular file and not a symbolic 1584 * link. Its link count should be 1. The owner should be 1585 * root and the file should be empty. 1586 */ 1587 if (!S_ISREG(sbuf1.st_mode) || 1588 sbuf1.st_nlink != 1 || 1589 sbuf1.st_uid != 0 || 1590 sbuf1.st_size != 0) { 1591 EXIT_FATAL2("Bad lock file %s", LOCK_FILE); 1592 } 1593 if ((fd = open(LOCK_FILE, O_CREAT|O_RDWR, 1594 S_IRUSR|S_IWUSR)) == -1) { 1595 /* Will exit */ 1596 perm_check(); 1597 } 1598 /* 1599 * Check whether we opened the file that we lstat()ed. 1600 */ 1601 if (fstat(fd, &sbuf2) == -1) { 1602 EXIT_FATAL2("Cannot lstat lock file %s", LOCK_FILE); 1603 } 1604 if (sbuf1.st_dev != sbuf2.st_dev || 1605 sbuf1.st_ino != sbuf2.st_ino) { 1606 /* File changed after we did the lstat() above */ 1607 EXIT_FATAL2("Bad lock file %s", LOCK_FILE); 1608 } 1609 } 1610 if (lockf(fd, F_LOCK, 0) == -1) { 1611 EXIT_FATAL2("Cannot lockf %s", LOCK_FILE); 1612 } 1613 return (fd); 1614 } 1615 1616 static int 1617 unlock(int fd) 1618 { 1619 if (lockf(fd, F_ULOCK, 0) == -1) { 1620 warn("lockf"); 1621 return (-1); 1622 } 1623 return (0); 1624 } 1625 1626 /* send in TOK_* */ 1627 static void 1628 print_pattern_string(int type) 1629 { 1630 int j; 1631 1632 for (j = 0; pattern_table[j].string != NULL; j++) { 1633 if (type == pattern_table[j].tok_val) { 1634 (void) printf("%s ", pattern_table[j].string); 1635 return; 1636 } 1637 } 1638 } 1639 1640 static void 1641 print_icmp_typecode(uint8_t type, uint8_t type_end, uint8_t code, 1642 uint8_t code_end) 1643 { 1644 (void) printf("type %d", type); 1645 if (type_end != type) 1646 (void) printf("-%d ", type_end); 1647 else 1648 (void) printf(" "); 1649 if (code != 255) { 1650 (void) printf("code %d", code); 1651 if (code_end != code) 1652 (void) printf("-%d ", code_end); 1653 else 1654 (void) printf(" "); 1655 } 1656 } 1657 1658 1659 static void 1660 print_spd_flags(uint32_t flags) 1661 { 1662 flags &= (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND); 1663 1664 if (flags == SPD_RULE_FLAG_OUTBOUND) 1665 (void) printf("dir out "); 1666 else if (flags == SPD_RULE_FLAG_INBOUND) 1667 (void) printf("dir in "); 1668 else if (flags == (SPD_RULE_FLAG_INBOUND|SPD_RULE_FLAG_OUTBOUND)) 1669 (void) printf("dir both "); 1670 } 1671 1672 static void 1673 print_bit_range(int min, int max) 1674 { 1675 if (min != 0 || (max != 0 && max != SPD_MAX_MAXBITS)) { 1676 (void) printf("("); 1677 if (min != 0) 1678 (void) printf("%d", min); 1679 if (min != 0 && max != 0 && min != max) { 1680 (void) printf(".."); 1681 if (max != 0 && max != SPD_MAX_MAXBITS) 1682 (void) printf("%d", max); 1683 } 1684 (void) printf(")"); 1685 } 1686 } 1687 1688 static void 1689 print_alg(const char *tag, algreq_t *algreq, int proto_num) 1690 { 1691 int min = algreq->alg_minbits; 1692 int max = algreq->alg_maxbits; 1693 struct ipsecalgent *alg; 1694 1695 /* 1696 * This function won't be called with alg_id == 0, so we don't 1697 * have to worry about ANY vs. NONE here. 1698 */ 1699 1700 (void) printf("%s ", tag); 1701 1702 alg = getipsecalgbynum(algreq->alg_id, proto_num, NULL); 1703 if (alg == NULL) { 1704 (void) printf("%d", algreq->alg_id); 1705 } else { 1706 (void) printf("%s", alg->a_names[0]); 1707 freeipsecalgent(alg); 1708 } 1709 1710 print_bit_range(min, max); 1711 (void) printf(" "); 1712 } 1713 1714 static void 1715 print_ulp(uint8_t proto) 1716 { 1717 struct protoent *pe; 1718 1719 if (proto == 0) 1720 return; 1721 1722 print_pattern_string(TOK_ulp); 1723 pe = NULL; 1724 if (!ipsecconf_nflag) { 1725 pe = getprotobynumber(proto); 1726 } 1727 if (pe != NULL) 1728 (void) printf("%s ", pe->p_name); 1729 else 1730 (void) printf("%d ", proto); 1731 } 1732 1733 /* needs to do ranges */ 1734 static void 1735 print_port(uint16_t in_port, int type) 1736 { 1737 in_port_t port = ntohs(in_port); 1738 struct servent *sp; 1739 1740 if (port == 0) 1741 return; 1742 1743 print_pattern_string(type); 1744 sp = NULL; 1745 if (!ipsecconf_nflag) 1746 sp = getservbyport(port, NULL); 1747 1748 if (sp != NULL) 1749 (void) printf("%s ", sp->s_name); 1750 else 1751 (void) printf("%d ", port); 1752 } 1753 1754 /* 1755 * Print the address, given as "raw" input via the void pointer. 1756 */ 1757 static void 1758 print_raw_address(void *input, boolean_t isv4) 1759 { 1760 char *cp; 1761 struct hostent *hp; 1762 char domain[MAXHOSTNAMELEN + 1]; 1763 struct in_addr addr; 1764 struct in6_addr addr6; 1765 char abuf[INET6_ADDRSTRLEN]; 1766 int error_num; 1767 struct in6_addr in_addr; 1768 uchar_t *addr_ptr; 1769 sa_family_t af; 1770 int addr_len; 1771 1772 if (isv4) { 1773 af = AF_INET; 1774 (void) memcpy(&V4_PART_OF_V6(in_addr), input, 4); 1775 /* we don't print unspecified addresses */ 1776 IN6_V4MAPPED_TO_INADDR(&in_addr, &addr); 1777 if (addr.s_addr == INADDR_ANY) 1778 return; 1779 addr_ptr = (uchar_t *)&addr.s_addr; 1780 addr_len = IPV4_ADDR_LEN; 1781 } else { 1782 (void) memcpy(&addr6, input, 16); 1783 af = AF_INET6; 1784 /* we don't print unspecified addresses */ 1785 if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) 1786 return; 1787 addr_ptr = (uchar_t *)&addr6.s6_addr; 1788 addr_len = sizeof (struct in6_addr); 1789 } 1790 1791 cp = NULL; 1792 if (!ipsecconf_nflag) { 1793 if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 && 1794 (cp = strchr(domain, '.')) != NULL) { 1795 (void) strlcpy(domain, cp + 1, sizeof (domain)); 1796 } else { 1797 domain[0] = 0; 1798 } 1799 hp = getipnodebyaddr(addr_ptr, addr_len, af, &error_num); 1800 if (hp) { 1801 if ((cp = strchr(hp->h_name, '.')) != 0 && 1802 strcasecmp(cp + 1, domain) == 0) 1803 *cp = 0; 1804 cp = hp->h_name; 1805 } 1806 } 1807 1808 if (cp) { 1809 (void) printf("%s", cp); 1810 } else { 1811 (void) printf("%s", inet_ntop(af, addr_ptr, abuf, 1812 INET6_ADDRSTRLEN)); 1813 } 1814 } 1815 1816 /* 1817 * Get the next SPD_DUMP message from the PF_POLICY socket. A single 1818 * read may contain multiple messages. This function uses static buffers, 1819 * and is therefore non-reentrant, so if you lift it for an MT application, 1820 * be careful. 1821 * 1822 * Return NULL if there's an error. 1823 */ 1824 static spd_msg_t * 1825 ipsec_read_dump(int pfd) 1826 { 1827 static uint64_t buf[SADB_8TO64(CBUF_LEN)]; 1828 static uint64_t *offset; 1829 static int len; /* In uint64_t units. */ 1830 spd_msg_t *retval; 1831 1832 /* Assume offset and len are initialized to NULL and 0. */ 1833 1834 if ((offset - len == buf) || (offset == NULL)) { 1835 /* read a new block from the socket. */ 1836 len = read(pfd, &buf, sizeof (buf)); 1837 if (len == -1) { 1838 warn(gettext("rule dump: bad read")); 1839 return (NULL); 1840 } 1841 offset = buf; 1842 len = SADB_8TO64(len); 1843 } /* Else I still have more messages from a previous read. */ 1844 1845 retval = (spd_msg_t *)offset; 1846 offset += retval->spd_msg_len; 1847 if (offset > buf + len) { 1848 warnx(gettext("dump read: message corruption," 1849 " %d len exceeds %d boundary."), 1850 SADB_64TO8((uintptr_t)(offset - buf)), 1851 SADB_64TO8((uintptr_t)(buf + len))); 1852 return (NULL); 1853 } 1854 1855 return (retval); 1856 } 1857 1858 /* 1859 * returns 0 on success 1860 * -1 on read error 1861 * >0 on invalid returned message 1862 */ 1863 1864 static int 1865 ipsec_conf_list(void) 1866 { 1867 int ret; 1868 int pfd; 1869 struct spd_msg *msg; 1870 int cnt; 1871 spd_msg_t *rmsg; 1872 spd_ext_t *exts[SPD_EXT_MAX+1]; 1873 /* 1874 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation 1875 * issues. 1876 */ 1877 uint64_t buffer[ 1878 SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1]; 1879 1880 pfd = get_pf_pol_socket(); 1881 1882 if (pfd == -1) { 1883 warnx(gettext("Error getting list of policies from kernel")); 1884 return (-1); 1885 } 1886 1887 (void) memset(buffer, 0, sizeof (buffer)); 1888 msg = (struct spd_msg *)buffer; 1889 msg->spd_msg_version = PF_POLICY_V1; 1890 msg->spd_msg_type = SPD_DUMP; 1891 msg->spd_msg_len = SPD_8TO64(sizeof (*msg)); 1892 1893 msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1)); 1894 1895 cnt = write(pfd, msg, SPD_64TO8(msg->spd_msg_len)); 1896 1897 if (cnt < 0) { 1898 warn(gettext("dump: invalid write() return")); 1899 (void) close(pfd); 1900 return (-1); 1901 } 1902 1903 rmsg = ipsec_read_dump(pfd); 1904 1905 if (rmsg == NULL || rmsg->spd_msg_errno != 0) { 1906 warnx("%s: %s", gettext("ruleset dump failed"), 1907 (rmsg == NULL ? 1908 gettext("read error") : 1909 sys_error_message(rmsg->spd_msg_errno))); 1910 (void) close(pfd); 1911 return (-1); 1912 } 1913 1914 1915 for (;;) { 1916 /* read rule */ 1917 rmsg = ipsec_read_dump(pfd); 1918 1919 if (rmsg == NULL) { 1920 (void) close(pfd); 1921 return (-1); 1922 } 1923 1924 if (rmsg->spd_msg_errno != 0) { 1925 warnx("%s: %s", gettext("dump read: bad message"), 1926 sys_error_message(rmsg->spd_msg_errno)); 1927 (void) close(pfd); 1928 return (-1); 1929 } 1930 1931 ret = spdsock_get_ext(exts, rmsg, rmsg->spd_msg_len, 1932 spdsock_diag_buf, SPDSOCK_DIAG_BUF_LEN); 1933 if (ret != 0) { 1934 if (strlen(spdsock_diag_buf) != 0) 1935 warnx(spdsock_diag_buf); 1936 warnx("%s: %s", gettext("dump read: bad message"), 1937 sys_error_message(rmsg->spd_msg_errno)); 1938 (void) close(pfd); 1939 return (ret); 1940 } 1941 1942 /* 1943 * End of dump.. 1944 */ 1945 if (exts[SPD_EXT_RULESET] != NULL) 1946 break; /* and return 0. */ 1947 1948 print_pfpol_msg(rmsg); 1949 } 1950 1951 (void) close(pfd); 1952 return (0); 1953 } 1954 1955 static void 1956 print_iap(ips_act_props_t *iap) 1957 { 1958 1959 /* action */ 1960 switch (iap->iap_action) { 1961 case SPD_ACTTYPE_PASS: 1962 (void) printf("pass "); 1963 break; 1964 case SPD_ACTTYPE_DROP: 1965 (void) printf("drop "); 1966 break; 1967 case SPD_ACTTYPE_IPSEC: 1968 (void) printf("ipsec "); 1969 break; 1970 } 1971 1972 /* properties */ 1973 (void) printf("%c ", CURL_BEGIN); 1974 if (iap->iap_action == SPD_ACTTYPE_IPSEC) { 1975 if (iap->iap_attr & SPD_APPLY_AH && 1976 iap->iap_aauth.alg_id != 0) 1977 print_alg("auth_algs", &iap->iap_aauth, 1978 IPSEC_PROTO_AH); 1979 1980 if (iap->iap_attr & SPD_APPLY_ESP) { 1981 print_alg("encr_algs", &iap->iap_eencr, 1982 IPSEC_PROTO_ESP); 1983 if (iap->iap_eauth.alg_id != 0) 1984 print_alg("encr_auth_algs", &iap->iap_eauth, 1985 IPSEC_PROTO_AH); 1986 } 1987 if (iap->iap_attr & SPD_APPLY_UNIQUE) 1988 (void) printf("sa unique "); 1989 else 1990 (void) printf("sa shared "); 1991 } 1992 (void) printf("%c ", CURL_END); 1993 } 1994 1995 1996 static void 1997 print_pfpol_msg(spd_msg_t *msg) 1998 { 1999 spd_ext_t *exts[SPD_EXT_MAX+1]; 2000 spd_address_t *spd_address; 2001 struct spd_rule *spd_rule; 2002 struct spd_proto *spd_proto; 2003 struct spd_portrange *spd_portrange; 2004 struct spd_ext_actions *spd_ext_actions; 2005 struct spd_typecode *spd_typecode; 2006 struct spd_attribute *app; 2007 spd_if_t *spd_if; 2008 uint32_t rv; 2009 uint16_t act_count; 2010 2011 rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, spdsock_diag_buf, 2012 SPDSOCK_DIAG_BUF_LEN); 2013 2014 if (rv == KGE_OK && exts[SPD_EXT_RULE] != NULL) { 2015 spd_if = (spd_if_t *)exts[SPD_EXT_TUN_NAME]; 2016 spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE]; 2017 if (spd_if == NULL) { 2018 (void) printf("%s %lld\n", INDEX_TAG, 2019 spd_rule->spd_rule_index); 2020 } else { 2021 (void) printf("%s %s,%lld\n", INDEX_TAG, 2022 (char *)spd_if->spd_if_name, 2023 spd_rule->spd_rule_index); 2024 } 2025 } else { 2026 if (strlen(spdsock_diag_buf) != 0) 2027 warnx(spdsock_diag_buf); 2028 warnx(gettext("print_pfpol_msg: malformed PF_POLICY message.")); 2029 return; 2030 } 2031 2032 (void) printf("%c ", CURL_BEGIN); 2033 2034 if (spd_if != NULL) { 2035 (void) printf("tunnel %s negotiate %s ", 2036 (char *)spd_if->spd_if_name, 2037 (spd_rule->spd_rule_flags & SPD_RULE_FLAG_TUNNEL) ? 2038 "tunnel" : "transport"); 2039 } 2040 2041 if (exts[SPD_EXT_PROTO] != NULL) { 2042 spd_proto = (struct spd_proto *)exts[SPD_EXT_PROTO]; 2043 print_ulp(spd_proto->spd_proto_number); 2044 } 2045 2046 if (exts[SPD_EXT_LCLADDR] != NULL) { 2047 spd_address = (spd_address_t *)exts[SPD_EXT_LCLADDR]; 2048 2049 (void) printf("laddr "); 2050 print_raw_address((spd_address + 1), 2051 (spd_address->spd_address_len == 2)); 2052 (void) printf("/%d ", spd_address->spd_address_prefixlen); 2053 } 2054 2055 if (exts[SPD_EXT_LCLPORT] != NULL) { 2056 spd_portrange = (struct spd_portrange *)exts[SPD_EXT_LCLPORT]; 2057 if (spd_portrange->spd_ports_minport != 0) { 2058 print_port(spd_portrange->spd_ports_minport, 2059 TOK_lport); 2060 } 2061 } 2062 2063 2064 if (exts[SPD_EXT_REMADDR] != NULL) { 2065 spd_address = (spd_address_t *)exts[SPD_EXT_REMADDR]; 2066 2067 (void) printf("raddr "); 2068 print_raw_address((spd_address + 1), 2069 (spd_address->spd_address_len == 2)); 2070 (void) printf("/%d ", spd_address->spd_address_prefixlen); 2071 } 2072 2073 if (exts[SPD_EXT_REMPORT] != NULL) { 2074 spd_portrange = 2075 (struct spd_portrange *)exts[SPD_EXT_REMPORT]; 2076 if (spd_portrange->spd_ports_minport != 0) { 2077 print_port( 2078 spd_portrange->spd_ports_minport, 2079 TOK_rport); 2080 } 2081 } 2082 2083 if (exts[SPD_EXT_ICMP_TYPECODE] != NULL) { 2084 spd_typecode = 2085 (struct spd_typecode *)exts[SPD_EXT_ICMP_TYPECODE]; 2086 print_icmp_typecode(spd_typecode->spd_typecode_type, 2087 spd_typecode->spd_typecode_type_end, 2088 spd_typecode->spd_typecode_code, 2089 spd_typecode->spd_typecode_code_end); 2090 } 2091 2092 if (exts[SPD_EXT_RULE] != NULL) { 2093 spd_rule = (struct spd_rule *)exts[SPD_EXT_RULE]; 2094 print_spd_flags(spd_rule->spd_rule_flags); 2095 } 2096 2097 2098 (void) printf("%c ", CURL_END); 2099 2100 if (exts[SPD_EXT_ACTION] != NULL) { 2101 ips_act_props_t iap; 2102 int or_needed = 0; 2103 2104 (void) memset(&iap, 0, sizeof (iap)); 2105 spd_ext_actions = 2106 (struct spd_ext_actions *)exts[SPD_EXT_ACTION]; 2107 app = (struct spd_attribute *)(spd_ext_actions + 1); 2108 2109 for (act_count = 0; 2110 act_count < spd_ext_actions->spd_actions_len -1; 2111 act_count++) { 2112 2113 switch (app->spd_attr_tag) { 2114 2115 case SPD_ATTR_NOP: 2116 break; 2117 2118 case SPD_ATTR_END: 2119 /* print */ 2120 if (or_needed) { 2121 (void) printf("or "); 2122 } else { 2123 or_needed = 1; 2124 } 2125 print_iap(&iap); 2126 break; 2127 2128 case SPD_ATTR_EMPTY: 2129 /* clear */ 2130 (void) memset(&iap, 0, sizeof (iap)); 2131 break; 2132 2133 case SPD_ATTR_NEXT: 2134 /* print */ 2135 if (or_needed) { 2136 (void) printf("or "); 2137 } else { 2138 or_needed = 1; 2139 } 2140 2141 print_iap(&iap); 2142 break; 2143 2144 case SPD_ATTR_TYPE: 2145 iap.iap_action = app->spd_attr_value; 2146 break; 2147 2148 case SPD_ATTR_FLAGS: 2149 iap.iap_attr = app->spd_attr_value; 2150 break; 2151 2152 case SPD_ATTR_AH_AUTH: 2153 iap.iap_aauth.alg_id = app->spd_attr_value; 2154 break; 2155 2156 case SPD_ATTR_ESP_ENCR: 2157 iap.iap_eencr.alg_id = app->spd_attr_value; 2158 break; 2159 2160 case SPD_ATTR_ESP_AUTH: 2161 iap.iap_eauth.alg_id = app->spd_attr_value; 2162 break; 2163 2164 case SPD_ATTR_ENCR_MINBITS: 2165 iap.iap_eencr.alg_minbits = app->spd_attr_value; 2166 break; 2167 2168 case SPD_ATTR_ENCR_MAXBITS: 2169 iap.iap_eencr.alg_maxbits = app->spd_attr_value; 2170 break; 2171 2172 case SPD_ATTR_AH_MINBITS: 2173 iap.iap_aauth.alg_minbits = app->spd_attr_value; 2174 break; 2175 2176 case SPD_ATTR_AH_MAXBITS: 2177 iap.iap_aauth.alg_maxbits = app->spd_attr_value; 2178 break; 2179 2180 case SPD_ATTR_ESPA_MINBITS: 2181 iap.iap_eauth.alg_minbits = app->spd_attr_value; 2182 break; 2183 2184 case SPD_ATTR_ESPA_MAXBITS: 2185 iap.iap_eauth.alg_maxbits = app->spd_attr_value; 2186 break; 2187 2188 case SPD_ATTR_LIFE_SOFT_TIME: 2189 case SPD_ATTR_LIFE_HARD_TIME: 2190 case SPD_ATTR_LIFE_SOFT_BYTES: 2191 case SPD_ATTR_LIFE_HARD_BYTES: 2192 default: 2193 (void) printf("\tattr %d: %X-%d\n", 2194 act_count, 2195 app->spd_attr_tag, 2196 app->spd_attr_value); 2197 break; 2198 } 2199 app++; 2200 } 2201 } 2202 2203 (void) printf("\n"); 2204 } 2205 2206 #ifdef DEBUG_HEAVY 2207 static void 2208 pfpol_msg_dump(spd_msg_t *msg, char *tag) 2209 { 2210 spd_ext_t *exts[SPD_EXT_MAX+1]; 2211 uint32_t i; 2212 spd_address_t *spd_address; 2213 struct spd_rule *spd_rule; 2214 struct spd_proto *spd_proto; 2215 struct spd_portrange *spd_portrange; 2216 struct spd_typecode *spd_typecode; 2217 struct spd_ext_actions *spd_ext_actions; 2218 struct spd_attribute *app; 2219 spd_if_t *spd_if; 2220 char abuf[INET6_ADDRSTRLEN]; 2221 uint32_t rv; 2222 uint16_t act_count; 2223 2224 rv = spdsock_get_ext(exts, msg, msg->spd_msg_len, NULL, 0); 2225 if (rv != KGE_OK) 2226 return; 2227 2228 (void) printf("===========%s==============\n", tag); 2229 (void) printf("pfpol_msg_dump %d\n-------------------\n", rv); 2230 2231 (void) printf("spd_msg_version:%d\n", msg->spd_msg_version); 2232 (void) printf("spd_msg_type:%d\n", msg->spd_msg_type); 2233 (void) printf("spd_msg_errno:%d\n", msg->spd_msg_errno); 2234 (void) printf("spd_msg_spdid:%d\n", msg->spd_msg_spdid); 2235 (void) printf("spd_msg_len:%d\n", msg->spd_msg_len); 2236 (void) printf("spd_msg_diagnostic:%d\n", msg->spd_msg_diagnostic); 2237 (void) printf("spd_msg_seq:%d\n", msg->spd_msg_seq); 2238 (void) printf("spd_msg_pid:%d\n", msg->spd_msg_pid); 2239 2240 for (i = 1; i <= SPD_EXT_MAX; i++) { 2241 if (exts[i] == NULL) { 2242 printf("skipped %d\n", i); 2243 continue; 2244 } 2245 2246 switch (i) { 2247 case SPD_EXT_TUN_NAME: 2248 spd_if = (spd_if_t *)exts[i]; 2249 (void) printf("spd_if = %s\n", spd_if->spd_if_name); 2250 break; 2251 2252 case SPD_EXT_ICMP_TYPECODE: 2253 spd_typecode = (struct spd_typecode *)exts[i]; 2254 (void) printf("icmp type %d-%d code %d-%d\n", 2255 spd_typecode->spd_typecode_type, 2256 spd_typecode->spd_typecode_type_end, 2257 spd_typecode->spd_typecode_code, 2258 spd_typecode->spd_typecode_code_end); 2259 break; 2260 2261 case SPD_EXT_LCLPORT: 2262 spd_portrange = (struct spd_portrange *)exts[i]; 2263 (void) printf("local ports %d-%d\n", 2264 spd_portrange->spd_ports_minport, 2265 spd_portrange->spd_ports_maxport); 2266 2267 break; 2268 2269 case SPD_EXT_REMPORT: 2270 spd_portrange = (struct spd_portrange *)exts[i]; 2271 (void) printf("remote ports %d-%d\n", 2272 spd_portrange->spd_ports_minport, 2273 spd_portrange->spd_ports_maxport); 2274 2275 break; 2276 2277 case SPD_EXT_PROTO: 2278 spd_proto = (struct spd_proto *)exts[i]; 2279 (void) printf("proto:spd_proto_exttype %d\n", 2280 spd_proto->spd_proto_exttype); 2281 (void) printf("proto:spd_proto_number %d\n", 2282 spd_proto->spd_proto_number); 2283 break; 2284 2285 case SPD_EXT_LCLADDR: 2286 case SPD_EXT_REMADDR: 2287 spd_address = (spd_address_t *)exts[i]; 2288 if (i == SPD_EXT_LCLADDR) 2289 (void) printf("local addr "); 2290 else 2291 (void) printf("remote addr "); 2292 2293 2294 (void) printf("%s\n", 2295 inet_ntop(spd_address->spd_address_af, 2296 (void *) (spd_address +1), abuf, 2297 INET6_ADDRSTRLEN)); 2298 2299 (void) printf("prefixlen: %d\n", 2300 spd_address->spd_address_prefixlen); 2301 break; 2302 2303 case SPD_EXT_ACTION: 2304 spd_ext_actions = (struct spd_ext_actions *)exts[i]; 2305 (void) printf("spd_ext_action\n"); 2306 (void) printf("spd_actions_count %d\n", 2307 spd_ext_actions->spd_actions_count); 2308 app = (struct spd_attribute *)(spd_ext_actions + 1); 2309 2310 for (act_count = 0; 2311 act_count < spd_ext_actions->spd_actions_len -1; 2312 act_count++) { 2313 (void) printf("\tattr %d: %X-%d\n", act_count, 2314 app->spd_attr_tag, app->spd_attr_value); 2315 app++; 2316 } 2317 2318 break; 2319 2320 case SPD_EXT_RULE: 2321 spd_rule = (struct spd_rule *)exts[i]; 2322 (void) printf("spd_rule_priority: 0x%x\n", 2323 spd_rule->spd_rule_priority); 2324 (void) printf("spd_rule_flags: %d\n", 2325 spd_rule->spd_rule_flags); 2326 break; 2327 2328 case SPD_EXT_RULESET: 2329 (void) printf("spd_ext_ruleset\n"); 2330 break; 2331 default: 2332 (void) printf("default\n"); 2333 break; 2334 } 2335 } 2336 2337 (void) printf("-------------------\n"); 2338 (void) printf("=========================\n"); 2339 } 2340 #endif /* DEBUG_HEAVY */ 2341 2342 static int 2343 ipsec_conf_view() 2344 { 2345 char buf[MAXLEN]; 2346 FILE *fp; 2347 2348 fp = fopen(POLICY_CONF_FILE, "r"); 2349 if (fp == NULL) { 2350 if (errno == ENOENT) { 2351 /* 2352 * The absence of POLICY_CONF_FILE should 2353 * not cause the command to exit with a 2354 * non-zero status, since this condition 2355 * is valid when no policies were previously 2356 * defined. 2357 */ 2358 return (0); 2359 } 2360 warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 2361 return (-1); 2362 } 2363 while (fgets(buf, MAXLEN, fp) != NULL) { 2364 /* Don't print removed entries */ 2365 if (*buf == ';') 2366 continue; 2367 if (strlen(buf) != 0) 2368 buf[strlen(buf) - 1] = '\0'; 2369 (void) puts(buf); 2370 } 2371 return (0); 2372 } 2373 2374 /* 2375 * Delete nlines from start in the POLICY_CONF_FILE. 2376 */ 2377 static int 2378 delete_from_file(int start, int nlines) 2379 { 2380 FILE *fp; 2381 char ibuf[MAXLEN]; 2382 int len; 2383 2384 if ((fp = fopen(POLICY_CONF_FILE, "r+b")) == NULL) { 2385 warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 2386 return (-1); 2387 } 2388 2389 /* 2390 * Insert a ";", read the line and discard it. Repeat 2391 * this logic nlines - 1 times. For the last line there 2392 * is just a newline character. We can't just insert a 2393 * single ";" character instead of the newline character 2394 * as it would affect the next line. Thus when we comment 2395 * the last line we seek one less and insert a ";" 2396 * character, which will replace the newline of the 2397 * penultimate line with ; and newline of the last line 2398 * will become part of the previous line. 2399 */ 2400 do { 2401 /* 2402 * It is not enough to seek just once and expect the 2403 * subsequent fgets below to take you to the right 2404 * offset of the next line. fgets below seems to affect 2405 * the offset. Thus we need to seek, replace with ";", 2406 * and discard a line using fgets for every line. 2407 */ 2408 if (fseek(fp, start, SEEK_SET) == -1) { 2409 warn("fseek"); 2410 return (-1); 2411 } 2412 if (fputc(';', fp) < 0) { 2413 warn("fputc"); 2414 return (-1); 2415 } 2416 /* 2417 * Flush the above ";" character before we do the fgets(). 2418 * Without this, fgets() gets confused with offsets. 2419 */ 2420 (void) fflush(fp); 2421 len = 0; 2422 while (fgets(ibuf, MAXLEN, fp) != NULL) { 2423 len += strlen(ibuf); 2424 if (ibuf[len - 1] == '\n') { 2425 /* 2426 * We have read a complete line. 2427 */ 2428 break; 2429 } 2430 } 2431 /* 2432 * We read the line after ";" character has been inserted. 2433 * Thus len does not count ";". To advance to the next line 2434 * increment by 1. 2435 */ 2436 start += (len + 1); 2437 /* 2438 * If nlines == 2, we will be commenting out the last 2439 * line next, which has only one newline character. 2440 * If we blindly replace it with ";", it will be 2441 * read as part of the next line which could have 2442 * a INDEX string and thus confusing ipsec_conf_view. 2443 * Thus, we seek one less and replace the previous 2444 * line's newline character with ";", and the 2445 * last line's newline character will become part of 2446 * the previous line. 2447 */ 2448 if (nlines == 2) 2449 start--; 2450 } while (--nlines != 0); 2451 (void) fclose(fp); 2452 if (nlines != 0) 2453 return (-1); 2454 else 2455 return (0); 2456 } 2457 2458 /* 2459 * Delete an entry from the file by inserting a ";" at the 2460 * beginning of the lines to be removed. 2461 */ 2462 static int 2463 ipsec_conf_del(int policy_index, boolean_t ignore_spd) 2464 { 2465 act_prop_t *act_props = malloc(sizeof (act_prop_t)); 2466 char *buf; 2467 FILE *fp; 2468 char ibuf[MAXLEN]; 2469 int ibuf_len, index_len, index; 2470 int ret = 0; 2471 int offset, prev_offset; 2472 int nlines; 2473 char lifname[LIFNAMSIZ]; 2474 2475 if (act_props == NULL) { 2476 warn(gettext("memory")); 2477 return (-1); 2478 } 2479 2480 fp = fopen(POLICY_CONF_FILE, "r"); 2481 if (fp == NULL) { 2482 warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 2483 free(act_props); 2484 return (-1); 2485 } 2486 2487 index_len = strlen(INDEX_TAG); 2488 index = 0; 2489 for (offset = prev_offset = 0; fgets(ibuf, MAXLEN, fp) != NULL; 2490 offset += ibuf_len) { 2491 prev_offset = offset; 2492 ibuf_len = strlen(ibuf); 2493 2494 if (strncmp(ibuf, INDEX_TAG, index_len) != 0) { 2495 continue; 2496 } 2497 2498 /* 2499 * This line contains INDEX_TAG 2500 */ 2501 buf = ibuf + index_len; 2502 buf++; /* Skip the space */ 2503 index = parse_index(buf, lifname); 2504 if (index == -1) { 2505 warnx(gettext("Invalid index in the file")); 2506 free(act_props); 2507 return (-1); 2508 } 2509 if (index == policy_index && 2510 (interface_name == NULL || 2511 strncmp(interface_name, lifname, LIFNAMSIZ) == 0)) { 2512 if (!ignore_spd) { 2513 ret = parse_one(fp, act_props); 2514 if (ret == -1) { 2515 warnx(gettext("Invalid policy entry " 2516 "in the file")); 2517 free(act_props); 2518 return (-1); 2519 } 2520 } 2521 /* 2522 * nlines is the number of lines we should comment 2523 * out. linecount tells us how many lines this command 2524 * spans. And we need to remove the line with INDEX 2525 * and an extra line we added during ipsec_conf_add. 2526 * 2527 * NOTE : If somebody added a policy entry which does 2528 * not have a newline, ipsec_conf_add() fills in the 2529 * newline. Hence, there is always 2 extra lines 2530 * to delete. 2531 */ 2532 nlines = linecount + 2; 2533 goto delete; 2534 } 2535 } 2536 2537 if (!ignore_spd) 2538 ret = pfp_delete_rule(policy_index); 2539 2540 if (ret != 0) { 2541 warnx(gettext("Deletion incomplete. Please " 2542 "flush all the entries and re-configure :")); 2543 reconfigure(); 2544 free(act_props); 2545 return (ret); 2546 } 2547 free(act_props); 2548 return (ret); 2549 2550 delete: 2551 /* Delete nlines from prev_offset */ 2552 (void) fclose(fp); 2553 ret = delete_from_file(prev_offset, nlines); 2554 2555 if (ret != 0) { 2556 warnx(gettext("Deletion incomplete. Please " 2557 "flush all the entries and re-configure :")); 2558 reconfigure(); 2559 free(act_props); 2560 return (ret); 2561 } 2562 2563 if (!ignore_spd) 2564 ret = pfp_delete_rule(policy_index); 2565 2566 if (ret != 0) { 2567 warnx(gettext("Deletion incomplete. Please " 2568 "flush all the entries and re-configure :")); 2569 reconfigure(); 2570 free(act_props); 2571 return (ret); 2572 } 2573 free(act_props); 2574 return (0); 2575 } 2576 2577 static int 2578 pfp_delete_rule(uint64_t index) 2579 { 2580 struct spd_msg *msg; 2581 struct spd_rule *rule; 2582 int sfd; 2583 int cnt, len, alloclen; 2584 2585 sfd = get_pf_pol_socket(); 2586 if (sfd < 0) { 2587 warn(gettext("unable to open policy socket")); 2588 return (-1); 2589 } 2590 2591 /* 2592 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation 2593 * issues. 2594 */ 2595 alloclen = sizeof (spd_msg_t) + sizeof (struct spd_rule) + 2596 sizeof (spd_if_t) + LIFNAMSIZ + 8; 2597 msg = (spd_msg_t *)malloc(alloclen); 2598 2599 if (msg == NULL) { 2600 warn("malloc"); 2601 return (-1); 2602 } 2603 2604 rule = (struct spd_rule *)(msg + 1); 2605 2606 (void) memset(msg, 0, alloclen); 2607 msg->spd_msg_version = PF_POLICY_V1; 2608 msg->spd_msg_type = SPD_DELETERULE; 2609 msg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t) 2610 + sizeof (struct spd_rule)); 2611 2612 rule->spd_rule_type = SPD_EXT_RULE; 2613 rule->spd_rule_len = SPD_8TO64(sizeof (struct spd_rule)); 2614 rule->spd_rule_index = index; 2615 2616 msg->spd_msg_len += attach_tunname((spd_if_t *)(rule + 1)); 2617 2618 len = SPD_64TO8(msg->spd_msg_len); 2619 cnt = write(sfd, msg, len); 2620 2621 if (cnt != len) { 2622 if (cnt < 0) { 2623 (void) close(sfd); 2624 free(msg); 2625 warn(gettext("Delete failed: write")); 2626 return (-1); 2627 } else { 2628 (void) close(sfd); 2629 free(msg); 2630 warnx(gettext("Delete failed: short write")); 2631 return (-1); 2632 } 2633 } 2634 2635 cnt = read(sfd, msg, len); 2636 if (cnt != len) { 2637 if (cnt < 0) { 2638 (void) close(sfd); 2639 free(msg); 2640 warn(gettext("Delete failed: read")); 2641 return (-1); 2642 } else { 2643 (void) close(sfd); 2644 free(msg); 2645 warnx(gettext("Delete failed while reading reply")); 2646 return (-1); 2647 } 2648 } 2649 (void) close(sfd); 2650 if (msg->spd_msg_errno != 0) { 2651 free(msg); 2652 errno = msg->spd_msg_errno; 2653 warn(gettext("Delete failed: SPD_FLUSH")); 2654 return (-1); 2655 } 2656 2657 free(msg); 2658 return (0); 2659 } 2660 2661 static int 2662 ipsec_conf_flush(int db) 2663 { 2664 int pfd, cnt, len; 2665 int sfd; 2666 struct spd_msg *msg; 2667 /* 2668 * Add an extra 8 bytes of space (+1 uint64_t) to avoid truncation 2669 * issues. 2670 */ 2671 uint64_t buffer[ 2672 SPD_8TO64(sizeof (*msg) + sizeof (spd_if_t) + LIFNAMSIZ) + 1]; 2673 2674 sfd = get_pf_pol_socket(); 2675 if (sfd < 0) { 2676 warn(gettext("unable to open policy socket")); 2677 return (-1); 2678 } 2679 2680 (void) memset(buffer, 0, sizeof (buffer)); 2681 msg = (struct spd_msg *)buffer; 2682 msg->spd_msg_version = PF_POLICY_V1; 2683 msg->spd_msg_type = SPD_FLUSH; 2684 msg->spd_msg_len = SPD_8TO64(sizeof (*msg)); 2685 msg->spd_msg_spdid = db; 2686 2687 msg->spd_msg_len += attach_tunname((spd_if_t *)(msg + 1)); 2688 2689 len = SPD_64TO8(msg->spd_msg_len); 2690 cnt = write(sfd, msg, len); 2691 if (cnt != len) { 2692 if (cnt < 0) { 2693 warn(gettext("Flush failed: write")); 2694 return (-1); 2695 } else { 2696 warnx(gettext("Flush failed: short write")); 2697 return (-1); 2698 } 2699 } 2700 2701 cnt = read(sfd, msg, len); 2702 if (cnt != len) { 2703 if (cnt < 0) { 2704 warn(gettext("Flush failed: read")); 2705 return (-1); 2706 } else { 2707 warnx(gettext("Flush failed while reading reply")); 2708 return (-1); 2709 } 2710 } 2711 (void) close(sfd); 2712 if (msg->spd_msg_errno != 0) { 2713 warnx("%s: %s", gettext("Flush failed: SPD_FLUSH"), 2714 sys_error_message(msg->spd_msg_errno)); 2715 return (-1); 2716 } 2717 2718 /* Truncate the file */ 2719 if (db == SPD_ACTIVE) { 2720 if ((pfd = open(POLICY_CONF_FILE, O_TRUNC|O_RDWR)) == -1) { 2721 if (errno == ENOENT) { 2722 /* 2723 * The absence of POLICY_CONF_FILE should 2724 * not cause the command to exit with a 2725 * non-zero status, since this condition 2726 * is valid when no policies were previously 2727 * defined. 2728 */ 2729 return (0); 2730 } 2731 warn(gettext("%s cannot be truncated"), 2732 POLICY_CONF_FILE); 2733 return (-1); 2734 } 2735 (void) close(pfd); 2736 } 2737 return (0); 2738 } 2739 2740 /* 2741 * function to send SPD_FLIP and SPD_CLONE messages 2742 * Do it for ALL polheads for simplicity's sake. 2743 */ 2744 static void 2745 ipsec_conf_admin(uint8_t type) 2746 { 2747 int cnt; 2748 int sfd; 2749 struct spd_msg *msg; 2750 uint64_t buffer[ 2751 SPD_8TO64(sizeof (struct spd_msg) + sizeof (spd_if_t))]; 2752 char *save_ifname; 2753 2754 sfd = get_pf_pol_socket(); 2755 if (sfd < 0) { 2756 err(-1, gettext("unable to open policy socket")); 2757 } 2758 2759 (void) memset(buffer, 0, sizeof (buffer)); 2760 msg = (struct spd_msg *)buffer; 2761 msg->spd_msg_version = PF_POLICY_V1; 2762 msg->spd_msg_type = type; 2763 msg->spd_msg_len = SPD_8TO64(sizeof (buffer)); 2764 2765 save_ifname = interface_name; 2766 /* Apply to all policy heads - global and tunnels. */ 2767 interface_name = &all_polheads; 2768 (void) attach_tunname((spd_if_t *)(msg + 1)); 2769 interface_name = save_ifname; 2770 2771 cnt = write(sfd, msg, sizeof (buffer)); 2772 if (cnt != sizeof (buffer)) { 2773 if (cnt < 0) { 2774 err(-1, gettext("admin failed: write")); 2775 } else { 2776 errx(-1, gettext("admin failed: short write")); 2777 } 2778 } 2779 2780 cnt = read(sfd, msg, sizeof (buffer)); 2781 if (cnt != sizeof (buffer)) { 2782 if (cnt < 0) { 2783 err(-1, gettext("admin failed: read")); 2784 } else { 2785 errx(-1, gettext("admin failed while reading reply")); 2786 } 2787 } 2788 (void) close(sfd); 2789 if (msg->spd_msg_errno != 0) { 2790 errno = msg->spd_msg_errno; 2791 err(-1, gettext("admin failed")); 2792 } 2793 } 2794 2795 static void 2796 reconfigure() 2797 { 2798 (void) fprintf(stderr, gettext( 2799 "\tipsecconf -f \n " 2800 "\tipsecconf -a policy_file\n")); 2801 } 2802 2803 static void 2804 usage(void) 2805 { 2806 (void) fprintf(stderr, gettext( 2807 "Usage: ipsecconf\n" 2808 "\tipsecconf -a ([-]|<filename>) [-q]\n" 2809 "\tipsecconf -c <filename>\n" 2810 "\tipsecconf -r ([-]|<filename>) [-q]\n" 2811 "\tipsecconf -d [-i tunnel-interface] <index>\n" 2812 "\tipsecconf -d <tunnel-interface,index>\n" 2813 "\tipsecconf -l [-n] [-i tunnel-interface]\n" 2814 "\tipsecconf -f [-i tunnel-interface]\n" 2815 "\tipsecconf -L [-n]\n" 2816 "\tipsecconf -F\n")); 2817 } 2818 2819 /* 2820 * a type consists of 2821 * "type" <int>{ "-" <int>} 2822 * or 2823 * "type" keyword 2824 * 2825 * a code consists of 2826 * "code" <int>{ "-" <int>} 2827 * or 2828 * "code" keyword 2829 */ 2830 2831 2832 static int 2833 parse_type_code(const char *str, const str_val_t *table) 2834 { 2835 char *end1, *end2; 2836 int res1 = 0, res2 = 0; 2837 int i; 2838 2839 if (isdigit(str[0])) { 2840 res1 = strtol(str, &end1, 0); 2841 2842 if (end1 == str) { 2843 return (-1); 2844 } 2845 2846 if (res1 > 255 || res1 < 0) { 2847 return (-1); 2848 } 2849 2850 if (*end1 == '-') { 2851 end1++; 2852 res2 = strtol(end1, &end2, 0); 2853 if (res2 > 255 || res2 < 0) { 2854 return (-1); 2855 } 2856 } else { 2857 end2 = end1; 2858 } 2859 2860 while (isspace(*end2)) 2861 end2++; 2862 2863 if (*end2 != '\0') { 2864 return (-1); 2865 } 2866 2867 return (res1 + (res2 << 8)); 2868 } 2869 2870 for (i = 0; table[i].string; i++) { 2871 if (strcmp(str, table[i].string) == 0) { 2872 return (table[i].value); 2873 } 2874 } 2875 2876 return (-1); 2877 } 2878 2879 static int 2880 parse_int(const char *str) 2881 { 2882 char *end; 2883 int res; 2884 2885 res = strtol(str, &end, 0); 2886 if (end == str) 2887 return (-1); 2888 while (isspace(*end)) 2889 end++; 2890 if (*end != '\0') 2891 return (-1); 2892 return (res); 2893 } 2894 2895 /* 2896 * Parses <interface>,<index>. Sets iname or the global interface_name (if 2897 * iname == NULL) to <interface> and returns <index>. Calls exit() if we have 2898 * an interface_name already set. 2899 */ 2900 static int 2901 parse_index(const char *str, char *iname) 2902 { 2903 char *intf, *num, *copy; 2904 int rc; 2905 2906 copy = strdup(str); 2907 if (copy == NULL) { 2908 EXIT_FATAL("Out of memory."); 2909 } 2910 2911 intf = strtok(copy, ","); 2912 /* Just want the rest of the string unmolested, so use "" for arg2. */ 2913 num = strtok(NULL, ""); 2914 if (num == NULL) { 2915 /* No comma found, just parse it like an int. */ 2916 free(copy); 2917 return (parse_int(str)); 2918 } 2919 2920 if (iname != NULL) { 2921 (void) strlcpy(iname, intf, LIFNAMSIZ); 2922 } else { 2923 if (interface_name != NULL) { 2924 EXIT_FATAL("Interface name already selected"); 2925 } 2926 2927 interface_name = strdup(intf); 2928 if (interface_name == NULL) { 2929 EXIT_FATAL("Out of memory."); 2930 } 2931 } 2932 2933 rc = parse_int(num); 2934 free(copy); 2935 return (rc); 2936 } 2937 2938 /* 2939 * Convert a mask to a prefix length. 2940 * Returns prefix length on success, -1 otherwise. 2941 */ 2942 static int 2943 in_getprefixlen(char *mask) 2944 { 2945 int prefixlen; 2946 char *end; 2947 2948 prefixlen = (int)strtol(mask, &end, 10); 2949 if (prefixlen < 0) { 2950 return (-1); 2951 } 2952 if (mask == end) { 2953 return (-1); 2954 } 2955 if (*end != '\0') { 2956 return (-1); 2957 } 2958 return (prefixlen); 2959 } 2960 2961 /* 2962 * Convert a prefix length to a mask. 2963 * Assumes the mask array is zero'ed by the caller. 2964 */ 2965 static void 2966 in_prefixlentomask(unsigned int prefixlen, uchar_t *mask) 2967 { 2968 while (prefixlen > 0) { 2969 if (prefixlen >= 8) { 2970 *mask++ = 0xFF; 2971 prefixlen -= 8; 2972 continue; 2973 } 2974 *mask |= 1 << (8 - prefixlen); 2975 prefixlen--; 2976 } 2977 } 2978 2979 2980 static int 2981 parse_address(int type, char *addr_str) 2982 { 2983 char *ptr; 2984 int prefix_len = 0; 2985 struct netent *ne = NULL; 2986 struct hostent *hp = NULL; 2987 int h_errno; 2988 struct in_addr netaddr; 2989 struct in6_addr *netaddr6; 2990 struct hostent *ne_hent; 2991 boolean_t has_mask = B_FALSE; 2992 2993 ptr = strchr(addr_str, '/'); 2994 if (ptr != NULL) { 2995 has_mask = B_TRUE; 2996 *ptr++ = NULL; 2997 2998 prefix_len = in_getprefixlen(ptr); 2999 if (prefix_len < 0) 3000 return (-1); 3001 } 3002 3003 /* 3004 * getipnodebyname() is thread safe. This allows us to hold on to the 3005 * returned hostent structure, which is pointed to by the shp and 3006 * dhp globals for the source and destination addresses, respectively. 3007 */ 3008 hp = getipnodebyname(addr_str, AF_INET6, AI_DEFAULT | AI_ALL, &h_errno); 3009 if (hp != NULL) { 3010 /* 3011 * We come here for both a hostname and 3012 * any host address /network address. 3013 */ 3014 assert(hp->h_addrtype == AF_INET6); 3015 } else if ((ne = getnetbyname(addr_str)) != NULL) { 3016 switch (ne->n_addrtype) { 3017 case AF_INET: 3018 /* 3019 * Allocate a struct hostent and initialize 3020 * it with the address corresponding to the 3021 * network number previously returned by 3022 * getnetbyname(). Freed by do_address_adds() 3023 * once the policy is defined. 3024 */ 3025 ne_hent = malloc(sizeof (struct hostent)); 3026 if (ne_hent == NULL) { 3027 warn("malloc"); 3028 return (-1); 3029 } 3030 ne_hent->h_addr_list = malloc(2*sizeof (char *)); 3031 if (ne_hent->h_addr_list == NULL) { 3032 warn("malloc"); 3033 free(ne_hent); 3034 return (-1); 3035 } 3036 netaddr6 = malloc(sizeof (struct in6_addr)); 3037 if (netaddr6 == NULL) { 3038 warn("malloc"); 3039 free(ne_hent->h_addr_list); 3040 free(ne_hent); 3041 return (-1); 3042 } 3043 ne_hent->h_addr_list[0] = (char *)netaddr6; 3044 ne_hent->h_addr_list[1] = NULL; 3045 netaddr = inet_makeaddr(ne->n_net, INADDR_ANY); 3046 IN6_INADDR_TO_V4MAPPED(&netaddr, netaddr6); 3047 hp = ne_hent; 3048 break; 3049 default: 3050 warnx("Address type %d not supported.", ne->n_addrtype); 3051 return (-1); 3052 } 3053 } else { 3054 return (-1); 3055 } 3056 3057 if (type == IPSEC_CONF_SRC_ADDRESS) { 3058 shp = hp; 3059 if (has_mask) 3060 splen = prefix_len; 3061 has_saprefix = has_mask; 3062 } else { 3063 dhp = hp; 3064 if (has_mask) 3065 dplen = prefix_len; 3066 has_daprefix = has_mask; 3067 } 3068 3069 return (0); 3070 } 3071 3072 /* 3073 * Add port-only entries. Make sure to add them in both the V6 and V4 tables! 3074 */ 3075 static int 3076 do_port_adds(ips_conf_t *cptr) 3077 { 3078 int ret, diag; 3079 3080 assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)); 3081 assert(IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_addr_v6)); 3082 3083 #ifdef DEBUG_HEAVY 3084 (void) dump_conf(cptr); 3085 #endif 3086 3087 ret = send_pf_pol_message(SPD_ADDRULE, cptr, &diag); 3088 if (ret != 0 && !ipsecconf_qflag) { 3089 warnx( 3090 gettext("Could not add IPv4 policy for sport %d, dport %d " 3091 "- diagnostic %d - %s"), 3092 ntohs(cptr->ips_src_port_min), 3093 ntohs(cptr->ips_dst_port_min), diag, spdsock_diag(diag)); 3094 } 3095 3096 return (ret); 3097 } 3098 3099 /* 3100 * Nuke a list of policy entries. 3101 * rewrite this to use flipping 3102 * d_list isn't freed because we will be 3103 * exiting the program soon. 3104 */ 3105 static void 3106 nuke_adds() 3107 { 3108 d_list_t *temp = d_list; 3109 FILE *policy_fp; 3110 3111 policy_fp = fopen(POLICY_CONF_FILE, "a"); 3112 if (policy_fp == NULL) { 3113 warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 3114 } 3115 (void) fprintf(policy_fp, "\n\n"); 3116 (void) fflush(policy_fp); 3117 3118 while (temp != NULL) { 3119 (void) ipsec_conf_del(temp->index, B_TRUE); 3120 temp = temp->next; 3121 } 3122 } 3123 3124 /* 3125 * Set mask info from the specified prefix len. Fail if multihomed. 3126 */ 3127 static int 3128 set_mask_info(struct hostent *hp, unsigned int plen, struct in6_addr *mask_v6) 3129 { 3130 struct in6_addr addr; 3131 struct in_addr mask_v4; 3132 3133 if (hp->h_addr_list[1] != NULL) { 3134 return (EOPNOTSUPP); 3135 } 3136 3137 if (!IN6_IS_ADDR_UNSPECIFIED(mask_v6)) { 3138 return (EBUSY); 3139 } 3140 3141 bcopy(hp->h_addr_list[0], &addr, sizeof (struct in6_addr)); 3142 if (IN6_IS_ADDR_V4MAPPED(&addr)) { 3143 if (plen > IP_ABITS) { 3144 return (ERANGE); 3145 } 3146 (void) memset(&mask_v4, 0, sizeof (mask_v4)); 3147 in_prefixlentomask(plen, (uchar_t *)&mask_v4); 3148 IN6_INADDR_TO_V4MAPPED(&mask_v4, mask_v6); 3149 } else { 3150 if (plen > IPV6_ABITS) { 3151 return (ERANGE); 3152 } 3153 /* mask_v6 is already zero (unspecified), see test above */ 3154 in_prefixlentomask(plen, (uchar_t *)mask_v6); 3155 } 3156 return (0); 3157 } 3158 3159 /* 3160 * Initialize the specified IPv6 address with all f's. 3161 */ 3162 static void 3163 init_addr_wildcard(struct in6_addr *addr_v6, boolean_t isv4) 3164 { 3165 if (isv4) { 3166 uint32_t addr_v4 = 0xffffffff; 3167 IN6_INADDR_TO_V4MAPPED((struct in_addr *)&addr_v4, addr_v6); 3168 } else { 3169 (void) memset(addr_v6, 0xff, sizeof (struct in6_addr)); 3170 } 3171 } 3172 3173 /* 3174 * Called at the end to actually add policy. Handles single and multi-homed 3175 * cases. 3176 */ 3177 static int 3178 do_address_adds(ips_conf_t *cptr, int *diag) 3179 { 3180 int i, j; 3181 int ret = 0; /* For ioctl() call. */ 3182 int rc = 0; /* My own return code. */ 3183 struct in6_addr zeroes = {0, 0, 0, 0}; 3184 char *ptr[2]; 3185 struct hostent hent; 3186 boolean_t isv4; 3187 int add_count = 0; 3188 3189 /* 3190 * dst_hent may not be initialized if a destination 3191 * address was not given. It will be initalized with just 3192 * one address if a destination address was given. In both 3193 * the cases, we initialize here with ipsc_dst_addr and enter 3194 * the loop below. 3195 */ 3196 if (dhp == NULL) { 3197 assert(shp != NULL); 3198 hent.h_addr_list = ptr; 3199 ptr[0] = (char *)&zeroes.s6_addr; 3200 ptr[1] = NULL; 3201 dhp = &hent; 3202 } else if (shp == NULL) { 3203 assert(dhp != NULL); 3204 hent.h_addr_list = ptr; 3205 ptr[0] = (char *)&zeroes.s6_addr; 3206 ptr[1] = NULL; 3207 shp = &hent; 3208 } 3209 3210 /* 3211 * Set mask info here. Bail if multihomed and there's a prefix len. 3212 */ 3213 if (has_saprefix) { 3214 rc = set_mask_info(shp, splen, &cptr->ips_src_mask_v6); 3215 if (rc != 0) 3216 goto bail; 3217 cptr->ips_src_mask_len = splen; 3218 } 3219 3220 if (has_daprefix) { 3221 rc = set_mask_info(dhp, dplen, &cptr->ips_dst_mask_v6); 3222 if (rc != 0) 3223 goto bail; 3224 cptr->ips_dst_mask_len = dplen; 3225 } 3226 3227 for (i = 0; shp->h_addr_list[i] != NULL; i++) { 3228 bcopy(shp->h_addr_list[i], &cptr->ips_src_addr_v6, 3229 sizeof (struct in6_addr)); 3230 isv4 = cptr->ips_isv4 = 3231 IN6_IS_ADDR_V4MAPPED(&cptr->ips_src_addr_v6); 3232 if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_mask_v6) && 3233 shp != &hent) { 3234 init_addr_wildcard(&cptr->ips_src_mask_v6, isv4); 3235 } 3236 3237 for (j = 0; dhp->h_addr_list[j] != NULL; j++) { 3238 bcopy(dhp->h_addr_list[j], &cptr->ips_dst_addr_v6, 3239 sizeof (struct in6_addr)); 3240 if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_src_addr_v6)) { 3241 /* 3242 * Src was not specified, so update isv4 flag 3243 * for this policy according to the family 3244 * of the destination address. 3245 */ 3246 isv4 = cptr->ips_isv4 = 3247 IN6_IS_ADDR_V4MAPPED( 3248 &cptr->ips_dst_addr_v6); 3249 } else if ((dhp != &hent) && (isv4 != 3250 IN6_IS_ADDR_V4MAPPED(&cptr->ips_dst_addr_v6))) { 3251 /* v6/v4 mismatch. */ 3252 continue; 3253 } 3254 if (IN6_IS_ADDR_UNSPECIFIED(&cptr->ips_dst_mask_v6) && 3255 dhp != &hent) { 3256 init_addr_wildcard(&cptr->ips_dst_mask_v6, 3257 isv4); 3258 } 3259 3260 ret = send_pf_pol_message(SPD_ADDRULE, cptr, diag); 3261 3262 if (ret == 0) { 3263 add_count++; 3264 } else { 3265 /* For now, allow duplicate/overlap policies. */ 3266 if (ret != EEXIST) { 3267 /* 3268 * We have an error where we added 3269 * some, but had errors with others. 3270 * Undo the previous adds, and 3271 * bail. 3272 */ 3273 rc = ret; 3274 goto bail; 3275 } 3276 } 3277 3278 bzero(&cptr->ips_dst_mask_v6, 3279 sizeof (struct in6_addr)); 3280 } 3281 3282 bzero(&cptr->ips_src_mask_v6, sizeof (struct in6_addr)); 3283 } 3284 3285 bail: 3286 if (shp != &hent) 3287 freehostent(shp); 3288 shp = NULL; 3289 if (dhp != &hent) 3290 freehostent(dhp); 3291 dhp = NULL; 3292 splen = 0; 3293 dplen = 0; 3294 3295 if ((add_count == 0) && (rc == 0)) { 3296 /* 3297 * No entries were added. We failed all adds 3298 * because the entries already existed, or because 3299 * no v4 or v6 src/dst pairs were found. Either way, 3300 * we must fail here with an appropriate error 3301 * to avoid a corresponding entry from being added 3302 * to ipsecpolicy.conf. 3303 */ 3304 if ((ret == EEXIST)) { 3305 /* All adds failed with EEXIST */ 3306 rc = EEXIST; 3307 } else { 3308 /* No matching v4 or v6 src/dst pairs */ 3309 rc = ESRCH; 3310 } 3311 } 3312 3313 return (rc); 3314 } 3315 3316 static int 3317 parse_mask(int type, char *mask_str, ips_conf_t *cptr) 3318 { 3319 struct in_addr mask; 3320 struct in6_addr *mask6; 3321 3322 if (type == IPSEC_CONF_SRC_MASK) { 3323 mask6 = &cptr->ips_src_mask_v6; 3324 } else { 3325 mask6 = &cptr->ips_dst_mask_v6; 3326 } 3327 3328 if ((strncasecmp(mask_str, "0x", 2) == 0) && 3329 (strchr(mask_str, '.') == NULL)) { 3330 /* Is it in the form 0xff000000 ? */ 3331 char *end; 3332 3333 mask.s_addr = strtoul(mask_str, &end, 0); 3334 if (end == mask_str) { 3335 return (-1); 3336 } 3337 if (*end != '\0') { 3338 return (-1); 3339 } 3340 mask.s_addr = htonl(mask.s_addr); 3341 } else { 3342 /* 3343 * Since inet_addr() returns -1 on error, we have 3344 * to convert a broadcast address ourselves. 3345 */ 3346 if (strcmp(mask_str, "255.255.255.255") == 0) { 3347 mask.s_addr = 0xffffffff; 3348 } else { 3349 mask.s_addr = inet_addr(mask_str); 3350 if (mask.s_addr == (unsigned int)-1) 3351 return (-1); 3352 } 3353 } 3354 3355 /* Should we check for non-contiguous masks ? */ 3356 if (mask.s_addr == 0) 3357 return (-1); 3358 IN6_INADDR_TO_V4MAPPED(&mask, mask6); 3359 3360 3361 if (type == IPSEC_CONF_SRC_MASK) { 3362 cptr->ips_src_mask_len = in_masktoprefix(mask6->s6_addr, 3363 B_TRUE); 3364 } else { 3365 cptr->ips_dst_mask_len = in_masktoprefix(mask6->s6_addr, 3366 B_TRUE); 3367 } 3368 3369 return (0); 3370 } 3371 3372 static int 3373 parse_port(int type, char *port_str, ips_conf_t *conf) 3374 { 3375 struct servent *sent; 3376 in_port_t port; 3377 int ret; 3378 3379 sent = getservbyname(port_str, NULL); 3380 if (sent == NULL) { 3381 ret = parse_int(port_str); 3382 if (ret < 0 || ret >= 65536) { 3383 return (-1); 3384 } 3385 port = htons((in_port_t)ret); 3386 } else { 3387 port = sent->s_port; 3388 } 3389 if (type == IPSEC_CONF_SRC_PORT) { 3390 conf->ips_src_port_min = conf->ips_src_port_max = port; 3391 } else { 3392 conf->ips_dst_port_min = conf->ips_dst_port_max = port; 3393 } 3394 return (0); 3395 } 3396 3397 static int 3398 valid_algorithm(int proto_num, const char *str) 3399 { 3400 const char *tmp; 3401 int ret; 3402 struct ipsecalgent *alg; 3403 3404 /* Short-circuit "none" */ 3405 if (strncasecmp("none", str, 5) == 0) 3406 return (-2); 3407 3408 alg = getipsecalgbyname(str, proto_num, NULL); 3409 if (alg != NULL) { 3410 ret = alg->a_alg_num; 3411 freeipsecalgent(alg); 3412 return (ret); 3413 } 3414 3415 /* 3416 * Look whether it could be a valid number. 3417 * We support numbers also so that users can 3418 * load algorithms as they need it. We can't 3419 * check for validity of numbers here. It will 3420 * be checked when the SA is negotiated/looked up. 3421 * parse_int uses strtol(str), which converts 3DES 3422 * to a valid number i.e looks only at initial 3423 * number part. If we come here we should expect 3424 * only a decimal number. 3425 */ 3426 tmp = str; 3427 while (*tmp) { 3428 if (!isdigit(*tmp)) 3429 return (-1); 3430 tmp++; 3431 } 3432 3433 ret = parse_int(str); 3434 if (ret > 0 && ret <= 255) 3435 return (ret); 3436 else 3437 return (-1); 3438 } 3439 3440 static int 3441 parse_ipsec_alg(char *str, ips_act_props_t *iap, int alg_type) 3442 { 3443 int alg_value; 3444 char tstr[VALID_ALG_LEN]; 3445 char *lens = NULL; 3446 char *l1_str; 3447 int l1 = 0; 3448 char *l2_str; 3449 int l2 = SPD_MAX_MAXBITS; 3450 algreq_t *ap; 3451 uint_t a_type; 3452 3453 fetch_algorithms(); 3454 3455 /* 3456 * Make sure that we get a null terminated string. 3457 * For a bad input, we truncate at VALID_ALG_LEN. 3458 */ 3459 (void) strlcpy(tstr, str, VALID_ALG_LEN); 3460 lens = strtok(tstr, "()"); 3461 lens = strtok(NULL, "()"); 3462 3463 if (lens != NULL) { 3464 int len1 = 0; 3465 int len2 = SPD_MAX_MAXBITS; 3466 int len_all = strlen(lens); 3467 int dot_start = (lens[0] == '.'); 3468 l1_str = strtok(lens, "."); 3469 l2_str = strtok(NULL, "."); 3470 if (l1_str != NULL) { 3471 l1 = parse_int(l1_str); 3472 len1 = strlen(l1_str); 3473 if (len1 < 0) 3474 return (1); 3475 } 3476 if (l2_str != NULL) { 3477 l2 = parse_int(l2_str); 3478 len2 = strlen(l2_str); 3479 if (len2 < 0) 3480 return (1); 3481 } 3482 3483 if (len_all == len1) { 3484 /* alg(n) */ 3485 l2 = l1; 3486 } else if (dot_start) { 3487 /* alg(..n) */ 3488 l2 = l1; 3489 l1 = 0; 3490 } else if ((len_all - 2) == len1) { 3491 /* alg(n..) */ 3492 l2 = SPD_MAX_MAXBITS; 3493 } /* else alg(n..m) */ 3494 } 3495 3496 if (alg_type == SPD_ATTR_AH_AUTH || 3497 alg_type == SPD_ATTR_ESP_AUTH) { 3498 alg_value = valid_algorithm(IPSEC_PROTO_AH, tstr); 3499 } else { 3500 alg_value = valid_algorithm(IPSEC_PROTO_ESP, tstr); 3501 } 3502 if (alg_value < 0) { 3503 /* Invalid algorithm or "none" */ 3504 return (alg_value); 3505 } 3506 3507 if (alg_type == SPD_ATTR_AH_AUTH) { 3508 a_type = AH_AUTH; 3509 iap->iap_attr |= SPD_APPLY_AH; 3510 ap = &(iap->iap_aauth); 3511 } else if (alg_type == SPD_ATTR_ESP_AUTH) { 3512 a_type = ESP_AUTH; 3513 iap->iap_attr |= SPD_APPLY_ESP|SPD_APPLY_ESPA; 3514 ap = &(iap->iap_eauth); 3515 } else { 3516 a_type = ESP_ENCR; 3517 iap->iap_attr |= SPD_APPLY_ESP; 3518 ap = &(iap->iap_eencr); 3519 } 3520 3521 ap->alg_id = alg_value; 3522 ap->alg_minbits = l1; 3523 ap->alg_maxbits = l2; 3524 3525 if (!alg_rangecheck(a_type, alg_value, ap)) 3526 return (1); 3527 3528 return (0); 3529 } 3530 3531 static char * 3532 sys_error_message(int syserr) 3533 { 3534 char *mesg; 3535 3536 switch (syserr) { 3537 case EEXIST: 3538 mesg = gettext("Entry already exists"); 3539 break; 3540 case ENOENT: 3541 mesg = gettext("Tunnel not found"); 3542 break; 3543 case EINVAL: 3544 mesg = gettext("Invalid entry"); 3545 break; 3546 default : 3547 mesg = strerror(syserr); 3548 } 3549 return (mesg); 3550 } 3551 3552 static void 3553 error_message(error_type_t error, int type, int line) 3554 { 3555 char *mesg; 3556 3557 switch (type) { 3558 case IPSEC_CONF_SRC_ADDRESS: 3559 mesg = gettext("Source Address"); 3560 break; 3561 case IPSEC_CONF_DST_ADDRESS: 3562 mesg = gettext("Destination Address"); 3563 break; 3564 case IPSEC_CONF_SRC_PORT: 3565 mesg = gettext("Source Port"); 3566 break; 3567 case IPSEC_CONF_DST_PORT: 3568 mesg = gettext("Destination Port"); 3569 break; 3570 case IPSEC_CONF_SRC_MASK: 3571 mesg = gettext("Source Mask"); 3572 break; 3573 case IPSEC_CONF_DST_MASK: 3574 mesg = gettext("Destination Mask"); 3575 break; 3576 case IPSEC_CONF_ULP: 3577 mesg = gettext("Upper Layer Protocol"); 3578 break; 3579 case IPSEC_CONF_IPSEC_AALGS: 3580 mesg = gettext("Authentication Algorithm"); 3581 break; 3582 case IPSEC_CONF_IPSEC_EALGS: 3583 mesg = gettext("Encryption Algorithm"); 3584 break; 3585 case IPSEC_CONF_IPSEC_EAALGS: 3586 mesg = gettext("ESP Authentication Algorithm"); 3587 break; 3588 case IPSEC_CONF_IPSEC_SA: 3589 mesg = gettext("SA"); 3590 break; 3591 case IPSEC_CONF_IPSEC_DIR: 3592 mesg = gettext("Direction"); 3593 break; 3594 case IPSEC_CONF_ICMP_TYPE: 3595 mesg = gettext("ICMP type"); 3596 break; 3597 case IPSEC_CONF_ICMP_CODE: 3598 mesg = gettext("ICMP code"); 3599 break; 3600 case IPSEC_CONF_NEGOTIATE: 3601 mesg = gettext("Negotiate"); 3602 break; 3603 case IPSEC_CONF_TUNNEL: 3604 mesg = gettext("Tunnel"); 3605 break; 3606 default : 3607 return; 3608 } 3609 /* 3610 * If we never read a newline character, we don't want 3611 * to print 0. 3612 */ 3613 warnx(gettext("%s%s%s %s on line: %d"), 3614 (error == BAD_ERROR) ? gettext("Bad") : "", 3615 (error == DUP_ERROR) ? gettext("Duplicate") : "", 3616 (error == REQ_ERROR) ? gettext("Requires") : "", 3617 mesg, 3618 (arg_indices[line] == 0) ? 1 : arg_indices[line]); 3619 } 3620 3621 static int 3622 validate_properties(ips_act_props_t *cptr, boolean_t dir, boolean_t is_alg) 3623 { 3624 if (cptr->iap_action == SPD_ACTTYPE_PASS || 3625 cptr->iap_action == SPD_ACTTYPE_DROP) { 3626 if (!dir) { 3627 warnx(gettext("dir string " 3628 "not found for bypass policy")); 3629 } 3630 3631 if (is_alg) { 3632 warnx(gettext("Algorithms found for bypass policy")); 3633 return (-1); 3634 } 3635 return (0); 3636 } 3637 if (!is_alg) { 3638 warnx(gettext("No IPsec algorithms given")); 3639 return (-1); 3640 } 3641 if (cptr->iap_attr == 0) { 3642 warnx(gettext("No SA attribute")); 3643 return (-1); 3644 } 3645 return (0); 3646 } 3647 3648 /* 3649 * This function is called only to parse a single rule's worth of 3650 * action strings. This is called after parsing pattern and before 3651 * parsing properties. Thus we may have something in the leftover 3652 * buffer while parsing the pattern, which we need to handle here. 3653 */ 3654 static int 3655 parse_action(FILE *fp, char **action, char **leftover) 3656 { 3657 char *cp; 3658 char ibuf[MAXLEN]; 3659 char *tmp_buf; 3660 char *buf; 3661 boolean_t new_stuff; 3662 3663 if (*leftover != NULL) { 3664 buf = *leftover; 3665 new_stuff = B_FALSE; 3666 goto scan; 3667 } 3668 while (fgets(ibuf, MAXLEN, fp) != NULL) { 3669 new_stuff = B_TRUE; 3670 if (ibuf[strlen(ibuf) - 1] == '\n') 3671 linecount++; 3672 buf = ibuf; 3673 scan: 3674 /* Truncate at the beginning of a comment */ 3675 cp = strchr(buf, '#'); 3676 if (cp != NULL) 3677 *cp = NULL; 3678 3679 /* Skip any whitespace */ 3680 while (*buf != NULL && isspace(*buf)) 3681 buf++; 3682 3683 /* Empty line */ 3684 if (*buf == NULL) 3685 continue; 3686 3687 /* 3688 * Store the command for error reporting 3689 * and ipsec_conf_add(). 3690 */ 3691 if (new_stuff) { 3692 /* 3693 * Check for buffer overflow including the null 3694 * terminating character. 3695 */ 3696 int len = strlen(ibuf); 3697 if ((cbuf_offset + len + 1) >= CBUF_LEN) 3698 return (-1); 3699 (void) strcpy(cbuf + cbuf_offset, ibuf); 3700 cbuf_offset += len; 3701 } 3702 /* 3703 * Start of the non-empty non-space character. 3704 */ 3705 tmp_buf = buf++; 3706 3707 /* Skip until next whitespace or CURL_BEGIN */ 3708 while (*buf != NULL && !isspace(*buf) && 3709 *buf != CURL_BEGIN) 3710 buf++; 3711 3712 3713 if (*buf != NULL) { 3714 if (*buf == CURL_BEGIN) { 3715 *buf = NULL; 3716 /* Allocate an extra byte for the null also */ 3717 if ((*action = malloc(strlen(tmp_buf) + 1)) == 3718 NULL) { 3719 warn("malloc"); 3720 return (ENOMEM); 3721 } 3722 (void) strcpy(*action, tmp_buf); 3723 *buf = CURL_BEGIN; 3724 } else { 3725 /* We have hit a space */ 3726 *buf++ = NULL; 3727 /* Allocate an extra byte for the null also */ 3728 if ((*action = malloc(strlen(tmp_buf) + 1)) == 3729 NULL) { 3730 warn("malloc"); 3731 return (ENOMEM); 3732 } 3733 (void) strcpy(*action, tmp_buf); 3734 } 3735 /* 3736 * Copy the rest of the line into the 3737 * leftover buffer. 3738 */ 3739 if (*buf != NULL) { 3740 (void) strlcpy(lo_buf, buf, sizeof (lo_buf)); 3741 *leftover = lo_buf; 3742 } else { 3743 *leftover = NULL; 3744 } 3745 } else { 3746 /* Allocate an extra byte for the null also */ 3747 if ((*action = malloc(strlen(tmp_buf) + 1)) == 3748 NULL) { 3749 warn("malloc"); 3750 return (ENOMEM); 3751 } 3752 (void) strcpy(*action, tmp_buf); 3753 *leftover = NULL; 3754 } 3755 if (argindex >= ARG_BUF_LEN) 3756 return (-1); 3757 arg_indices[argindex++] = linecount; 3758 return (PARSE_SUCCESS); 3759 } 3760 /* 3761 * Return error, on an empty action field. 3762 */ 3763 return (-1); 3764 } 3765 3766 /* 3767 * This is called to parse pattern or properties that is enclosed 3768 * between CURL_BEGIN and CURL_END. 3769 */ 3770 static int 3771 parse_pattern_or_prop(FILE *fp, char *argvec[], char **leftover) 3772 { 3773 char *cp; 3774 int i = 0; 3775 boolean_t curl_begin_seen = B_FALSE; 3776 char ibuf[MAXLEN]; 3777 char *tmp_buf; 3778 char *buf; 3779 boolean_t new_stuff; 3780 3781 /* 3782 * When parsing properties, leftover buffer could have the 3783 * leftovers of the previous fgets(). 3784 */ 3785 if (*leftover != NULL) { 3786 buf = *leftover; 3787 new_stuff = B_FALSE; 3788 goto scan; 3789 } 3790 while (fgets(ibuf, MAXLEN, fp) != NULL) { 3791 new_stuff = B_TRUE; 3792 #ifdef DEBUG_HEAVY 3793 (void) printf("%s\n", ibuf); 3794 #endif 3795 if (ibuf[strlen(ibuf) - 1] == '\n') 3796 linecount++; 3797 buf = ibuf; 3798 scan: 3799 /* Truncate at the beginning of a comment */ 3800 cp = strchr(buf, '#'); 3801 if (cp != NULL) 3802 *cp = NULL; 3803 3804 /* Skip any whitespace */ 3805 while (*buf != NULL && isspace(*buf)) 3806 buf++; 3807 3808 /* Empty line */ 3809 if (*buf == NULL) 3810 continue; 3811 /* 3812 * Store the command for error reporting 3813 * and ipsec_conf_add(). 3814 */ 3815 if (new_stuff) { 3816 /* 3817 * Check for buffer overflow including the null 3818 * terminating character. 3819 */ 3820 int len = strlen(ibuf); 3821 if ((cbuf_offset + len + 1) >= CBUF_LEN) 3822 return (-1); 3823 (void) strcpy(cbuf + cbuf_offset, ibuf); 3824 cbuf_offset += len; 3825 } 3826 /* 3827 * First non-space character should be 3828 * a curly bracket. 3829 */ 3830 if (!curl_begin_seen) { 3831 if (*buf != CURL_BEGIN) { 3832 /* 3833 * If we never read a newline character, 3834 * we don't want to print 0. 3835 */ 3836 warnx(gettext("line %d : line must start " 3837 "with \"{\" character"), 3838 (linecount == 0) ? 1 : linecount); 3839 return (-1); 3840 } 3841 buf++; 3842 curl_begin_seen = B_TRUE; 3843 } 3844 /* 3845 * Arguments are separated by white spaces or 3846 * newlines. Scan till you see a CURL_END. 3847 */ 3848 while (*buf != NULL) { 3849 if (*buf == CURL_END) { 3850 ret: 3851 *buf++ = NULL; 3852 /* 3853 * Copy the rest of the line into the 3854 * leftover buffer if any. 3855 */ 3856 if (*buf != NULL) { 3857 (void) strlcpy(lo_buf, buf, 3858 sizeof (lo_buf)); 3859 *leftover = lo_buf; 3860 } else { 3861 *leftover = NULL; 3862 } 3863 return (PARSE_SUCCESS); 3864 } 3865 /* 3866 * Skip any trailing whitespace until we see a 3867 * non white-space character. 3868 */ 3869 while (*buf != NULL && isspace(*buf)) 3870 buf++; 3871 3872 if (*buf == CURL_END) 3873 goto ret; 3874 3875 /* Scan the next line as this buffer is empty */ 3876 if (*buf == NULL) 3877 break; 3878 3879 if (i >= MAXARGS) { 3880 warnx( 3881 gettext("Number of Arguments exceeded %d"), 3882 i); 3883 return (-1); 3884 } 3885 /* 3886 * Non-empty, Non-space buffer. 3887 */ 3888 tmp_buf = buf++; 3889 /* 3890 * Real scan of the argument takes place here. 3891 * Skip past till space or CURL_END. 3892 */ 3893 while (*buf != NULL && !isspace(*buf) && 3894 *buf != CURL_END) { 3895 buf++; 3896 } 3897 /* 3898 * Either a space or we have hit the CURL_END or 3899 * the real end. 3900 */ 3901 if (*buf != NULL) { 3902 if (*buf == CURL_END) { 3903 *buf++ = NULL; 3904 if ((argvec[i] = malloc(strlen(tmp_buf) 3905 + 1)) == NULL) { 3906 warn("malloc"); 3907 return (ENOMEM); 3908 } 3909 if (strlen(tmp_buf) != 0) { 3910 (void) strcpy(argvec[i], 3911 tmp_buf); 3912 if (argindex >= ARG_BUF_LEN) 3913 return (-1); 3914 arg_indices[argindex++] = 3915 linecount; 3916 } 3917 /* 3918 * Copy the rest of the line into the 3919 * leftover buffer. 3920 */ 3921 if (*buf != NULL) { 3922 (void) strlcpy(lo_buf, buf, 3923 sizeof (lo_buf)); 3924 *leftover = lo_buf; 3925 } else { 3926 *leftover = NULL; 3927 } 3928 return (PARSE_SUCCESS); 3929 } else { 3930 *buf++ = NULL; 3931 } 3932 } 3933 /* 3934 * Copy this argument and scan for the buffer more 3935 * if it is non-empty. If it is empty scan for 3936 * the next line. 3937 */ 3938 if ((argvec[i] = malloc(strlen(tmp_buf) + 1)) == 3939 NULL) { 3940 warn("malloc"); 3941 return (ENOMEM); 3942 } 3943 (void) strcpy(argvec[i++], tmp_buf); 3944 if (argindex >= ARG_BUF_LEN) 3945 return (-1); 3946 arg_indices[argindex++] = linecount; 3947 } 3948 } 3949 /* 3950 * If nothing is given in the file, it is okay. 3951 * If something is given in the file and it is 3952 * not CURL_BEGIN, we would have returned error 3953 * above. If curl_begin_seen and we are here, 3954 * something is wrong. 3955 */ 3956 if (curl_begin_seen) 3957 return (-1); 3958 return (PARSE_EOF); /* Nothing more in the file */ 3959 } 3960 3961 /* 3962 * Parse one command i.e {pattern} action {properties}. 3963 * 3964 * {pattern} ( action {prop} | pass | drop ) (or ...)* 3965 */ 3966 static int 3967 parse_one(FILE *fp, act_prop_t *act_props) 3968 { 3969 char *leftover; 3970 int ret; 3971 int i; 3972 int ap_num = 0; 3973 enum parse_state {pattern, action, prop } pstate; 3974 3975 has_daprefix = has_saprefix = B_FALSE; 3976 3977 (void) memset(act_props, 0, sizeof (act_prop_t)); 3978 pstate = pattern; 3979 3980 ret = 0; 3981 leftover = NULL; 3982 argindex = 0; 3983 cbuf_offset = 0; 3984 assert(shp == NULL && dhp == NULL); 3985 3986 3987 for (;;) { 3988 switch (pstate) { 3989 case pattern: 3990 { 3991 #ifdef DEBUG_HEAVY 3992 (void) printf("pattern\n"); 3993 #endif 3994 ret = parse_pattern_or_prop(fp, 3995 act_props->pattern, &leftover); 3996 if (ret == PARSE_EOF) { 3997 /* EOF reached */ 3998 return (0); 3999 } 4000 if (ret != 0) { 4001 goto err; 4002 } 4003 pstate = action; 4004 break; 4005 } 4006 case action: 4007 { 4008 #ifdef DEBUG_HEAVY 4009 (void) printf("action\n"); 4010 #endif 4011 ret = parse_action(fp, 4012 &act_props->ap[ap_num].act, &leftover); 4013 if (ret != 0) { 4014 goto err; 4015 } 4016 4017 /* 4018 * Validate action now itself so that we don't 4019 * proceed too much into the bad world. 4020 */ 4021 for (i = 0; action_table[i].string; i++) { 4022 if (strcmp(act_props->ap[ap_num].act, 4023 action_table[i].string) == 0) 4024 break; 4025 } 4026 4027 if (action_table[i].tok_val == TOK_or) { 4028 /* hit an or, go again */ 4029 break; 4030 } 4031 4032 if (action_table[i].string == NULL) { 4033 /* 4034 * If we never read a newline 4035 * character, we don't want 4036 * to print 0. 4037 */ 4038 warnx(gettext("(parsing one command)" 4039 "Invalid action on line %d: %s"), 4040 (linecount == 0) ? 1 : linecount, 4041 act_props->ap[ap_num].act); 4042 return (-1); 4043 } 4044 4045 pstate = prop; 4046 break; 4047 } 4048 case prop: 4049 { 4050 #ifdef DEBUG_HEAVY 4051 (void) printf("prop\n"); 4052 #endif 4053 ret = parse_pattern_or_prop(fp, 4054 act_props->ap[ap_num].prop, &leftover); 4055 if (ret != 0) { 4056 goto err; 4057 } 4058 4059 if (leftover != NULL) { 4060 /* Accomodate spaces at the end */ 4061 while (*leftover != NULL) { 4062 if (*leftover == 'o') { 4063 leftover++; 4064 if (*leftover == 'r') { 4065 leftover++; 4066 ap_num++; 4067 if (ap_num > MAXARGS) 4068 return (1); 4069 pstate = action; 4070 goto again; 4071 } 4072 4073 } 4074 if (!isspace(*leftover)) { 4075 ret = -1; 4076 goto err; 4077 } 4078 leftover++; 4079 } 4080 return (0); 4081 } 4082 ap_num++; 4083 if (ap_num > MAXARGS) 4084 return (0); 4085 pstate = action; /* or */ 4086 break; 4087 } /* case prop: */ 4088 } /* switch(pstate) */ 4089 4090 again: 4091 if (ap_num > MAXARGS) 4092 return (0); 4093 } /* while(1) */ 4094 err: 4095 if (ret != 0) { 4096 /* 4097 * If we never read a newline character, we don't want 4098 * to print 0. 4099 */ 4100 warnx(gettext("Error before or at line %d"), 4101 (linecount == 0) ? 1 : linecount); 4102 } 4103 return (ret); 4104 } 4105 4106 /* 4107 * convert an act_propts_t to an ips_conf_t 4108 */ 4109 4110 static int 4111 form_ipsec_conf(act_prop_t *act_props, ips_conf_t *cptr) 4112 { 4113 int i, j, k; 4114 int tok_count = 0; 4115 struct protoent *pent; 4116 boolean_t saddr, daddr, ipsec_aalg, ipsec_ealg, ipsec_eaalg, dir; 4117 boolean_t old_style, new_style; 4118 struct in_addr mask; 4119 int line_no; 4120 int ret; 4121 int ap_num = 0; 4122 int type, code, type_end, code_end; 4123 #ifdef DEBUG_HEAVY 4124 /* 4125 * pattern => act_props->pattern 4126 * action => act_props->ap[].act 4127 * properties => act_props->ap[].prop 4128 */ 4129 (void) printf("\npattern\n------------\n"); 4130 for (i = 0; act_props->pattern[i] != NULL; i++) 4131 (void) printf("%s\n", act_props->pattern[i]); 4132 (void) printf("apz\n----------\n"); 4133 for (j = 0; act_props->ap[j].act != NULL; j++) { 4134 4135 (void) printf("act%d->%s\n", j, act_props->ap[j].act); 4136 for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 4137 (void) printf("%dprop%d->%s\n", 4138 j, i, act_props->ap[j].prop[i]); 4139 } 4140 (void) printf("------------\n\n"); 4141 #endif 4142 4143 (void) memset(cptr, 0, sizeof (ips_conf_t)); 4144 saddr = daddr = ipsec_aalg = ipsec_ealg = ipsec_eaalg = dir = B_FALSE; 4145 old_style = new_style = B_FALSE; 4146 /* 4147 * Get the Pattern. NULL pattern is valid. 4148 */ 4149 for (i = 0, line_no = 0; act_props->pattern[i]; i++, line_no++) { 4150 for (j = 0; pattern_table[j].string; j++) { 4151 if (strcmp(act_props->pattern[i], 4152 pattern_table[j].string) == 0) 4153 break; 4154 } 4155 4156 if (pattern_table[j].string == NULL) { 4157 /* 4158 * If we never read a newline character, we don't want 4159 * to print 0. 4160 */ 4161 warnx(gettext("Invalid pattern on line %d: %s"), 4162 (arg_indices[line_no] == 0) ? 1 : 4163 arg_indices[line_no], act_props->pattern[i]); 4164 return (-1); 4165 } 4166 4167 cptr->patt_tok[tok_count++] = pattern_table[j].tok_val; 4168 4169 switch (pattern_table[j].tok_val) { 4170 4171 case TOK_dir: 4172 i++, line_no++; 4173 if (act_props->pattern[i] == NULL) { 4174 error_message(BAD_ERROR, 4175 IPSEC_CONF_IPSEC_DIR, line_no); 4176 return (-1); 4177 } 4178 4179 if (strncmp(act_props->pattern[i], "in", 2) == 0) { 4180 cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 4181 } else if (strncmp( 4182 act_props->pattern[i], "out", 3) == 0) { 4183 cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 4184 } else if (strncmp( 4185 act_props->pattern[i], "both", 4) == 0) { 4186 if (old_style) { 4187 error_message(BAD_ERROR, 4188 IPSEC_CONF_IPSEC_DIR, line_no); 4189 return (-1); 4190 } 4191 new_style = B_TRUE; 4192 cptr->ips_dir = 4193 SPD_RULE_FLAG_OUTBOUND | 4194 SPD_RULE_FLAG_INBOUND; 4195 } else { 4196 error_message(BAD_ERROR, 4197 IPSEC_CONF_IPSEC_DIR, line_no); 4198 return (-1); 4199 } 4200 dir = B_TRUE; 4201 break; 4202 4203 case TOK_local: 4204 if (old_style) { 4205 error_message(BAD_ERROR, 4206 IPSEC_CONF_SRC_ADDRESS, line_no); 4207 return (-1); 4208 } 4209 new_style = B_TRUE; 4210 4211 if (saddr) { 4212 error_message(DUP_ERROR, 4213 IPSEC_CONF_SRC_ADDRESS, line_no); 4214 return (-1); 4215 } 4216 /* 4217 * Use this to detect duplicates rather 4218 * than 0 like other cases, because 0 for 4219 * address means INADDR_ANY. 4220 */ 4221 saddr = B_TRUE; 4222 cptr->has_saddr = 1; 4223 /* 4224 * Advance to the string containing 4225 * the address. 4226 */ 4227 i++, line_no++; 4228 if (act_props->pattern[i] == NULL) { 4229 error_message(BAD_ERROR, 4230 IPSEC_CONF_SRC_ADDRESS, line_no); 4231 return (-1); 4232 } 4233 if (parse_address(IPSEC_CONF_SRC_ADDRESS, 4234 act_props->pattern[i]) != 0) { 4235 error_message(BAD_ERROR, 4236 IPSEC_CONF_SRC_ADDRESS, line_no); 4237 return (-1); 4238 } 4239 if (!cptr->has_smask) 4240 cptr->has_smask = has_saprefix; 4241 4242 break; 4243 case TOK_remote: 4244 if (old_style) { 4245 error_message(BAD_ERROR, 4246 IPSEC_CONF_DST_ADDRESS, line_no); 4247 return (-1); 4248 } 4249 new_style = B_TRUE; 4250 4251 if (daddr) { 4252 error_message(DUP_ERROR, 4253 IPSEC_CONF_DST_ADDRESS, line_no); 4254 return (-1); 4255 } 4256 /* 4257 * Use this to detect duplicates rather 4258 * than 0 like other cases, because 0 for 4259 * address means INADDR_ANY. 4260 */ 4261 daddr = B_TRUE; 4262 cptr->has_daddr = 1; 4263 /* 4264 * Advance to the string containing 4265 * the address. 4266 */ 4267 i++, line_no++; 4268 if (act_props->pattern[i] == NULL) { 4269 error_message(BAD_ERROR, 4270 IPSEC_CONF_DST_ADDRESS, line_no); 4271 return (-1); 4272 } 4273 if (parse_address(IPSEC_CONF_DST_ADDRESS, 4274 act_props->pattern[i]) != 0) { 4275 error_message(BAD_ERROR, 4276 IPSEC_CONF_DST_ADDRESS, line_no); 4277 return (-1); 4278 } 4279 if (!cptr->has_dmask) 4280 cptr->has_dmask = has_daprefix; 4281 break; 4282 4283 case TOK_saddr: 4284 if (new_style) { 4285 error_message(BAD_ERROR, 4286 IPSEC_CONF_SRC_ADDRESS, line_no); 4287 return (-1); 4288 } 4289 old_style = B_TRUE; 4290 4291 if (saddr) { 4292 error_message(DUP_ERROR, 4293 IPSEC_CONF_SRC_ADDRESS, line_no); 4294 return (-1); 4295 } 4296 /* 4297 * Use this to detect duplicates rather 4298 * than 0 like other cases, because 0 for 4299 * address means INADDR_ANY. 4300 */ 4301 saddr = B_TRUE; 4302 cptr->has_saddr = 1; 4303 /* 4304 * Advance to the string containing 4305 * the address. 4306 */ 4307 i++, line_no++; 4308 if (act_props->pattern[i] == NULL) { 4309 error_message(BAD_ERROR, 4310 IPSEC_CONF_SRC_ADDRESS, line_no); 4311 return (-1); 4312 } 4313 4314 if (parse_address(IPSEC_CONF_SRC_ADDRESS, 4315 act_props->pattern[i]) != 0) { 4316 error_message(BAD_ERROR, 4317 IPSEC_CONF_SRC_ADDRESS, line_no); 4318 return (-1); 4319 } 4320 /* shp or bhp? */ 4321 if (!cptr->has_smask) 4322 cptr->has_smask = has_saprefix; 4323 break; 4324 4325 case TOK_daddr: 4326 if (new_style) { 4327 error_message(BAD_ERROR, 4328 IPSEC_CONF_DST_ADDRESS, line_no); 4329 return (-1); 4330 } 4331 old_style = B_TRUE; 4332 4333 if (daddr) { 4334 error_message(DUP_ERROR, 4335 IPSEC_CONF_DST_ADDRESS, line_no); 4336 return (-1); 4337 } 4338 /* 4339 * Use this to detect duplicates rather 4340 * than 0 like other cases, because 0 for 4341 * address means INADDR_ANY. 4342 */ 4343 daddr = B_TRUE; 4344 cptr->has_daddr = 1; 4345 /* 4346 * Advance to the string containing 4347 * the address. 4348 */ 4349 i++, line_no++; 4350 if (act_props->pattern[i] == NULL) { 4351 error_message(BAD_ERROR, 4352 IPSEC_CONF_DST_ADDRESS, line_no); 4353 return (-1); 4354 } 4355 if (parse_address(IPSEC_CONF_DST_ADDRESS, 4356 act_props->pattern[i]) != 0) { 4357 error_message(BAD_ERROR, 4358 IPSEC_CONF_DST_ADDRESS, line_no); 4359 return (-1); 4360 } 4361 if (!cptr->has_dmask) 4362 cptr->has_dmask = has_daprefix; 4363 break; 4364 4365 case TOK_sport: 4366 if (new_style) { 4367 error_message(BAD_ERROR, 4368 IPSEC_CONF_SRC_PORT, line_no); 4369 return (-1); 4370 } 4371 old_style = B_TRUE; 4372 4373 if (cptr->ips_src_port_min != 0) { 4374 error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT, 4375 line_no); 4376 return (-1); 4377 } 4378 i++, line_no++; 4379 if (act_props->pattern[i] == NULL) { 4380 error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 4381 line_no); 4382 return (-1); 4383 } 4384 ret = parse_port(IPSEC_CONF_SRC_PORT, 4385 act_props->pattern[i], cptr); 4386 if (ret != 0) { 4387 error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 4388 line_no); 4389 return (-1); 4390 } 4391 break; 4392 case TOK_dport: 4393 if (new_style) { 4394 error_message(BAD_ERROR, 4395 IPSEC_CONF_DST_PORT, line_no); 4396 return (-1); 4397 } 4398 old_style = B_TRUE; 4399 4400 if (cptr->ips_dst_port_min != 0) { 4401 error_message(DUP_ERROR, IPSEC_CONF_DST_PORT, 4402 line_no); 4403 return (-1); 4404 } 4405 i++, line_no++; 4406 if (act_props->pattern[i] == NULL) { 4407 error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 4408 line_no); 4409 return (-1); 4410 } 4411 ret = parse_port(IPSEC_CONF_DST_PORT, 4412 act_props->pattern[i], 4413 cptr); 4414 if (ret != 0) { 4415 error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 4416 line_no); 4417 return (-1); 4418 } 4419 break; 4420 4421 case TOK_lport: 4422 if (old_style) { 4423 error_message(BAD_ERROR, 4424 IPSEC_CONF_SRC_PORT, line_no); 4425 return (-1); 4426 } 4427 new_style = B_TRUE; 4428 4429 if (cptr->ips_src_port_min != 0) { 4430 error_message(DUP_ERROR, IPSEC_CONF_SRC_PORT, 4431 line_no); 4432 return (-1); 4433 } 4434 i++, line_no++; 4435 if (act_props->pattern[i] == NULL) { 4436 error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 4437 line_no); 4438 return (-1); 4439 } 4440 ret = parse_port(IPSEC_CONF_SRC_PORT, 4441 act_props->pattern[i], 4442 cptr); 4443 if (ret != 0) { 4444 error_message(BAD_ERROR, IPSEC_CONF_SRC_PORT, 4445 line_no); 4446 return (-1); 4447 } 4448 break; 4449 4450 case TOK_rport: 4451 if (old_style) { 4452 error_message(BAD_ERROR, 4453 IPSEC_CONF_DST_PORT, line_no); 4454 return (-1); 4455 } 4456 new_style = B_TRUE; 4457 4458 if (cptr->ips_dst_port_min != 0) { 4459 error_message(DUP_ERROR, IPSEC_CONF_DST_PORT, 4460 line_no); 4461 return (-1); 4462 } 4463 i++, line_no++; 4464 if (act_props->pattern[i] == NULL) { 4465 error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 4466 line_no); 4467 return (-1); 4468 } 4469 ret = parse_port(IPSEC_CONF_DST_PORT, 4470 act_props->pattern[i], 4471 cptr); 4472 if (ret != 0) { 4473 error_message(BAD_ERROR, IPSEC_CONF_DST_PORT, 4474 line_no); 4475 return (-1); 4476 } 4477 break; 4478 4479 case TOK_smask: 4480 if (new_style) { 4481 error_message(BAD_ERROR, 4482 IPSEC_CONF_SRC_MASK, line_no); 4483 return (-1); 4484 } 4485 old_style = B_TRUE; 4486 cptr->has_smask = B_TRUE; 4487 4488 IN6_V4MAPPED_TO_INADDR(&cptr->ips_src_mask_v6, &mask); 4489 if (mask.s_addr != 0) { 4490 error_message(DUP_ERROR, IPSEC_CONF_SRC_MASK, 4491 line_no); 4492 return (-1); 4493 } 4494 i++, line_no++; 4495 if (act_props->pattern[i] == NULL) { 4496 error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK, 4497 line_no); 4498 return (-1); 4499 } 4500 ret = parse_mask(IPSEC_CONF_SRC_MASK, 4501 act_props->pattern[i], 4502 cptr); 4503 if (ret != 0) { 4504 error_message(BAD_ERROR, IPSEC_CONF_SRC_MASK, 4505 line_no); 4506 return (-1); 4507 } 4508 break; 4509 case TOK_dmask: 4510 if (new_style) { 4511 error_message(BAD_ERROR, 4512 IPSEC_CONF_DST_MASK, line_no); 4513 return (-1); 4514 } 4515 old_style = B_TRUE; 4516 cptr->has_dmask = B_TRUE; 4517 4518 IN6_V4MAPPED_TO_INADDR(&cptr->ips_dst_mask_v6, &mask); 4519 if (mask.s_addr != 0) { 4520 error_message(DUP_ERROR, IPSEC_CONF_DST_MASK, 4521 line_no); 4522 return (-1); 4523 } 4524 i++, line_no++; 4525 if (act_props->pattern[i] == NULL) { 4526 error_message(BAD_ERROR, IPSEC_CONF_DST_MASK, 4527 line_no); 4528 return (-1); 4529 } 4530 ret = parse_mask(IPSEC_CONF_DST_MASK, 4531 act_props->pattern[i], 4532 cptr); 4533 if (ret != 0) { 4534 error_message(BAD_ERROR, IPSEC_CONF_DST_MASK, 4535 line_no); 4536 return (-1); 4537 } 4538 break; 4539 case TOK_ulp: 4540 if (cptr->ips_ulp_prot != 0) { 4541 error_message(DUP_ERROR, 4542 IPSEC_CONF_ULP, line_no); 4543 return (-1); 4544 } 4545 i++, line_no++; 4546 if (act_props->pattern[i] == NULL) { 4547 error_message(BAD_ERROR, 4548 IPSEC_CONF_ULP, line_no); 4549 return (-1); 4550 } 4551 pent = getprotobyname(act_props->pattern[i]); 4552 if (pent == NULL) { 4553 int ulp; 4554 ulp = parse_int(act_props->pattern[i]); 4555 if (ulp == -1) { 4556 error_message(BAD_ERROR, 4557 IPSEC_CONF_ULP, line_no); 4558 return (-1); 4559 } 4560 cptr->ips_ulp_prot = ulp; 4561 } else { 4562 cptr->ips_ulp_prot = pent->p_proto; 4563 } 4564 break; 4565 case TOK_type: 4566 if (cptr->has_type) { 4567 error_message(DUP_ERROR, 4568 IPSEC_CONF_ICMP_TYPE, line_no); 4569 return (-1); 4570 } 4571 4572 i++, line_no++; 4573 type = parse_type_code(act_props->pattern[i], 4574 icmp_type_table); 4575 4576 if (type > 65536 || type < 0) { 4577 error_message(BAD_ERROR, 4578 IPSEC_CONF_ICMP_TYPE, line_no); 4579 return (-1); 4580 } 4581 4582 type_end = type / 256; 4583 type = type % 256; 4584 4585 if (type_end < type) 4586 type_end = type; 4587 4588 cptr->has_type = 1; 4589 cptr->ips_icmp_type = (uint8_t)type; 4590 cptr->ips_icmp_type_end = (uint8_t)type_end; 4591 break; 4592 case TOK_code: 4593 if (!cptr->has_type) { 4594 error_message(BAD_ERROR, 4595 IPSEC_CONF_ICMP_CODE, line_no); 4596 return (-1); 4597 } 4598 4599 if (cptr->has_code) { 4600 error_message(DUP_ERROR, 4601 IPSEC_CONF_ICMP_CODE, line_no); 4602 return (-1); 4603 } 4604 4605 i++, line_no++; 4606 4607 code = parse_type_code(act_props->pattern[i], 4608 icmp_code_table); 4609 if (type > 65536 || type < 0) { 4610 error_message(BAD_ERROR, 4611 IPSEC_CONF_ICMP_CODE, line_no); 4612 return (-1); 4613 } 4614 code_end = code / 256; 4615 code = code % 256; 4616 4617 if (code_end < code) 4618 code_end = code; 4619 4620 cptr->has_code = 1; 4621 cptr->ips_icmp_code = (uint8_t)code; 4622 cptr->ips_icmp_code_end = (uint8_t)code_end; 4623 break; 4624 case TOK_tunnel: 4625 if (cptr->has_tunnel == 1) { 4626 error_message(BAD_ERROR, 4627 IPSEC_CONF_TUNNEL, line_no); 4628 return (-1); 4629 } 4630 i++, line_no++; 4631 if (act_props->pattern[i] == NULL) { 4632 error_message(BAD_ERROR, 4633 IPSEC_CONF_TUNNEL, line_no); 4634 return (-1); 4635 } 4636 4637 if (strlcpy(tunif, act_props->pattern[i], 4638 TUNNAMEMAXLEN) >= TUNNAMEMAXLEN) { 4639 error_message(BAD_ERROR, 4640 IPSEC_CONF_TUNNEL, line_no); 4641 return (-1); 4642 } 4643 cptr->has_tunnel = 1; 4644 break; 4645 case TOK_negotiate: 4646 if (cptr->has_negotiate == 1) { 4647 error_message(BAD_ERROR, 4648 IPSEC_CONF_NEGOTIATE, line_no); 4649 return (-1); 4650 } 4651 i++, line_no++; 4652 if (act_props->pattern[i] == NULL) { 4653 error_message(BAD_ERROR, 4654 IPSEC_CONF_NEGOTIATE, line_no); 4655 return (-1); 4656 } 4657 4658 if (strncmp(act_props->pattern[i], "tunnel", 6) == 0) { 4659 cptr->ips_tunnel = B_TRUE; 4660 } else if (strncmp( 4661 act_props->pattern[i], "transport", 9) != 0) { 4662 error_message(BAD_ERROR, 4663 IPSEC_CONF_NEGOTIATE, line_no); 4664 return (-1); 4665 } 4666 cptr->has_negotiate = 1; 4667 break; 4668 } 4669 4670 } 4671 4672 /* Sanity check that certain tokens occur together */ 4673 if (cptr->has_tunnel + cptr->has_negotiate == 1) { 4674 if (cptr->has_negotiate == 0) { 4675 error_message(REQ_ERROR, IPSEC_CONF_NEGOTIATE, line_no); 4676 } else { 4677 error_message(REQ_ERROR, IPSEC_CONF_TUNNEL, line_no); 4678 } 4679 errx(1, gettext( 4680 "tunnel and negotiate tokens must occur together")); 4681 return (-1); 4682 } 4683 4684 /* 4685 * Get the actions. 4686 */ 4687 4688 for (ap_num = 0; act_props->ap[ap_num].act != NULL; ap_num++) { 4689 ips_act_props_t *iap; 4690 4691 if (ap_num > 0) { 4692 /* or's only with new style */ 4693 if (old_style) { 4694 (void) printf("%s\n", gettext( 4695 "or's only with new style")); 4696 return (-1); 4697 } 4698 new_style = B_TRUE; 4699 } 4700 4701 ipsec_aalg = ipsec_ealg = ipsec_eaalg = B_FALSE; 4702 tok_count = 0; 4703 4704 for (k = 0; action_table[k].string; k++) { 4705 if (strcmp(act_props->ap[ap_num].act, 4706 action_table[k].string) == 0) 4707 break; 4708 } 4709 /* 4710 * The following thing should never happen as 4711 * we have already tested for its validity in parse. 4712 */ 4713 if (action_table[k].string == NULL) { 4714 warnx(gettext("(form act)Invalid action on line " 4715 "%d: %s"), (arg_indices[line_no] == 0) ? 1 : 4716 arg_indices[line_no], 4717 act_props->ap[ap_num].act); 4718 warnx("%s", act_props->ap[ap_num].act); 4719 return (-1); 4720 } 4721 4722 /* we have a good action alloc an iap */ 4723 iap = alloc_iap(cptr); 4724 4725 iap->iap_action = action_table[k].value; 4726 iap->iap_act_tok = action_table[k].tok_val; 4727 4728 switch (action_table[k].tok_val) { 4729 case TOK_apply: 4730 cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 4731 break; 4732 case TOK_permit: 4733 cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 4734 break; 4735 case TOK_ipsec: 4736 if (old_style) { 4737 /* Using saddr/daddr with ipsec action. */ 4738 if (!dir) { 4739 /* No direction specified */ 4740 error_message(REQ_ERROR, 4741 IPSEC_CONF_IPSEC_DIR, line_no); 4742 return (-1); 4743 } 4744 if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND) 4745 /* 4746 * Need to swap addresses if 4747 * 'dir in' or translation to 4748 * laddr/raddr will be incorrect. 4749 */ 4750 cptr->swap = 1; 4751 } 4752 if (!dir) 4753 cptr->ips_dir = 4754 SPD_RULE_FLAG_INBOUND 4755 |SPD_RULE_FLAG_OUTBOUND; 4756 break; 4757 case TOK_bypass: 4758 /* do something? */ 4759 break; 4760 } 4761 4762 line_no++; 4763 /* 4764 * Get the properties. NULL properties is not valid. 4765 * Later checks will catch it. 4766 */ 4767 for (i = 0; act_props->ap[ap_num].prop[i]; i++, line_no++) { 4768 for (j = 0; property_table[j].string; j++) { 4769 if (strcmp(act_props->ap[ap_num].prop[i], 4770 property_table[j].string) == 0) { 4771 break; 4772 } 4773 } 4774 if (property_table[j].string == NULL) { 4775 warnx(gettext("Invalid properties on line " 4776 "%d: %s"), 4777 (arg_indices[line_no] == 0) ? 4778 1 : arg_indices[line_no], 4779 act_props->ap[ap_num].prop[i]); 4780 return (-1); 4781 } 4782 4783 iap->iap_attr_tok[tok_count++] 4784 = property_table[j].value; 4785 4786 switch (property_table[j].value) { 4787 case SPD_ATTR_AH_AUTH: 4788 if (ipsec_aalg) { 4789 error_message(DUP_ERROR, 4790 IPSEC_CONF_IPSEC_AALGS, line_no); 4791 return (-1); 4792 } 4793 i++, line_no++; 4794 if (act_props->ap[ap_num].prop[i] == NULL) { 4795 error_message(BAD_ERROR, 4796 IPSEC_CONF_IPSEC_AALGS, line_no); 4797 return (-1); 4798 } 4799 ret = parse_ipsec_alg( 4800 act_props->ap[ap_num].prop[i], 4801 iap, SPD_ATTR_AH_AUTH); 4802 if (ret == -2) { 4803 /* "none" - ignore */ 4804 break; 4805 } 4806 if (ret != 0) { 4807 error_message(BAD_ERROR, 4808 IPSEC_CONF_IPSEC_AALGS, line_no); 4809 return (-1); 4810 } 4811 ipsec_aalg = B_TRUE; 4812 break; 4813 case SPD_ATTR_ESP_ENCR: 4814 /* 4815 * If this option was not given 4816 * and encr_auth_algs was given, 4817 * we provide null-encryption. We do the 4818 * setting after we parse all the options. 4819 */ 4820 if (ipsec_ealg) { 4821 error_message(DUP_ERROR, 4822 IPSEC_CONF_IPSEC_EALGS, line_no); 4823 return (-1); 4824 } 4825 i++, line_no++; 4826 if (act_props->ap[ap_num].prop[i] == NULL) { 4827 error_message(BAD_ERROR, 4828 IPSEC_CONF_IPSEC_EALGS, line_no); 4829 return (-1); 4830 } 4831 ret = parse_ipsec_alg( 4832 act_props->ap[ap_num].prop[i], 4833 iap, SPD_ATTR_ESP_ENCR); 4834 if (ret == -2) { 4835 /* "none" - ignore */ 4836 break; 4837 } 4838 if (ret != 0) { 4839 error_message(BAD_ERROR, 4840 IPSEC_CONF_IPSEC_EALGS, line_no); 4841 return (-1); 4842 } 4843 ipsec_ealg = B_TRUE; 4844 break; 4845 case SPD_ATTR_ESP_AUTH: 4846 /* 4847 * If this option was not given and encr_algs 4848 * option was given, we still pass a default 4849 * value in ipsc_esp_auth_algs. This is to 4850 * encourage the use of authentication with 4851 * ESP. 4852 */ 4853 if (ipsec_eaalg) { 4854 error_message(DUP_ERROR, 4855 IPSEC_CONF_IPSEC_EAALGS, line_no); 4856 return (-1); 4857 } 4858 i++, line_no++; 4859 if (act_props->ap[ap_num].prop[i] == NULL) { 4860 error_message(BAD_ERROR, 4861 IPSEC_CONF_IPSEC_EAALGS, line_no); 4862 return (-1); 4863 } 4864 ret = parse_ipsec_alg( 4865 act_props->ap[ap_num].prop[i], 4866 iap, SPD_ATTR_ESP_AUTH); 4867 if (ret == -2) { 4868 /* "none" - ignore */ 4869 break; 4870 } 4871 if (ret != 0) { 4872 error_message(BAD_ERROR, 4873 IPSEC_CONF_IPSEC_EAALGS, line_no); 4874 return (-1); 4875 } 4876 ipsec_eaalg = B_TRUE; 4877 break; 4878 case IPS_SA: 4879 i++, line_no++; 4880 if (act_props->ap[ap_num].prop[i] == NULL) { 4881 error_message(BAD_ERROR, 4882 IPSEC_CONF_IPSEC_SA, line_no); 4883 return (-1); 4884 } 4885 4886 if (strcmp(act_props->ap[ap_num].prop[i], 4887 "unique") == 0) { 4888 iap->iap_attr |= SPD_APPLY_UNIQUE; 4889 } else if (strcmp(act_props->ap[ap_num].prop[i], 4890 "shared") != 0) { 4891 /* "shared" is default. */ 4892 error_message(BAD_ERROR, 4893 IPSEC_CONF_IPSEC_SA, line_no); 4894 return (-1); 4895 } 4896 4897 break; 4898 case IPS_DIR: 4899 if (dir) { 4900 error_message(DUP_ERROR, 4901 IPSEC_CONF_IPSEC_DIR, line_no); 4902 return (-1); 4903 } 4904 if (new_style) { 4905 error_message(BAD_ERROR, 4906 IPSEC_CONF_IPSEC_DIR, line_no); 4907 return (-1); 4908 } 4909 old_style = B_TRUE; 4910 dir = B_TRUE; 4911 i++, line_no++; 4912 if (act_props->ap[ap_num].prop[i] == NULL) { 4913 error_message(BAD_ERROR, 4914 IPSEC_CONF_IPSEC_DIR, line_no); 4915 return (-1); 4916 } 4917 if (strcmp(act_props->ap[ap_num].prop[i], 4918 "out") == 0) { 4919 cptr->ips_dir = SPD_RULE_FLAG_OUTBOUND; 4920 } else if (strcmp(act_props->ap[ap_num].prop[i], 4921 "in") == 0) { 4922 cptr->ips_dir = SPD_RULE_FLAG_INBOUND; 4923 } else { 4924 error_message(BAD_ERROR, 4925 IPSEC_CONF_IPSEC_DIR, line_no); 4926 return (-1); 4927 } 4928 if ((cptr->ips_dir & SPD_RULE_FLAG_INBOUND) && 4929 iap->iap_act_tok == TOK_apply) { 4930 warnx(gettext("Direction" 4931 " in conflict with action")); 4932 return (-1); 4933 } 4934 if ((cptr->ips_dir & SPD_RULE_FLAG_OUTBOUND) && 4935 iap->iap_act_tok == TOK_permit) { 4936 warnx(gettext("Direction" 4937 "in conflict with action")); 4938 return (-1); 4939 } 4940 4941 break; 4942 } 4943 } 4944 4945 if (!ipsec_ealg && ipsec_eaalg) { 4946 /* 4947 * If the user has specified the auth alg to be used 4948 * with encryption and did not provide a encryption 4949 * algorithm, provide null encryption. 4950 */ 4951 iap->iap_eencr.alg_id = SADB_EALG_NULL; 4952 ipsec_ealg = B_TRUE; 4953 } 4954 4955 /* Set the level of IPSEC protection we want */ 4956 if (ipsec_aalg && (ipsec_ealg || ipsec_eaalg)) { 4957 iap->iap_attr |= SPD_APPLY_AH|SPD_APPLY_ESP; 4958 } else if (ipsec_aalg) { 4959 iap->iap_attr |= SPD_APPLY_AH; 4960 } else if (ipsec_ealg || ipsec_eaalg) { 4961 iap->iap_attr |= SPD_APPLY_ESP; 4962 } 4963 4964 /* convert src/dst to local/remote */ 4965 if (!new_style) { 4966 switch (cptr->ips_acts->iap_act_tok) { 4967 case TOK_apply: 4968 /* outbound */ 4969 /* src=local, dst=remote */ 4970 /* this is ok. */ 4971 break; 4972 4973 case TOK_permit: 4974 /* inbound */ 4975 /* src=remote, dst=local */ 4976 /* switch */ 4977 cptr->swap = 1; 4978 break; 4979 case TOK_bypass: 4980 case TOK_drop: 4981 /* check the direction for what to do */ 4982 if (cptr->ips_dir == SPD_RULE_FLAG_INBOUND) 4983 cptr->swap = 1; 4984 break; 4985 default: 4986 break; 4987 } 4988 } 4989 /* Validate the properties */ 4990 if (ret = validate_properties(iap, dir, 4991 (ipsec_aalg || ipsec_ealg || ipsec_eaalg))) { 4992 return (ret); 4993 } 4994 } 4995 4996 return (0); 4997 4998 } 4999 5000 static int 5001 print_cmd_buf(FILE *fp, int error) 5002 { 5003 *(cbuf + cbuf_offset) = '\0'; 5004 5005 if (fp == stderr) { 5006 if (error != EEXIST) { 5007 warnx(gettext("Malformed command (fatal):\n%s"), cbuf); 5008 return (0); 5009 } 5010 if (ipsecconf_qflag) { 5011 return (0); 5012 } 5013 warnx(gettext("Duplicate policy entry (ignored):\n%s"), cbuf); 5014 } else { 5015 if (fprintf(fp, "%s", cbuf) == -1) { 5016 warn("fprintf"); 5017 return (-1); 5018 } 5019 } 5020 5021 return (0); 5022 } 5023 5024 #ifdef DEBUG 5025 5026 static uchar_t * 5027 addr_ptr(int isv4, struct in6_addr *addr6, struct in_addr *addr4) 5028 { 5029 if (isv4) { 5030 IN6_V4MAPPED_TO_INADDR(addr6, addr4); 5031 return ((uchar_t *)&addr4->s_addr); 5032 } else { 5033 return ((uchar_t *)&addr6->s6_addr); 5034 } 5035 } 5036 5037 static void 5038 dump_algreq(const char *tag, algreq_t *alg) 5039 { 5040 (void) printf("%s algid %d, bits %d..%d\n", 5041 tag, alg->alg_id, alg->alg_minbits, alg->alg_maxbits); 5042 } 5043 5044 static void 5045 dump_conf(ips_conf_t *conf) 5046 { 5047 boolean_t isv4 = conf->ips_isv4; 5048 struct in_addr addr; 5049 char buf[INET6_ADDRSTRLEN]; 5050 int af; 5051 ips_act_props_t *iap = conf->ips_acts; 5052 5053 af = isv4 ? AF_INET : AF_INET6; 5054 5055 (void) printf("Source Addr is %s\n", 5056 inet_ntop(af, addr_ptr(isv4, &conf->ips_src_addr_v6, &addr), 5057 buf, INET6_ADDRSTRLEN)); 5058 5059 (void) printf("Dest Addr is %s\n", 5060 inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_addr_v6, &addr), 5061 buf, INET6_ADDRSTRLEN)); 5062 5063 (void) printf("Source Mask is %s\n", 5064 inet_ntop(af, addr_ptr(isv4, &conf->ips_src_mask_v6, &addr), 5065 buf, INET6_ADDRSTRLEN)); 5066 5067 (void) printf("Dest Mask is %s\n", 5068 inet_ntop(af, addr_ptr(isv4, &conf->ips_dst_mask_v6, &addr), 5069 buf, INET6_ADDRSTRLEN)); 5070 5071 (void) printf("Source port %d\n", ntohs(conf->ips_src_port_min)); 5072 (void) printf("Dest port %d\n", ntohs(conf->ips_dst_port_min)); 5073 (void) printf("ULP %d\n", conf->ips_ulp_prot); 5074 5075 (void) printf("ICMP type %d-%d code %d-%d", conf->ips_icmp_type, 5076 conf->ips_icmp_type_end, 5077 conf->ips_icmp_code, 5078 conf->ips_icmp_code_end); 5079 5080 while (iap != NULL) { 5081 (void) printf("------------------------------------\n"); 5082 (void) printf("IPsec act is %d\n", iap->iap_action); 5083 (void) printf("IPsec attr is %d\n", iap->iap_attr); 5084 dump_algreq("AH authentication", &iap->iap_aauth); 5085 dump_algreq("ESP authentication", &iap->iap_eauth); 5086 dump_algreq("ESP encryption", &iap->iap_eencr); 5087 (void) printf("------------------------------------\n"); 5088 iap = iap->iap_next; 5089 } 5090 5091 (void) fflush(stdout); 5092 } 5093 #endif /* DEBUG */ 5094 5095 5096 static int 5097 ipsec_conf_add(boolean_t just_check, boolean_t smf_managed) 5098 { 5099 act_prop_t *act_props = malloc(sizeof (act_prop_t)); 5100 ips_conf_t conf; 5101 FILE *fp, *policy_fp; 5102 int ret, flushret, i, j, diag, num_rules, good_rules; 5103 char *warning = gettext( 5104 "\tWARNING : New policy entries that are being added may\n " 5105 "\taffect the existing connections. Existing connections\n" 5106 "\tthat are not subjected to policy constraints, may be\n" 5107 "\tsubjected to policy constraints because of the new\n" 5108 "\tpolicy. This can disrupt the communication of the\n" 5109 "\texisting connections.\n\n"); 5110 5111 boolean_t first_time = B_TRUE; 5112 num_rules = 0; 5113 good_rules = 0; 5114 5115 if (act_props == NULL) { 5116 warn(gettext("memory")); 5117 return (-1); 5118 } 5119 5120 if (strcmp(filename, "-") == 0) 5121 fp = stdin; 5122 else 5123 fp = fopen(filename, "r"); 5124 5125 /* 5126 * Treat the non-existence of a policy file as a special 5127 * case when ipsecconf is being managed by smf(5). 5128 * The assumption is the administrator has not yet 5129 * created a policy file, this should not force the service 5130 * into maintenance mode. 5131 */ 5132 5133 if (fp == NULL) { 5134 if (smf_managed) { 5135 (void) fprintf(stdout, gettext( 5136 "Policy configuration file (%s) does not exist.\n" 5137 "IPsec policy not configured.\n"), filename); 5138 return (0); 5139 } 5140 warn(gettext("%s : Policy config file cannot be opened"), 5141 filename); 5142 usage(); 5143 return (-1); 5144 } 5145 /* 5146 * This will create the file if it does not exist. 5147 * Make sure the umask is right. 5148 */ 5149 (void) umask(0022); 5150 policy_fp = fopen(POLICY_CONF_FILE, "a"); 5151 if (policy_fp == NULL) { 5152 warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 5153 return (-1); 5154 } 5155 5156 /* 5157 * Pattern, action, and properties are allocated in 5158 * parse_pattern_or_prop and in parse_action (called by 5159 * parse_one) as we parse arguments. 5160 */ 5161 while ((ret = parse_one(fp, act_props)) == 0) { 5162 5163 /* 5164 * If there is no action and parse returned success, 5165 * it means that there is nothing to add. 5166 */ 5167 5168 if (act_props->pattern[0] == NULL && 5169 act_props->ap[0].act == NULL) 5170 break; 5171 5172 num_rules++; 5173 5174 ret = form_ipsec_conf(act_props, &conf); 5175 if (ret != 0) { 5176 warnx(gettext("form_ipsec_conf error")); 5177 (void) print_cmd_buf(stderr, NOERROR); 5178 /* Reset globals before trying the next rule. */ 5179 if (shp != NULL) { 5180 freehostent(shp); 5181 shp = NULL; 5182 } 5183 if (dhp != NULL) { 5184 freehostent(dhp); 5185 dhp = NULL; 5186 } 5187 splen = 0; 5188 dplen = 0; 5189 continue; 5190 } 5191 5192 good_rules++; 5193 5194 if (first_time) { 5195 /* 5196 * Time to assume that there are valid policy entries. 5197 * If the IPsec kernel modules are not loaded this 5198 * will load them now. 5199 */ 5200 first_time = B_FALSE; 5201 fetch_algorithms(); 5202 ipsec_conf_admin(SPD_CLONE); 5203 } 5204 5205 /* 5206 * shp, dhp, splen, and dplen are globals set by 5207 * form_ipsec_conf() while parsing the addresses. 5208 */ 5209 if (shp == NULL && dhp == NULL) { 5210 switch (do_port_adds(&conf)) { 5211 case 0: 5212 /* no error */ 5213 break; 5214 case EEXIST: 5215 /* duplicate entries, continue adds */ 5216 (void) print_cmd_buf(stderr, EEXIST); 5217 goto next; 5218 default: 5219 /* other error, bail */ 5220 ret = -1; 5221 goto bail; 5222 } 5223 } else { 5224 ret = do_address_adds(&conf, &diag); 5225 switch (ret) { 5226 case 0: 5227 /* no error. */ 5228 break; 5229 case EEXIST: 5230 (void) print_cmd_buf(stderr, EEXIST); 5231 goto next; 5232 case EBUSY: 5233 warnx(gettext( 5234 "Can't set mask and /NN prefix.")); 5235 ret = -1; 5236 break; 5237 case ENOENT: 5238 warnx(gettext("Cannot find tunnel " 5239 "interface %s."), interface_name); 5240 ret = -1; 5241 break; 5242 case EINVAL: 5243 /* 5244 * PF_POLICY didn't like what we sent. We 5245 * can't check all input up here, but we 5246 * do in-kernel. 5247 */ 5248 warnx(gettext("PF_POLICY invalid input:\n\t%s"), 5249 spdsock_diag(diag)); 5250 break; 5251 case EOPNOTSUPP: 5252 warnx(gettext("Can't set /NN" 5253 " prefix on multi-host name.")); 5254 ret = -1; 5255 break; 5256 case ERANGE: 5257 warnx(gettext("/NN prefix is too big!")); 5258 ret = -1; 5259 break; 5260 case ESRCH: 5261 warnx(gettext("No matching IPv4 or " 5262 "IPv6 saddr/daddr pairs")); 5263 ret = -1; 5264 break; 5265 default: 5266 /* Should never get here. */ 5267 errno = ret; 5268 warn(gettext("Misc. error")); 5269 ret = -1; 5270 } 5271 if (ret == -1) 5272 goto bail; 5273 } 5274 5275 /* 5276 * Go ahead and add policy entries to config file. 5277 * The # should help re-using the ipsecpolicy.conf 5278 * for input again as # will be treated as comment. 5279 */ 5280 if (fprintf(policy_fp, "%s %lld \n", INDEX_TAG, 5281 conf.ips_policy_index) == -1) { 5282 warn("fprintf"); 5283 warnx(gettext("Addition incomplete, Please " 5284 "flush all the entries and re-configure :")); 5285 reconfigure(); 5286 ret = -1; 5287 break; 5288 } 5289 if (print_cmd_buf(policy_fp, NOERROR) == -1) { 5290 warnx(gettext("Addition incomplete. Please " 5291 "flush all the entries and re-configure :")); 5292 reconfigure(); 5293 ret = -1; 5294 break; 5295 } 5296 /* 5297 * We add one newline by default to separate out the 5298 * entries. If the last character is not a newline, we 5299 * insert a newline for free. This makes sure that all 5300 * entries look consistent in the file. 5301 */ 5302 if (*(cbuf + cbuf_offset - 1) == '\n') { 5303 if (fprintf(policy_fp, "\n") == -1) { 5304 warn("fprintf"); 5305 warnx(gettext("Addition incomplete. " 5306 "Please flush all the entries and " 5307 "re-configure :")); 5308 reconfigure(); 5309 ret = -1; 5310 break; 5311 } 5312 } else { 5313 if (fprintf(policy_fp, "\n\n") == -1) { 5314 warn("fprintf"); 5315 warnx(gettext("Addition incomplete. " 5316 "Please flush all the entries and " 5317 "re-configure :")); 5318 reconfigure(); 5319 ret = -1; 5320 break; 5321 } 5322 } 5323 next: 5324 /* 5325 * Make sure this gets to the disk before 5326 * we parse the next entry. 5327 */ 5328 (void) fflush(policy_fp); 5329 for (i = 0; act_props->pattern[i] != NULL; i++) 5330 free(act_props->pattern[i]); 5331 for (j = 0; act_props->ap[j].act != NULL; j++) { 5332 free(act_props->ap[j].act); 5333 for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 5334 free(act_props->ap[j].prop[i]); 5335 } 5336 } 5337 bail: 5338 if (ret == -1) { 5339 (void) print_cmd_buf(stderr, EINVAL); 5340 for (i = 0; act_props->pattern[i] != NULL; i++) 5341 free(act_props->pattern[i]); 5342 for (j = 0; act_props->ap[j].act != NULL; j++) { 5343 free(act_props->ap[j].act); 5344 for (i = 0; act_props->ap[j].prop[i] != NULL; i++) 5345 free(act_props->ap[j].prop[i]); 5346 } 5347 } 5348 #ifdef DEBUG_HEAVY 5349 (void) printf("ipsec_conf_add: ret val = %d\n", ret); 5350 (void) fflush(stdout); 5351 #endif 5352 if (!good_rules) { 5353 nuke_adds(); 5354 (void) restore_all_signals(); 5355 (void) unlock(lfd); 5356 EXIT_OK("Policy file does not contain any valid rules."); 5357 } 5358 if (smf_managed && !just_check) { 5359 (void) fprintf(stdout, gettext( 5360 "%d policy rules added.\n"), good_rules); 5361 (void) fflush(stdout); 5362 } 5363 5364 if (num_rules != good_rules) { 5365 /* This is an error */ 5366 nuke_adds(); 5367 (void) restore_all_signals(); 5368 (void) unlock(lfd); 5369 EXIT_BADCONFIG2("%d policy rule(s) contained errors.", 5370 num_rules - good_rules); 5371 } 5372 5373 /* looks good, flip it in */ 5374 if (ret == 0 && !just_check) { 5375 if (!ipsecconf_qflag) { 5376 (void) printf("%s", warning); 5377 } 5378 ipsec_conf_admin(SPD_FLIP); 5379 } else { 5380 nuke_adds(); 5381 if (just_check) { 5382 (void) fprintf(stdout, gettext( 5383 "IPsec policy was not modified.\n")); 5384 (void) fflush(stdout); 5385 } 5386 } 5387 flushret = ipsec_conf_flush(SPD_STANDBY); 5388 if (flushret != 0) 5389 return (flushret); 5390 return (ret); 5391 } 5392 5393 5394 static int 5395 ipsec_conf_sub() 5396 { 5397 act_prop_t *act_props = malloc(sizeof (act_prop_t)); 5398 FILE *remove_fp, *policy_fp; 5399 char rbuf[MAXLEN], pbuf[MAXLEN], /* remove buffer, and policy buffer */ 5400 *warning = gettext( 5401 "\tWARNING: Policy entries that are being removed may\n" 5402 "\taffect the existing connections. Existing connections\n" 5403 "\tthat are subjected to policy constraints may no longer\n" 5404 "\tbe subjected to policy contraints because of its\n" 5405 "\tremoval. This can compromise security, and disrupt\n" 5406 "\tthe communication of the existing connection.\n" 5407 "\tConnections that are latched will remain unaffected\n" 5408 "\tuntil they close.\n"); 5409 int ret = 0; 5410 int index_len, pindex = 0; /* init value in case of pfile error */ 5411 5412 if (act_props == NULL) { 5413 warn(gettext("memory")); 5414 return (-1); 5415 } 5416 5417 /* clone into standby DB */ 5418 (void) ipsec_conf_admin(SPD_CLONE); 5419 5420 if (strcmp(filename, "-") == 0) 5421 remove_fp = stdin; 5422 else 5423 remove_fp = fopen(filename, "r"); 5424 5425 if (remove_fp == NULL) { 5426 warn(gettext("%s : Input file cannot be opened"), filename); 5427 usage(); 5428 free(act_props); 5429 return (-1); 5430 } 5431 5432 /* open policy file so we can locate the correct policy */ 5433 (void) umask(0022); /* in case it gets created! */ 5434 policy_fp = fopen(POLICY_CONF_FILE, "r+"); 5435 if (policy_fp == NULL) { 5436 warn(gettext("%s cannot be opened"), POLICY_CONF_FILE); 5437 (void) fclose(remove_fp); 5438 free(act_props); 5439 return (-1); 5440 } 5441 5442 /* don't print the warning if we're in q[uiet] mode */ 5443 if (!ipsecconf_qflag) 5444 (void) printf("%s", warning); 5445 5446 /* this bit is done primarily so we can read what we write */ 5447 index_len = strlen(INDEX_TAG); 5448 5449 /* 5450 * We want to look for the policy in rbuf in the policy file. 5451 * Go through the list of policies to remove, locating each one. 5452 */ 5453 while (fgets(rbuf, MAXLEN, remove_fp) != NULL) { 5454 char *buf; 5455 int offset, prev_offset, prev_prev_offset, nlines; 5456 fpos_t ipos; 5457 int pbuf_len = 0; 5458 char *tmp; 5459 /* skip blanks here (so we don't need to do it below)! */ 5460 for (tmp = rbuf; (*tmp != '\0') && isspace(*tmp); tmp++); 5461 if (*tmp == '\0') 5462 continue; 5463 5464 /* skip the INDEX_TAG lines in the remove buffer */ 5465 if (strncasecmp(rbuf, INDEX_TAG, index_len) == 0) 5466 continue; 5467 5468 /* skip commented lines */ 5469 if (*tmp == '#') 5470 continue; 5471 5472 /* 5473 * We start by presuming only good policies are in the pfile, 5474 * and so only good policies from the rfile will match them. 5475 * ipsec_conf_del ensures this later by calling parse_one() on 5476 * pfile before it deletes the entry. 5477 */ 5478 for (offset = prev_offset = prev_prev_offset = 0; 5479 fgets(pbuf, MAXLEN, policy_fp) != NULL; 5480 offset += pbuf_len) { 5481 prev_offset = offset; 5482 pbuf_len = strlen(pbuf); 5483 5484 /* skip blank lines which seperate policy entries */ 5485 if (pbuf[0] == '\n') 5486 continue; 5487 5488 /* if we found an index, save it */ 5489 if (strncasecmp(pbuf, INDEX_TAG, index_len) == 0) { 5490 buf = pbuf + index_len; 5491 buf++; 5492 if ((pindex = parse_index(buf, NULL)) == -1) { 5493 /* bad index, we can't continue */ 5494 warnx(gettext( 5495 "Invalid index in the file")); 5496 (void) fclose(remove_fp); 5497 (void) fclose(policy_fp); 5498 free(act_props); 5499 return (-1); 5500 } 5501 5502 /* save this position in case it's the one */ 5503 if (fgetpos(policy_fp, &ipos) != 0) { 5504 (void) fclose(remove_fp); 5505 (void) fclose(policy_fp); 5506 free(act_props); 5507 return (-1); 5508 } 5509 } 5510 5511 /* Does pbuf contain the remove policy? */ 5512 if (strncasecmp(rbuf, pbuf, pbuf_len) == 0) { 5513 /* we found the one to remove! */ 5514 if (pindex == 0) { 5515 warnx(gettext("Didn't find a valid " 5516 "index for policy")); 5517 (void) fclose(remove_fp); 5518 (void) fclose(policy_fp); 5519 free(act_props); 5520 return (-1); 5521 } 5522 5523 /* off it - back up to the last INDEX! */ 5524 if (fsetpos(policy_fp, &ipos) != 0) { 5525 (void) fclose(remove_fp); 5526 (void) fclose(policy_fp); 5527 free(act_props); 5528 return (-1); 5529 } 5530 5531 /* parse_one sets linecount = #lines to off */ 5532 if (parse_one(policy_fp, act_props) == -1) { 5533 warnx(gettext("Invalid policy entry " 5534 "in the file")); 5535 (void) fclose(remove_fp); 5536 (void) fclose(policy_fp); 5537 free(act_props); 5538 return (-1); 5539 } 5540 5541 nlines = linecount + 2; 5542 goto delete; 5543 } 5544 /* 5545 * When we find a match, we want to pass the offset 5546 * of the line that is before it - the INDEX_TAG line. 5547 */ 5548 prev_prev_offset = prev_offset; 5549 } 5550 /* Didn't find a match - look at the next remove policy */ 5551 continue; 5552 5553 delete: 5554 (void) fclose(policy_fp); 5555 5556 if (delete_from_file(prev_prev_offset, nlines) != 0) { 5557 warnx(gettext("delete_from_file failure. " 5558 "Please flush all entries and re-configure :")); 5559 reconfigure(); 5560 (void) fclose(remove_fp); 5561 free(act_props); 5562 return (-1); 5563 } 5564 5565 if (pfp_delete_rule(pindex) != 0) { 5566 warnx(gettext("Deletion incomplete. Please flush" 5567 "all the entries and re-configure :")); 5568 reconfigure(); 5569 (void) fclose(remove_fp); 5570 free(act_props); 5571 return (-1); 5572 } 5573 5574 /* reset the globals */ 5575 linecount = 0; 5576 pindex = 0; 5577 /* free(NULL) also works. */ 5578 free(interface_name); 5579 interface_name = NULL; 5580 5581 /* reopen for next pass, automagically starting over. */ 5582 policy_fp = fopen(POLICY_CONF_FILE, "r"); 5583 if (policy_fp == NULL) { 5584 warn(gettext("%s cannot be re-opened, can't continue"), 5585 POLICY_CONF_FILE); 5586 (void) fclose(remove_fp); 5587 free(act_props); 5588 return (-1); 5589 } 5590 5591 } /* read next remove policy */ 5592 5593 if ((ret = pfp_delete_rule(pindex)) != 0) { 5594 warnx(gettext("Removal incomplete. Please flush " 5595 "all the entries and re-configure :")); 5596 reconfigure(); 5597 free(act_props); 5598 return (ret); 5599 } 5600 5601 /* nothing left to look for */ 5602 (void) fclose(remove_fp); 5603 free(act_props); 5604 5605 return (0); 5606 } 5607 5608 /* 5609 * Constructs a tunnel interface ID extension. Returns the length 5610 * of the extension in 64-bit-words. 5611 */ 5612 static int 5613 attach_tunname(spd_if_t *tunname) 5614 { 5615 if (tunname == NULL || interface_name == NULL) 5616 return (0); 5617 5618 tunname->spd_if_exttype = SPD_EXT_TUN_NAME; 5619 /* 5620 * Use "-3" because there's 4 bytes in the message itself, and 5621 * we lose one because of the '\0' terminator. 5622 */ 5623 tunname->spd_if_len = SPD_8TO64( 5624 P2ROUNDUP(sizeof (*tunname) + strlen(interface_name) - 3, 8)); 5625 (void) strlcpy((char *)tunname->spd_if_name, interface_name, LIFNAMSIZ); 5626 return (tunname->spd_if_len); 5627 } 5628