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