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