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