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