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