dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / ipsecutils / ipseckey.c
blobafcb93d6f83a17ccff4740d30fdb669bcab4a933
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>
60 #include <ipsec_util.h>
62 static int keysock;
63 static uint32_t seq;
64 static pid_t mypid;
65 static boolean_t vflag = B_FALSE; /* Verbose? */
66 static boolean_t cflag = B_FALSE; /* Check Only */
68 char *my_fmri = NULL;
69 FILE *debugfile;
71 #define MAX_GET_SIZE 1024
73 * WARN() and ERROR() do the same thing really, with ERROR() the function
74 * that prints the error buffer needs to be called at the end of a code block
75 * This will print out all accumulated errors before bailing. The WARN()
76 * macro calls handle_errors() in such a way that it prints the message
77 * then continues.
78 * If the FATAL() macro used call handle_errors() immediately.
80 #define ERROR(x, y, z) x = record_error(x, y, z)
81 #define ERROR1(w, x, y, z) w = record_error(w, x, y, z)
82 #define ERROR2(v, w, x, y, z) v = record_error(v, w, x, y, z)
83 #define WARN(x, y, z) ERROR(x, y, z);\
84 handle_errors(x, NULL, B_FALSE, B_FALSE); x = NULL
85 #define WARN1(w, x, y, z) ERROR1(w, x, y, z);\
86 handle_errors(w, NULL, B_FALSE, B_FALSE); w = NULL
87 #define WARN2(v, w, x, y, z) ERROR2(v, w, x, y, z);\
88 handle_errors(v, NULL, B_FALSE, B_FALSE); v = NULL
89 #define FATAL(x, y, z) ERROR(x, y, z);\
90 handle_errors(x, y, B_TRUE, B_TRUE)
91 #define FATAL1(w, x, y, z) ERROR1(w, x, y, z);\
92 handle_errors(w, x, B_TRUE, B_TRUE)
94 /* Defined as a uint64_t array for alignment purposes. */
95 static uint64_t get_buffer[MAX_GET_SIZE];
98 * Disable default TAB completion for now (until some brave soul tackles it).
100 /* ARGSUSED */
101 static
102 CPL_MATCH_FN(no_match)
104 return (0);
108 * Create/Grow a buffer large enough to hold error messages. If *ebuf
109 * is not NULL then it will contain a copy of the command line that
110 * triggered the error/warning, copy this into a new buffer or
111 * append new messages to the existing buffer.
113 /*PRINTFLIKE1*/
114 char *
115 record_error(char *ep, char *ebuf, char *fmt, ...)
117 char *err_ptr;
118 char tmp_buff[1024];
119 va_list ap;
120 int length = 0;
121 err_ptr = ep;
123 va_start(ap, fmt);
124 length = vsnprintf(tmp_buff, sizeof (tmp_buff), fmt, ap);
125 va_end(ap);
127 /* There is a new line character */
128 length++;
130 if (ep == NULL) {
131 if (ebuf != NULL)
132 length += strlen(ebuf);
133 } else {
134 length += strlen(ep);
137 if (err_ptr == NULL)
138 err_ptr = calloc(length, sizeof (char));
139 else
140 err_ptr = realloc(err_ptr, length);
142 if (err_ptr == NULL)
143 Bail("realloc() failure");
146 * If (ep == NULL) then this is the first error to record,
147 * copy in the command line that triggered this error/warning.
149 if (ep == NULL && ebuf != NULL)
150 (void) strlcpy(err_ptr, ebuf, length);
153 * Now the actual error.
155 (void) strlcat(err_ptr, tmp_buff, length);
156 return (err_ptr);
160 * If not in interactive mode print usage message and exit.
162 static void
163 usage(void)
165 if (!interactive) {
166 (void) fprintf(stderr, gettext("Usage:\t"
167 "ipseckey [ -nvp ] | cmd [sa_type] [extfield value]*\n"));
168 (void) fprintf(stderr,
169 gettext("\tipseckey [ -nvp ] -f infile\n"));
170 (void) fprintf(stderr,
171 gettext("\tipseckey [ -nvp ] -s outfile\n"));
172 EXIT_FATAL(NULL);
173 } else {
174 (void) fprintf(stderr,
175 gettext("Type help or ? for usage info\n"));
181 * Print out any errors, tidy up as required.
182 * error pointer ep will be free()'d
184 void
185 handle_errors(char *ep, char *ebuf, boolean_t fatal, boolean_t done)
187 if (ep != NULL) {
188 if (my_fmri == NULL) {
190 * For now suppress the errors when run from smf(5)
191 * because potentially sensitive information could
192 * end up in a publicly readable logfile.
194 (void) fprintf(stdout, "%s\n", ep);
195 (void) fflush(stdout);
197 free(ep);
198 if (fatal) {
199 if (ebuf != NULL) {
200 free(ebuf);
202 /* reset command buffer */
203 if (interactive)
204 longjmp(env, 1);
205 } else {
206 return;
208 } else {
210 * No errors, if this is the last time that this function
211 * is called, free(ebuf) and reset command buffer.
213 if (done) {
214 if (ebuf != NULL) {
215 free(ebuf);
217 /* reset command buffer */
218 if (interactive)
219 longjmp(env, 1);
221 return;
223 EXIT_FATAL(NULL);
227 * Initialize a PF_KEY base message.
229 static void
230 msg_init(struct sadb_msg *msg, uint8_t type, uint8_t satype)
232 msg->sadb_msg_version = PF_KEY_V2;
233 msg->sadb_msg_type = type;
234 msg->sadb_msg_errno = 0;
235 msg->sadb_msg_satype = satype;
236 /* For starters... */
237 msg->sadb_msg_len = SADB_8TO64(sizeof (*msg));
238 msg->sadb_msg_reserved = 0;
239 msg->sadb_msg_seq = ++seq;
240 msg->sadb_msg_pid = mypid;
244 * parseXXX and rparseXXX commands parse input and convert them to PF_KEY
245 * field values, or do the reverse for the purposes of saving the SA tables.
246 * (See the save_XXX functions.)
249 #define CMD_NONE 0
250 #define CMD_UPDATE 2
251 #define CMD_UPDATE_PAIR 3
252 #define CMD_ADD 4
253 #define CMD_DELETE 5
254 #define CMD_DELETE_PAIR 6
255 #define CMD_GET 7
256 #define CMD_FLUSH 9
257 #define CMD_DUMP 10
258 #define CMD_MONITOR 11
259 #define CMD_PMONITOR 12
260 #define CMD_QUIT 13
261 #define CMD_SAVE 14
262 #define CMD_HELP 15
265 * Parse the command.
267 static int
268 parsecmd(char *cmdstr)
270 static struct cmdtable {
271 char *cmd;
272 int token;
273 } table[] = {
275 * Q: Do we want to do GETSPI?
276 * A: No, it's for automated key mgmt. only. Either that,
277 * or it isn't relevant until we support non IPsec SA types.
279 {"update", CMD_UPDATE},
280 {"update-pair", CMD_UPDATE_PAIR},
281 {"add", CMD_ADD},
282 {"delete", CMD_DELETE},
283 {"delete-pair", CMD_DELETE_PAIR},
284 {"get", CMD_GET},
286 * Q: And ACQUIRE and REGISTER and EXPIRE?
287 * A: not until we support non IPsec SA types.
289 {"flush", CMD_FLUSH},
290 {"dump", CMD_DUMP},
291 {"monitor", CMD_MONITOR},
292 {"passive_monitor", CMD_PMONITOR},
293 {"pmonitor", CMD_PMONITOR},
294 {"quit", CMD_QUIT},
295 {"exit", CMD_QUIT},
296 {"save", CMD_SAVE},
297 {"help", CMD_HELP},
298 {"?", CMD_HELP},
299 {NULL, CMD_NONE}
301 struct cmdtable *ct = table;
303 while (ct->cmd != NULL && strcmp(ct->cmd, cmdstr) != 0)
304 ct++;
305 return (ct->token);
309 * Convert a number from a command line. I picked "u_longlong_t" for the
310 * number because we need the largest number available. Also, the strto<num>
311 * calls don't deal in units of uintNN_t.
313 static u_longlong_t
314 parsenum(char *num, boolean_t bail, char *ebuf)
316 u_longlong_t rc = 0;
317 char *end = NULL;
318 char *ep = NULL;
320 if (num == NULL) {
321 FATAL(ep, ebuf, gettext("Unexpected end of command line,"
322 " was expecting a number.\n"));
323 /* NOTREACHED */
326 errno = 0;
327 rc = strtoull(num, &end, 0);
328 if (errno != 0 || end == num || *end != '\0') {
329 if (bail) {
330 FATAL1(ep, ebuf, gettext(
331 "Expecting a number, not \"%s\"!\n"), num);
332 } else {
334 * -1, while not optimal, is sufficiently out of range
335 * for most of this function's applications when
336 * we don't just bail.
338 return ((u_longlong_t)-1);
341 handle_errors(ep, NULL, B_FALSE, B_FALSE);
342 return (rc);
346 * Parse and reverse parse a specific SA type (AH, ESP, etc.).
348 static struct typetable {
349 char *type;
350 int token;
351 } type_table[] = {
352 {"all", SADB_SATYPE_UNSPEC},
353 {"ah", SADB_SATYPE_AH},
354 {"esp", SADB_SATYPE_ESP},
355 /* PF_KEY NOTE: More to come if net/pfkeyv2.h gets updated. */
356 {NULL, 0} /* Token value is irrelevant for this entry. */
360 static int
361 parsesatype(char *type, char *ebuf)
363 struct typetable *tt = type_table;
364 char *ep = NULL;
366 if (type == NULL)
367 return (SADB_SATYPE_UNSPEC);
369 while (tt->type != NULL && strcasecmp(tt->type, type) != 0)
370 tt++;
373 * New SA types (including ones keysock maintains for user-land
374 * protocols) may be added, so parse a numeric value if possible.
376 if (tt->type == NULL) {
377 tt->token = (int)parsenum(type, B_FALSE, ebuf);
378 if (tt->token == -1) {
379 ERROR1(ep, ebuf, gettext(
380 "Unknown SA type (%s).\n"), type);
381 tt->token = SADB_SATYPE_UNSPEC;
384 handle_errors(ep, NULL, interactive ? B_TRUE : B_FALSE, B_FALSE);
385 return (tt->token);
388 #define NEXTEOF 0
389 #define NEXTNONE 1
390 #define NEXTNUM 2
391 #define NEXTSTR 3
392 #define NEXTNUMSTR 4
393 #define NEXTADDR 5
394 #define NEXTHEX 6
395 #define NEXTIDENT 7
396 #define NEXTADDR4 8
397 #define NEXTADDR6 9
398 #define NEXTLABEL 10
400 #define TOK_EOF 0
401 #define TOK_UNKNOWN 1
402 #define TOK_SPI 2
403 #define TOK_REPLAY 3
404 #define TOK_STATE 4
405 #define TOK_AUTHALG 5
406 #define TOK_ENCRALG 6
407 #define TOK_FLAGS 7
408 #define TOK_SOFT_ALLOC 8
409 #define TOK_SOFT_BYTES 9
410 #define TOK_SOFT_ADDTIME 10
411 #define TOK_SOFT_USETIME 11
412 #define TOK_HARD_ALLOC 12
413 #define TOK_HARD_BYTES 13
414 #define TOK_HARD_ADDTIME 14
415 #define TOK_HARD_USETIME 15
416 #define TOK_CURRENT_ALLOC 16
417 #define TOK_CURRENT_BYTES 17
418 #define TOK_CURRENT_ADDTIME 18
419 #define TOK_CURRENT_USETIME 19
420 #define TOK_SRCADDR 20
421 #define TOK_DSTADDR 21
422 #define TOK_PROXYADDR 22
423 #define TOK_AUTHKEY 23
424 #define TOK_ENCRKEY 24
425 #define TOK_SRCIDTYPE 25
426 #define TOK_DSTIDTYPE 26
427 #define TOK_DPD 27
428 #define TOK_INTEG_LEVEL 30
429 #define TOK_INTEG_MAP 31
430 #define TOK_SRCADDR6 32
431 #define TOK_DSTADDR6 33
432 #define TOK_PROXYADDR6 34
433 #define TOK_SRCPORT 35
434 #define TOK_DSTPORT 36
435 #define TOK_PROTO 37
436 #define TOK_ENCAP 38
437 #define TOK_NATLOC 39
438 #define TOK_NATREM 40
439 #define TOK_NATLPORT 41
440 #define TOK_NATRPORT 42
441 #define TOK_IPROTO 43
442 #define TOK_IDSTADDR 44
443 #define TOK_IDSTADDR6 45
444 #define TOK_ISRCPORT 46
445 #define TOK_IDSTPORT 47
446 #define TOK_PAIR_SPI 48
447 #define TOK_FLAG_INBOUND 49
448 #define TOK_FLAG_OUTBOUND 50
449 #define TOK_REPLAY_VALUE 51
450 #define TOK_IDLE_ADDTIME 52
451 #define TOK_IDLE_USETIME 53
452 #define TOK_RESERVED 54
454 static struct toktable {
455 char *string;
456 int token;
457 int next;
458 } tokens[] = {
459 /* "String", token value, next arg is */
460 {"spi", TOK_SPI, NEXTNUM},
461 {"pair-spi", TOK_PAIR_SPI, NEXTNUM},
462 {"replay", TOK_REPLAY, NEXTNUM},
463 {"state", TOK_STATE, NEXTNUMSTR},
464 {"auth_alg", TOK_AUTHALG, NEXTNUMSTR},
465 {"authalg", TOK_AUTHALG, NEXTNUMSTR},
466 {"encr_alg", TOK_ENCRALG, NEXTNUMSTR},
467 {"encralg", TOK_ENCRALG, NEXTNUMSTR},
468 {"flags", TOK_FLAGS, NEXTNUM},
469 {"soft_alloc", TOK_SOFT_ALLOC, NEXTNUM},
470 {"soft_bytes", TOK_SOFT_BYTES, NEXTNUM},
471 {"soft_addtime", TOK_SOFT_ADDTIME, NEXTNUM},
472 {"soft_usetime", TOK_SOFT_USETIME, NEXTNUM},
473 {"hard_alloc", TOK_HARD_ALLOC, NEXTNUM},
474 {"hard_bytes", TOK_HARD_BYTES, NEXTNUM},
475 {"hard_addtime", TOK_HARD_ADDTIME, NEXTNUM},
476 {"hard_usetime", TOK_HARD_USETIME, NEXTNUM},
477 {"current_alloc", TOK_CURRENT_ALLOC, NEXTNUM},
478 {"current_bytes", TOK_CURRENT_BYTES, NEXTNUM},
479 {"current_addtime", TOK_CURRENT_ADDTIME, NEXTNUM},
480 {"current_usetime", TOK_CURRENT_USETIME, NEXTNUM},
482 {"saddr", TOK_SRCADDR, NEXTADDR},
483 {"srcaddr", TOK_SRCADDR, NEXTADDR},
484 {"src", TOK_SRCADDR, NEXTADDR},
485 {"daddr", TOK_DSTADDR, NEXTADDR},
486 {"dstaddr", TOK_DSTADDR, NEXTADDR},
487 {"dst", TOK_DSTADDR, NEXTADDR},
488 {"proxyaddr", TOK_PROXYADDR, NEXTADDR},
489 {"proxy", TOK_PROXYADDR, NEXTADDR},
490 {"innersrc", TOK_PROXYADDR, NEXTADDR},
491 {"isrc", TOK_PROXYADDR, NEXTADDR},
492 {"innerdst", TOK_IDSTADDR, NEXTADDR},
493 {"idst", TOK_IDSTADDR, NEXTADDR},
495 {"sport", TOK_SRCPORT, NEXTNUM},
496 {"dport", TOK_DSTPORT, NEXTNUM},
497 {"innersport", TOK_ISRCPORT, NEXTNUM},
498 {"isport", TOK_ISRCPORT, NEXTNUM},
499 {"innerdport", TOK_IDSTPORT, NEXTNUM},
500 {"idport", TOK_IDSTPORT, NEXTNUM},
501 {"proto", TOK_PROTO, NEXTNUM},
502 {"ulp", TOK_PROTO, NEXTNUM},
503 {"iproto", TOK_IPROTO, NEXTNUM},
504 {"iulp", TOK_IPROTO, NEXTNUM},
506 {"saddr6", TOK_SRCADDR6, NEXTADDR},
507 {"srcaddr6", TOK_SRCADDR6, NEXTADDR},
508 {"src6", TOK_SRCADDR6, NEXTADDR},
509 {"daddr6", TOK_DSTADDR6, NEXTADDR},
510 {"dstaddr6", TOK_DSTADDR6, NEXTADDR},
511 {"dst6", TOK_DSTADDR6, NEXTADDR},
512 {"proxyaddr6", TOK_PROXYADDR6, NEXTADDR},
513 {"proxy6", TOK_PROXYADDR6, NEXTADDR},
514 {"innersrc6", TOK_PROXYADDR6, NEXTADDR},
515 {"isrc6", TOK_PROXYADDR6, NEXTADDR},
516 {"innerdst6", TOK_IDSTADDR6, NEXTADDR},
517 {"idst6", TOK_IDSTADDR6, NEXTADDR},
519 {"authkey", TOK_AUTHKEY, NEXTHEX},
520 {"encrkey", TOK_ENCRKEY, NEXTHEX},
521 {"srcidtype", TOK_SRCIDTYPE, NEXTIDENT},
522 {"dstidtype", TOK_DSTIDTYPE, NEXTIDENT},
523 {"dpd", TOK_DPD, NEXTNUM},
524 {"integ_level", TOK_INTEG_LEVEL, NEXTNUM},
525 {"integ_map", TOK_INTEG_MAP, NEXTHEX},
526 {"nat_loc", TOK_NATLOC, NEXTADDR},
527 {"nat_rem", TOK_NATREM, NEXTADDR},
528 {"nat_lport", TOK_NATLPORT, NEXTNUM},
529 {"nat_rport", TOK_NATRPORT, NEXTNUM},
530 {"encap", TOK_ENCAP, NEXTNUMSTR},
532 {"outbound", TOK_FLAG_OUTBOUND, 0},
533 {"inbound", TOK_FLAG_INBOUND, 0},
535 {"reserved_bits", TOK_RESERVED, NEXTNUM},
536 {"replay_value", TOK_REPLAY_VALUE, NEXTNUM},
537 {"idle_addtime", TOK_IDLE_ADDTIME, NEXTNUM},
538 {"idle_usetime", TOK_IDLE_USETIME, NEXTNUM},
540 {NULL, TOK_UNKNOWN, NEXTEOF}
544 * Q: Do I need stuff for proposals, combinations, supported algorithms,
545 * or SPI ranges?
547 * A: Probably not, but you never know.
549 * Parse out extension header type values.
551 static int
552 parseextval(char *value, int *next)
554 struct toktable *tp;
556 if (value == NULL)
557 return (TOK_EOF);
559 for (tp = tokens; tp->string != NULL; tp++)
560 if (strcmp(value, tp->string) == 0)
561 break;
564 * Since the OS controls what extensions are available, we don't have
565 * to parse numeric values here.
568 *next = tp->next;
569 return (tp->token);
573 * Parse possible state values.
575 static uint8_t
576 parsestate(char *state, char *ebuf)
578 struct states {
579 char *state;
580 uint8_t retval;
581 } states[] = {
582 {"larval", SADB_SASTATE_LARVAL},
583 {"mature", SADB_SASTATE_MATURE},
584 {"dying", SADB_SASTATE_DYING},
585 {"dead", SADB_SASTATE_DEAD},
586 {NULL, 0}
588 struct states *sp;
589 char *ep = NULL;
591 if (state == NULL) {
592 FATAL(ep, ebuf, "Unexpected end of command line "
593 "was expecting a state.\n");
596 for (sp = states; sp->state != NULL; sp++) {
597 if (strcmp(sp->state, state) == 0)
598 return (sp->retval);
600 ERROR1(ep, ebuf, gettext("Unknown state type \"%s\"\n"), state);
601 handle_errors(ep, NULL, B_FALSE, B_FALSE);
602 return (0);
606 * Return the numerical algorithm identifier corresponding to the specified
607 * algorithm name.
609 static uint8_t
610 parsealg(char *alg, int proto_num, char *ebuf)
612 u_longlong_t invalue;
613 struct ipsecalgent *algent;
614 char *ep = NULL;
616 if (alg == NULL) {
617 FATAL(ep, ebuf, gettext("Unexpected end of command line, "
618 "was expecting an algorithm name.\n"));
621 algent = getipsecalgbyname(alg, proto_num, NULL);
622 if (algent != NULL) {
623 uint8_t alg_num;
625 alg_num = algent->a_alg_num;
626 if (ALG_FLAG_COUNTERMODE & algent->a_alg_flags)
627 WARN1(ep, ebuf, gettext(
628 "Using manual keying with a Counter mode algorithm "
629 "such as \"%s\" may be insecure!\n"),
630 algent->a_names[0]);
631 freeipsecalgent(algent);
633 return (alg_num);
637 * Since algorithms can be loaded during kernel run-time, check for
638 * numeric algorithm values too. PF_KEY can catch bad ones with EINVAL.
640 invalue = parsenum(alg, B_FALSE, ebuf);
641 if (invalue != (u_longlong_t)-1 &&
642 (u_longlong_t)(invalue & (u_longlong_t)0xff) == invalue)
643 return ((uint8_t)invalue);
645 if (proto_num == IPSEC_PROTO_ESP) {
646 ERROR1(ep, ebuf, gettext(
647 "Unknown encryption algorithm type \"%s\"\n"), alg);
648 } else {
649 ERROR1(ep, ebuf, gettext(
650 "Unknown authentication algorithm type \"%s\"\n"), alg);
652 handle_errors(ep, NULL, B_FALSE, B_FALSE);
653 return (0);
657 * Parse and reverse parse out a source/destination ID type.
659 static struct idtypes {
660 char *idtype;
661 uint8_t retval;
662 } idtypes[] = {
663 {"prefix", SADB_IDENTTYPE_PREFIX},
664 {"fqdn", SADB_IDENTTYPE_FQDN},
665 {"domain", SADB_IDENTTYPE_FQDN},
666 {"domainname", SADB_IDENTTYPE_FQDN},
667 {"user_fqdn", SADB_IDENTTYPE_USER_FQDN},
668 {"mailbox", SADB_IDENTTYPE_USER_FQDN},
669 {"der_dn", SADB_X_IDENTTYPE_DN},
670 {"der_gn", SADB_X_IDENTTYPE_GN},
671 {NULL, 0}
674 static uint16_t
675 parseidtype(char *type, char *ebuf)
677 struct idtypes *idp;
678 u_longlong_t invalue;
679 char *ep = NULL;
681 if (type == NULL) {
682 /* Shouldn't reach here, see callers for why. */
683 FATAL(ep, ebuf, gettext("Unexpected end of command line, "
684 "was expecting a type.\n"));
687 for (idp = idtypes; idp->idtype != NULL; idp++) {
688 if (strcasecmp(idp->idtype, type) == 0)
689 return (idp->retval);
692 * Since identity types are almost arbitrary, check for numeric
693 * algorithm values too. PF_KEY can catch bad ones with EINVAL.
695 invalue = parsenum(type, B_FALSE, ebuf);
696 if (invalue != (u_longlong_t)-1 &&
697 (u_longlong_t)(invalue & (u_longlong_t)0xffff) == invalue)
698 return ((uint16_t)invalue);
701 ERROR1(ep, ebuf, gettext("Unknown identity type \"%s\"\n"), type);
703 handle_errors(ep, NULL, B_FALSE, B_FALSE);
704 return (0);
708 * Parse an address off the command line. Return length of sockaddr,
709 * and either return a hostent pointer (caller frees). The new
710 * getipnodebyname() call does the Right Thing (TM), even with
711 * raw addresses (colon-separated IPv6 or dotted decimal IPv4).
714 static struct {
715 struct hostent he;
716 char *addtl[2];
717 } dummy;
718 static union {
719 struct in6_addr ipv6;
720 struct in_addr ipv4;
721 uint64_t aligner;
722 } addr1;
724 static int
725 parseaddr(char *addr, struct hostent **hpp, boolean_t v6only, char *ebuf)
727 int hp_errno;
728 struct hostent *hp = NULL;
729 char *ep = NULL;
731 if (addr == NULL) {
732 FATAL(ep, ebuf, gettext("Unexpected end of command line, "
733 "was expecting an address.\n"));
736 if (!nflag) {
738 * Try name->address first. Assume AF_INET6, and
739 * get IPv4's, plus IPv6's if and only if IPv6 is configured.
740 * This means to add IPv6 SAs, you must have IPv6
741 * up-and-running. (AI_DEFAULT works here.)
743 hp = getipnodebyname(addr, AF_INET6,
744 (v6only ? AI_ADDRCONFIG : (AI_DEFAULT | AI_ALL)),
745 &hp_errno);
746 } else {
748 * Try a normal address conversion only. Use "dummy"
749 * to construct a fake hostent. Caller will know not
750 * to free this one.
752 if (inet_pton(AF_INET6, addr, &addr1) == 1) {
753 dummy.he.h_addr_list = dummy.addtl;
754 dummy.addtl[0] = (char *)&addr1;
755 dummy.addtl[1] = NULL;
756 hp = &dummy.he;
757 dummy.he.h_addrtype = AF_INET6;
758 dummy.he.h_length = sizeof (struct in6_addr);
759 } else if (inet_pton(AF_INET, addr, &addr1) == 1) {
761 * Remap to AF_INET6 anyway.
763 dummy.he.h_addr_list = dummy.addtl;
764 dummy.addtl[0] = (char *)&addr1;
765 dummy.addtl[1] = NULL;
766 hp = &dummy.he;
767 dummy.he.h_addrtype = AF_INET6;
768 dummy.he.h_length = sizeof (struct in6_addr);
770 * NOTE: If macro changes to disallow in-place
771 * conversion, rewhack this.
773 IN6_INADDR_TO_V4MAPPED(&addr1.ipv4, &addr1.ipv6);
774 } else {
775 hp = NULL;
779 if (hp == NULL)
780 WARN1(ep, ebuf, gettext("Unknown address %s."), addr);
782 *hpp = hp;
783 /* Always return sockaddr_in6 for now. */
784 handle_errors(ep, NULL, B_FALSE, B_FALSE);
785 return (sizeof (struct sockaddr_in6));
789 * Parse a hex character for a key. A string will take the form:
790 * xxxxxxxxx/nn
791 * where
792 * xxxxxxxxx == a string of hex characters ([0-9][a-f][A-F])
793 * nn == an optional decimal "mask". If it is not present, it
794 * is assumed that the hex string will be rounded to the nearest
795 * byte, where odd nibbles, like 123 will become 0x0123.
797 * NOTE:Unlike the expression of IP addresses, I will not allow an
798 * excessive "mask". For example 2112/50 is very illegal.
799 * NOTE2: This key should be in canonical order. Consult your man
800 * pages per algorithm about said order.
803 #define hd2num(hd) (((hd) >= '0' && (hd) <= '9') ? ((hd) - '0') : \
804 (((hd) >= 'a' && (hd) <= 'f') ? ((hd) - 'a' + 10) : ((hd) - 'A' + 10)))
806 static struct sadb_key *
807 parsekey(char *input, char *ebuf, uint_t reserved_bits)
809 struct sadb_key *retval;
810 uint_t i, hexlen = 0, bits, alloclen;
811 uint8_t *key;
812 char *ep = NULL;
814 if (input == NULL) {
815 FATAL(ep, ebuf, gettext("Unexpected end of command line, "
816 "was expecting a key.\n"));
818 /* Allow hex values prepended with 0x convention */
819 if ((strnlen(input, sizeof (hexlen)) > 2) &&
820 (strncasecmp(input, "0x", 2) == 0))
821 input += 2;
823 for (i = 0; input[i] != '\0' && input[i] != '/'; i++)
824 hexlen++;
826 if (input[i] == '\0') {
827 bits = 0;
828 } else {
829 /* Have /nn. */
830 input[i] = '\0';
831 if (sscanf((input + i + 1), "%u", &bits) != 1) {
832 FATAL1(ep, ebuf, gettext(
833 "\"%s\" is not a bit specifier.\n"),
834 (input + i + 1));
836 /* hexlen in nibbles */
837 if (((bits + 3) >> 2) > hexlen) {
838 ERROR2(ep, ebuf, gettext(
839 "bit length %d is too big for %s.\n"), bits, input);
842 * Adjust hexlen down if user gave us too small of a bit
843 * count.
845 if ((hexlen << 2) > bits + 3) {
846 WARN2(ep, ebuf, gettext(
847 "WARNING: Lower bits will be truncated "
848 "for:\n\t%s/%d.\n"), input, bits);
849 hexlen = (bits + 3) >> 2;
850 input[hexlen] = '\0';
855 * Allocate. Remember, hexlen is in nibbles.
858 alloclen = sizeof (*retval) + roundup((hexlen/2 + (hexlen & 0x1)), 8);
859 retval = malloc(alloclen);
861 if (retval == NULL)
862 Bail("malloc(parsekey)");
863 retval->sadb_key_len = SADB_8TO64(alloclen);
865 retval->sadb_key_reserved = reserved_bits;
867 if (bits == 0)
868 retval->sadb_key_bits = (hexlen + (hexlen & 0x1)) << 2;
869 else
870 retval->sadb_key_bits = bits;
873 * Read in nibbles. Read in odd-numbered as shifted high.
874 * (e.g. 123 becomes 0x1230).
877 key = (uint8_t *)(retval + 1);
878 for (i = 0; input[i] != '\0'; i += 2) {
879 boolean_t second = (input[i + 1] != '\0');
881 if (!isxdigit(input[i]) ||
882 (!isxdigit(input[i + 1]) && second)) {
883 ERROR1(ep, ebuf, gettext(
884 "string '%s' not a hex value.\n"), input);
885 free(retval);
886 retval = NULL;
887 break;
889 *key = (hd2num(input[i]) << 4);
890 if (second)
891 *key |= hd2num(input[i + 1]);
892 else
893 break; /* out of for loop. */
894 key++;
897 /* bzero the remaining bits if we're a non-octet amount. */
898 if (bits & 0x7)
899 *((input[i] == '\0') ? key - 1 : key) &=
900 0xff << (8 - (bits & 0x7));
902 handle_errors(ep, NULL, B_FALSE, B_FALSE);
903 return (retval);
906 * Write a message to the PF_KEY socket. If verbose, print the message
907 * heading into the kernel.
909 static int
910 key_write(int fd, void *msg, size_t len)
912 if (vflag) {
913 (void) printf(
914 gettext("VERBOSE ON: Message to kernel looks like:\n"));
915 (void) printf("==========================================\n");
916 print_samsg(stdout, msg, B_FALSE, vflag, nflag);
917 (void) printf("==========================================\n");
920 return (write(fd, msg, len));
924 * SIGALRM handler for time_critical_enter.
926 static void
927 time_critical_catch(int signal)
929 if (signal == SIGALRM) {
930 errx(1, gettext("Reply message from PF_KEY timed out."));
931 } else {
932 errx(1, gettext("Caught signal %d while trying to receive"
933 "PF_KEY reply message"), signal);
935 /* errx() calls exit. */
938 #define TIME_CRITICAL_TIME 10 /* In seconds */
941 * Enter a "time critical" section where key is waiting for a return message.
943 static void
944 time_critical_enter(void)
946 (void) signal(SIGALRM, time_critical_catch);
947 (void) alarm(TIME_CRITICAL_TIME);
951 * Exit the "time critical" section after getting an appropriate return
952 * message.
954 static void
955 time_critical_exit(void)
957 (void) alarm(0);
958 (void) signal(SIGALRM, SIG_DFL);
962 * Construct a PF_KEY FLUSH message for the SA type specified.
964 static void
965 doflush(int satype)
967 struct sadb_msg msg;
968 int rc;
970 msg_init(&msg, SADB_FLUSH, (uint8_t)satype);
971 rc = key_write(keysock, &msg, sizeof (msg));
972 if (rc == -1)
973 Bail("write() to PF_KEY socket failed (in doflush)");
975 time_critical_enter();
976 do {
977 rc = read(keysock, &msg, sizeof (msg));
978 if (rc == -1)
979 Bail("read (in doflush)");
980 } while (msg.sadb_msg_seq != seq || msg.sadb_msg_pid != mypid);
981 time_critical_exit();
984 * I should _never_ hit the following unless:
986 * 1. There is a kernel bug.
987 * 2. There is another process filling in its pid with mine, and
988 * issuing a different message that would cause a different result.
990 if (msg.sadb_msg_type != SADB_FLUSH ||
991 msg.sadb_msg_satype != (uint8_t)satype) {
992 syslog((LOG_NOTICE|LOG_AUTH),
993 gettext("doflush: Return message not of type SADB_FLUSH!"));
994 Bail("doflush: Return message not of type SADB_FLUSH!");
997 if (msg.sadb_msg_errno != 0) {
998 errno = msg.sadb_msg_errno;
999 if (errno == EINVAL) {
1000 print_diagnostic(stderr, msg.sadb_x_msg_diagnostic);
1001 warnx(gettext("Cannot flush SA type %d."), satype);
1003 Bail("return message (in doflush)");
1008 * save_XXX functions are used when "saving" the SA tables to either a
1009 * file or standard output. They use the dump_XXX functions where needed,
1010 * but mostly they use the rparseXXX functions.
1014 * Because "save" and "dump" both use the SADB_DUMP message, fold both
1015 * into the same function.
1017 static void
1018 dodump(int satype, FILE *ofile)
1020 struct sadb_msg *msg = (struct sadb_msg *)get_buffer;
1021 int rc;
1023 if (ofile != NULL) {
1024 (void) fprintf(ofile,
1025 gettext("# This key file was generated by the"));
1026 (void) fprintf(ofile,
1027 gettext(" ipseckey(1m) command's 'save' feature.\n\n"));
1029 msg_init(msg, SADB_DUMP, (uint8_t)satype);
1030 rc = key_write(keysock, msg, sizeof (*msg));
1031 if (rc == -1)
1032 Bail("write to PF_KEY socket failed (in dodump)");
1034 do {
1036 * For DUMP, do only the read as a time critical section.
1038 time_critical_enter();
1039 rc = read(keysock, get_buffer, sizeof (get_buffer));
1040 time_critical_exit();
1041 if (rc == -1)
1042 Bail("read (in dodump)");
1043 if (msg->sadb_msg_pid == mypid &&
1044 msg->sadb_msg_type == SADB_DUMP &&
1045 msg->sadb_msg_seq != 0 &&
1046 msg->sadb_msg_errno == 0) {
1047 if (ofile == NULL) {
1048 print_samsg(stdout, get_buffer, B_FALSE, vflag,
1049 nflag);
1050 (void) putchar('\n');
1051 } else {
1052 save_assoc(get_buffer, ofile);
1055 } while (msg->sadb_msg_pid != mypid ||
1056 (msg->sadb_msg_errno == 0 && msg->sadb_msg_seq != 0));
1058 if (ofile != NULL && ofile != stdout)
1059 (void) fclose(ofile);
1061 if (msg->sadb_msg_errno == 0) {
1062 if (ofile == NULL)
1063 (void) printf(
1064 gettext("Dump succeeded for SA type %d.\n"),
1065 satype);
1066 } else {
1067 print_diagnostic(stderr, msg->sadb_x_msg_diagnostic);
1068 errno = msg->sadb_msg_errno;
1069 Bail("Dump failed");
1073 #define SCOPE_UNSPEC 0
1074 #define SCOPE_LINKLOCAL 1
1075 #define SCOPE_SITELOCAL 2
1076 #define SCOPE_GLOBAL 3
1077 #define SCOPE_V4COMPAT 4
1078 #define SCOPE_LOOPBACK 5 /* Pedantic, yes, but necessary. */
1080 static int
1081 ipv6_addr_scope(struct in6_addr *addr)
1083 /* Don't return anything regarding multicast for now... */
1085 if (IN6_IS_ADDR_UNSPECIFIED(addr))
1086 return (SCOPE_UNSPEC);
1088 if (IN6_IS_ADDR_LINKLOCAL(addr))
1089 return (SCOPE_LINKLOCAL);
1091 if (IN6_IS_ADDR_SITELOCAL(addr))
1092 return (SCOPE_SITELOCAL);
1094 if (IN6_IS_ADDR_V4COMPAT(addr))
1095 return (SCOPE_V4COMPAT);
1097 if (IN6_IS_ADDR_LOOPBACK(addr))
1098 return (SCOPE_LOOPBACK);
1100 /* For now, return global by default. */
1101 return (SCOPE_GLOBAL);
1105 * doaddresses():
1107 * Used by doaddup() and dodelget() to create new SA's based on the
1108 * provided source and destination addresses hostent.
1110 * sadb_msg_type: expected PF_KEY reply message type
1111 * sadb_msg_satype: expected PF_KEY reply satype
1112 * cmd: user command
1113 * srchp: hostent for the source address(es)
1114 * dsthp: hostent for the destination address(es)
1115 * src: points to the SADB source address extension
1116 * dst: points to the SADB destination address extension
1117 * unspec_src: indicates an unspecified source address.
1118 * buffer: pointer to the SADB buffer to use with PF_KEY
1119 * buffer_size: size of buffer
1120 * spi: spi for this message (set by caller)
1121 * srcport: source port if specified
1122 * dstport: destination port if specified
1123 * proto: IP protocol number if specified
1124 * iproto: Inner (tunnel mode) IP protocol number if specified
1125 * NATT note: we are going to assume a semi-sane world where NAT
1126 * boxen don't explode to multiple addresses.
1128 static void
1129 doaddresses(uint8_t sadb_msg_type, uint8_t sadb_msg_satype, int cmd,
1130 struct hostent *srchp, struct hostent *dsthp,
1131 struct sadb_address *src, struct sadb_address *dst,
1132 boolean_t unspec_src, uint64_t *buffer, int buffer_size, uint32_t spi,
1133 char *ebuf)
1135 boolean_t last_dst;
1136 struct sockaddr_in6 *sin6;
1137 struct sadb_msg *msgp;
1138 int i, rc;
1139 char **walker; /* For the SRC and PROXY walking functions. */
1140 char *first_match;
1141 uint64_t savebuf[MAX_GET_SIZE];
1142 uint16_t srcport = 0, dstport = 0;
1143 char *ep = NULL;
1146 * Okay, now we have "src", "dst", and maybe "proxy" reassigned
1147 * to point into the buffer to be written to PF_KEY, we can do
1148 * potentially several writes based on destination address.
1150 * First, obtain port numbers from passed-in extensions.
1153 if (src != NULL) {
1154 sin6 = (struct sockaddr_in6 *)(src + 1);
1155 srcport = ntohs(sin6->sin6_port);
1157 if (dst != NULL) {
1158 sin6 = (struct sockaddr_in6 *)(dst + 1);
1159 dstport = ntohs(sin6->sin6_port);
1163 * The rules for ADD, GET, and UPDATE: (NOTE: This assumes IPsec.
1164 * If other consumers of PF_KEY happen, this will have to be
1165 * rewhacked.):
1167 * Do a message for every possible DST address.
1169 * If a source or proxy address explodes, keep unspecified
1170 * (and mention unspecified).
1172 * DELETE is different, because you can leave either "src" or "dst"
1173 * blank! You need to explode if one of them is full, and not assume
1174 * that the other is set.
1177 if (dsthp == NULL) {
1179 * No destination address specified.
1180 * With extended diagnostics, we don't have to bail the
1181 * non-DELETE cases here. The EINVAL diagnostics will be
1182 * enough to inform the user(s) what happened.
1184 i = 0;
1185 do {
1186 if (srchp == &dummy.he) {
1187 /* Just to be sure... */
1188 srchp->h_addr_list[1] = NULL;
1189 } else if (srchp != NULL) {
1190 /* Degenerate case, h_addr_list[0] == NULL. */
1191 if (srchp->h_addr_list[i] == NULL)
1192 Bail("Empty source address list");
1195 * Fill in the src sockaddr.
1197 sin6 = (struct sockaddr_in6 *)(src + 1);
1198 bzero(sin6, sizeof (*sin6));
1199 bcopy(srchp->h_addr_list[i], &sin6->sin6_addr,
1200 sizeof (struct in6_addr));
1201 sin6->sin6_family = AF_INET6;
1202 sin6->sin6_port = htons(srcport);
1205 /* Save off a copy for later writing... */
1206 msgp = (struct sadb_msg *)buffer;
1207 bcopy(buffer, savebuf, SADB_64TO8(msgp->sadb_msg_len));
1209 rc = key_write(keysock, buffer,
1210 SADB_64TO8(msgp->sadb_msg_len));
1211 if (rc == -1)
1212 Bail("write() to PF_KEY socket "
1213 "(in doaddresses)");
1215 time_critical_enter();
1216 do {
1217 rc = read(keysock, buffer, buffer_size);
1218 if (rc == -1)
1219 Bail("read (in doaddresses)");
1220 } while (msgp->sadb_msg_seq != seq ||
1221 msgp->sadb_msg_pid != mypid);
1222 time_critical_exit();
1224 if (msgp->sadb_msg_type != sadb_msg_type ||
1225 msgp->sadb_msg_satype != sadb_msg_satype) {
1226 syslog((LOG_NOTICE|LOG_AUTH), gettext(
1227 "doaddresses: Unexpected returned message "
1228 "(%d exp %d)\n"), msgp->sadb_msg_type,
1229 sadb_msg_type);
1230 Bail("doaddresses: Unexpected returned "
1231 "message");
1234 errno = msgp->sadb_msg_errno;
1235 if (errno != 0) {
1236 if (errno == EINVAL) {
1237 WARN(ep, ebuf, gettext(
1238 "One of the entered "
1239 "values is incorrect."));
1240 print_diagnostic(stderr,
1241 msgp->sadb_x_msg_diagnostic);
1242 } else {
1243 Bail("return message (in doaddresses)");
1247 /* ...and then restore the saved buffer. */
1248 msgp = (struct sadb_msg *)savebuf;
1249 bcopy(savebuf, buffer, SADB_64TO8(msgp->sadb_msg_len));
1250 } while (srchp != NULL && srchp->h_addr_list[++i] != NULL);
1251 return;
1255 * Go through the list of all dst addresses, trying to find matching
1256 * src address for each. If the first address is == dummy.he we will go
1257 * through the loop just once. If any other hp is == dummy.he, then we
1258 * don't have to apply any silly rules.
1260 for (i = 0; dsthp->h_addr_list[i] != NULL; i++) {
1261 if (dsthp == &dummy.he) {
1262 /* Just to be sure... */
1263 dsthp->h_addr_list[1] = NULL;
1264 } else {
1266 * Fill in the dst sockaddr.
1268 sin6 = (struct sockaddr_in6 *)(dst + 1);
1269 bzero(sin6, sizeof (*sin6));
1270 bcopy(dsthp->h_addr_list[i], &sin6->sin6_addr,
1271 sizeof (struct in6_addr));
1272 sin6->sin6_family = AF_INET6;
1273 sin6->sin6_port = htons(dstport);
1276 last_dst = (dsthp->h_addr_list[i + 1] == NULL);
1279 * Try and assign src, if there's any ambiguity.
1281 if (!unspec_src && srchp != &dummy.he) {
1282 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1284 * IPv4 address. Find an IPv4 address, then
1285 * keep looking for a second one. If a second
1286 * exists, print a message, and fill in the
1287 * unspecified address.
1289 first_match = NULL;
1291 for (walker = srchp->h_addr_list;
1292 *walker != NULL; walker++) {
1293 /* LINTED E_BAD_PTR_CAST_ALIGN */
1294 if (IN6_IS_ADDR_V4MAPPED(
1295 (struct in6_addr *)*walker)) {
1296 if (first_match != NULL)
1297 break;
1298 else
1299 first_match = *walker;
1302 sin6 = (struct sockaddr_in6 *)(src + 1);
1303 bzero(sin6, sizeof (*sin6));
1305 if (first_match == NULL) {
1307 * No IPv4 hits. Is this the last
1308 * destination address in the list ?
1310 ERROR1(ep, ebuf, gettext(
1311 "No IPv4 source address "
1312 "for name %s.\n"), srchp->h_name);
1313 if (last_dst) {
1314 FATAL(ep, ebuf, gettext(
1315 "No match for destination "
1316 "IP address.\n"));
1317 } else {
1318 /* Continue, but do I print? */
1319 continue; /* for loop */
1322 /* I should never reach here. */
1325 sin6->sin6_family = AF_INET6;
1326 sin6->sin6_port = htons(srcport);
1327 if (*walker != NULL) {
1329 * Early loop exit. It must've been
1330 * multiple hits...
1332 * Issue a null-source warning?
1334 WARN1(ep, ebuf, gettext(
1335 "Multiple IPv4 source addresses "
1336 "for %s, using unspecified source "
1337 "instead."), srchp->h_name);
1338 } else {
1340 * If I reach here w/o hitting the
1341 * previous if statements, I have a
1342 * single source address for this
1343 * destination.
1345 bcopy(first_match, &sin6->sin6_addr,
1346 sizeof (struct in6_addr));
1348 } else {
1350 * IPv6 address. Find an IPv6 address.
1351 * Unlike IPv4 addresses, things can get a
1352 * little more sticky with scopes, etc.
1354 int dst_scope, src_scope;
1356 dst_scope = ipv6_addr_scope(&sin6->sin6_addr);
1358 first_match = NULL;
1359 for (walker = srchp->h_addr_list;
1360 *walker != NULL; walker++) {
1361 /* LINTED E_BAD_PTR_CAST_ALIGN */
1362 if (!IN6_IS_ADDR_V4MAPPED(
1363 (struct in6_addr *)*walker)) {
1365 * Set first-match, etc.
1366 * Take into account scopes,
1367 * and other IPv6 thingies.
1369 src_scope = ipv6_addr_scope(
1370 /* LINTED E_BAD_PTR_CAST */
1371 (struct in6_addr *)*walker);
1372 if (src_scope == SCOPE_UNSPEC ||
1373 src_scope == dst_scope) {
1374 if (first_match !=
1375 NULL)
1376 break;
1377 else
1378 first_match =
1379 *walker;
1384 sin6 = (struct sockaddr_in6 *)(src + 1);
1385 bzero(sin6, sizeof (*sin6));
1386 sin6->sin6_port = htons(srcport);
1387 if (first_match == NULL) {
1389 * No IPv6 hits. Is this the last
1390 * destination address in the list ?
1392 ERROR1(ep, ebuf, gettext(
1393 "No IPv6 source address of "
1394 "matching scope for name %s.\n"),
1395 srchp->h_name);
1396 if (last_dst) {
1397 FATAL(ep, ebuf, gettext(
1398 "No match for IPV6 "
1399 "destination "
1400 "address.\n"));
1401 } else {
1402 /* Continue, but do I print? */
1403 continue; /* for loop */
1406 /* I should never reach here. */
1408 sin6->sin6_family = AF_INET6;
1409 if (*walker != NULL) {
1411 * Early loop exit. Issue a
1412 * null-source warning?
1414 WARN1(ep, ebuf, gettext(
1415 "Multiple IPv6 source addresses "
1416 "for %s of the same scope, using "
1417 "unspecified source instead.\n"),
1418 srchp->h_name);
1419 } else {
1421 * If I reach here w/o hitting the
1422 * previous if statements, I have a
1423 * single source address for this
1424 * destination.
1426 bcopy(first_match, &sin6->sin6_addr,
1427 sizeof (struct in6_addr));
1433 * If there are errors at this point there is no
1434 * point sending anything to PF_KEY.
1436 handle_errors(ep, ebuf, B_TRUE, B_FALSE);
1438 /* Save off a copy for later writing... */
1439 msgp = (struct sadb_msg *)buffer;
1440 bcopy(buffer, savebuf, SADB_64TO8(msgp->sadb_msg_len));
1442 rc = key_write(keysock, buffer, SADB_64TO8(msgp->sadb_msg_len));
1443 if (rc == -1)
1444 Bail("write() to PF_KEY socket (in doaddresses)");
1446 /* Blank the key for paranoia's sake. */
1447 bzero(buffer, buffer_size);
1448 time_critical_enter();
1449 do {
1450 rc = read(keysock, buffer, buffer_size);
1451 if (rc == -1)
1452 Bail("read (in doaddresses)");
1453 } while (msgp->sadb_msg_seq != seq ||
1454 msgp->sadb_msg_pid != mypid);
1455 time_critical_exit();
1458 * I should _never_ hit the following unless:
1460 * 1. There is a kernel bug.
1461 * 2. Another process is mistakenly using my pid in a PF_KEY
1462 * message.
1464 if (msgp->sadb_msg_type != sadb_msg_type ||
1465 msgp->sadb_msg_satype != sadb_msg_satype) {
1466 syslog((LOG_NOTICE|LOG_AUTH), gettext(
1467 "doaddresses: Unexpected returned message "
1468 "(%d exp %d)\n"), msgp->sadb_msg_type,
1469 sadb_msg_type);
1470 Bail("doaddresses: Unexpected returned message");
1473 if (msgp->sadb_msg_errno != 0) {
1474 char addrprint[INET6_ADDRSTRLEN];
1475 int on_errno = 0;
1476 char *on_errno_msg;
1479 * Print different error messages depending
1480 * on the SADB message type being processed.
1481 * If we get a ESRCH error for a GET/DELETE
1482 * messages, we report that the SA does not
1483 * exist. If we get a EEXIST error for a
1484 * ADD/UPDATE message, we report that the
1485 * SA already exists.
1487 if (sadb_msg_type == SADB_GET ||
1488 sadb_msg_type == SADB_DELETE) {
1489 on_errno = ESRCH;
1490 on_errno_msg = "does not exist";
1491 } else if (sadb_msg_type == SADB_ADD ||
1492 sadb_msg_type == SADB_UPDATE) {
1493 on_errno = EEXIST;
1494 on_errno_msg = "already exists";
1497 errno = msgp->sadb_msg_errno;
1498 if (errno == on_errno) {
1499 ERROR2(ep, ebuf, gettext(
1500 "Association (type = %s) "
1501 "with spi 0x%x and addr\n"),
1502 rparsesatype(msgp->sadb_msg_satype),
1503 ntohl(spi));
1504 ERROR2(ep, ebuf, "%s %s.\n",
1505 do_inet_ntop(dsthp->h_addr_list[i],
1506 addrprint, sizeof (addrprint)),
1507 on_errno_msg);
1508 msgp = (struct sadb_msg *)savebuf;
1509 bcopy(savebuf, buffer,
1510 SADB_64TO8(msgp->sadb_msg_len));
1511 continue;
1512 } else {
1513 if (errno == EINVAL || errno == ESRCH) {
1514 ERROR2(ep, ebuf, gettext(
1515 "PF_KEY Diagnostic code %u: %s.\n"),
1516 msgp->sadb_x_msg_diagnostic,
1517 keysock_diag(
1518 msgp->sadb_x_msg_diagnostic));
1519 } else {
1520 Bail("return message (in doaddresses)");
1525 if (cmd == CMD_GET) {
1526 if (msgp->sadb_msg_len > MAX_GET_SIZE) {
1527 WARN1(ep, ebuf, gettext("WARNING: "
1528 "SA information bigger than %d bytes.\n"),
1529 SADB_64TO8(MAX_GET_SIZE));
1531 print_samsg(stdout, buffer, B_FALSE, vflag, nflag);
1534 handle_errors(ep, ebuf, B_TRUE, B_FALSE);
1536 /* ...and then restore the saved buffer. */
1537 msgp = (struct sadb_msg *)savebuf;
1538 bcopy(savebuf, buffer, SADB_64TO8(msgp->sadb_msg_len));
1539 lines_added++;
1542 /* Degenerate case, h_addr_list[0] == NULL. */
1543 if (i == 0)
1544 Bail("Empty destination address list");
1547 * free(ebuf) even if there are no errors.
1548 * handle_errors() won't return here.
1550 handle_errors(ep, ebuf, B_TRUE, B_TRUE);
1554 * Perform an add or an update. ADD and UPDATE are similar in the extensions
1555 * they need.
1557 static void
1558 doaddup(int cmd, int satype, char *argv[], char *ebuf)
1560 uint64_t *buffer, *nexthdr;
1561 struct sadb_msg msg;
1562 struct sadb_sa *assoc = NULL;
1563 struct sadb_x_pair *sadb_pair = NULL;
1564 struct sadb_address *src = NULL, *dst = NULL;
1565 struct sadb_address *isrc = NULL, *idst = NULL;
1566 struct sadb_address *natt_local = NULL, *natt_remote = NULL;
1567 struct sadb_key *encrypt = NULL, *auth = NULL;
1568 struct sadb_ident *srcid = NULL, *dstid = NULL;
1569 struct sadb_lifetime *hard = NULL, *soft = NULL; /* Current? */
1570 struct sadb_lifetime *idle = NULL;
1571 struct sadb_x_replay_ctr *replay_ctr = NULL;
1572 struct sockaddr_in6 *sin6;
1573 int next, token, sa_len, alloclen, totallen = sizeof (msg), prefix;
1574 uint32_t spi = 0;
1575 uint_t reserved_bits = 0;
1576 uint8_t sadb_msg_type;
1577 char *thiscmd, *pstr;
1578 boolean_t readstate = B_FALSE, unspec_src = B_FALSE;
1579 boolean_t alloc_inner = B_FALSE, use_natt = B_FALSE;
1580 struct hostent *srchp = NULL, *dsthp = NULL, *isrchp = NULL,
1581 *idsthp = NULL;
1582 struct hostent *natt_lhp = NULL, *natt_rhp = NULL;
1583 uint16_t srcport = 0, dstport = 0, natt_lport = 0, natt_rport = 0,
1584 isrcport = 0, idstport = 0;
1585 uint8_t proto = 0, iproto = 0;
1586 char *ep = NULL;
1588 switch (cmd) {
1589 case CMD_ADD:
1590 thiscmd = "add";
1591 sadb_msg_type = SADB_ADD;
1592 break;
1593 case CMD_UPDATE:
1594 thiscmd = "update";
1595 sadb_msg_type = SADB_UPDATE;
1596 break;
1597 case CMD_UPDATE_PAIR:
1598 thiscmd = "update-pair";
1599 sadb_msg_type = SADB_X_UPDATEPAIR;
1600 break;
1603 msg_init(&msg, sadb_msg_type, (uint8_t)satype);
1604 /* Assume last element in argv is set to NULL. */
1605 do {
1606 token = parseextval(*argv, &next);
1607 argv++;
1608 switch (token) {
1609 case TOK_EOF:
1610 /* Do nothing, I'm done. */
1611 break;
1612 case TOK_UNKNOWN:
1613 ERROR1(ep, ebuf, gettext(
1614 "Unknown extension field \"%s\" \n"), *(argv - 1));
1615 break;
1616 case TOK_SPI:
1617 case TOK_PAIR_SPI:
1618 case TOK_REPLAY:
1619 case TOK_STATE:
1620 case TOK_AUTHALG:
1621 case TOK_ENCRALG:
1622 case TOK_ENCAP:
1624 * May want to place this chunk of code in a function.
1626 * This code checks for duplicate entries on a command
1627 * line.
1630 /* Allocate the SADB_EXT_SA extension. */
1631 if (assoc == NULL) {
1632 assoc = malloc(sizeof (*assoc));
1633 if (assoc == NULL)
1634 Bail("malloc(assoc)");
1635 bzero(assoc, sizeof (*assoc));
1636 assoc->sadb_sa_exttype = SADB_EXT_SA;
1637 assoc->sadb_sa_len =
1638 SADB_8TO64(sizeof (*assoc));
1639 totallen += sizeof (*assoc);
1641 switch (token) {
1642 case TOK_SPI:
1644 * If some cretin types in "spi 0" then they
1645 * can type in another SPI.
1647 if (assoc->sadb_sa_spi != 0) {
1648 ERROR(ep, ebuf, gettext(
1649 "Can only specify "
1650 "single SPI value.\n"));
1651 break;
1653 /* Must convert SPI to network order! */
1654 assoc->sadb_sa_spi =
1655 htonl((uint32_t)parsenum(*argv, B_TRUE,
1656 ebuf));
1657 if (assoc->sadb_sa_spi == 0) {
1658 ERROR(ep, ebuf, gettext(
1659 "Invalid SPI value \"0\" .\n"));
1661 break;
1662 case TOK_PAIR_SPI:
1663 if (cmd == CMD_UPDATE_PAIR) {
1664 ERROR(ep, ebuf, gettext(
1665 "pair-spi can not be used with the "
1666 "\"update-pair\" command.\n"));
1668 if (sadb_pair == NULL) {
1669 sadb_pair = malloc(sizeof (*sadb_pair));
1670 if (assoc == NULL)
1671 Bail("malloc(assoc)");
1672 bzero(sadb_pair, sizeof (*sadb_pair));
1673 totallen += sizeof (*sadb_pair);
1675 if (sadb_pair->sadb_x_pair_spi != 0) {
1676 ERROR(ep, ebuf, gettext(
1677 "Can only specify "
1678 "single pair SPI value.\n"));
1679 break;
1681 /* Must convert SPI to network order! */
1682 sadb_pair->sadb_x_pair_len =
1683 SADB_8TO64(sizeof (*sadb_pair));
1684 sadb_pair->sadb_x_pair_exttype =
1685 SADB_X_EXT_PAIR;
1686 sadb_pair->sadb_x_pair_spi =
1687 htonl((uint32_t)parsenum(*argv, B_TRUE,
1688 ebuf));
1689 if (sadb_pair->sadb_x_pair_spi == 0) {
1690 ERROR(ep, ebuf, gettext(
1691 "Invalid SPI value \"0\" .\n"));
1693 assoc->sadb_sa_flags |=
1694 SADB_X_SAFLAGS_PAIRED;
1695 break;
1696 case TOK_REPLAY:
1698 * That same cretin can do the same with
1699 * replay.
1701 if (assoc->sadb_sa_replay != 0) {
1702 ERROR(ep, ebuf, gettext(
1703 "Can only specify "
1704 "single replay window size.\n"));
1705 break;
1707 assoc->sadb_sa_replay =
1708 (uint8_t)parsenum(*argv, B_TRUE, ebuf);
1709 if (assoc->sadb_sa_replay != 0) {
1710 WARN(ep, ebuf, gettext(
1711 "WARNING: Replay with manual"
1712 " keying considered harmful.\n"));
1714 break;
1715 case TOK_STATE:
1717 * 0 is an actual state value, LARVAL. This
1718 * means that one can type in the larval state
1719 * and then type in another state on the same
1720 * command line.
1722 if (assoc->sadb_sa_state != 0) {
1723 ERROR(ep, ebuf, gettext(
1724 "Can only specify "
1725 "single SA state.\n"));
1726 break;
1728 assoc->sadb_sa_state = parsestate(*argv,
1729 ebuf);
1730 readstate = B_TRUE;
1731 break;
1732 case TOK_AUTHALG:
1733 if (assoc->sadb_sa_auth != 0) {
1734 ERROR(ep, ebuf, gettext(
1735 "Can only specify "
1736 "single auth algorithm.\n"));
1737 break;
1739 assoc->sadb_sa_auth = parsealg(*argv,
1740 IPSEC_PROTO_AH, ebuf);
1741 break;
1742 case TOK_ENCRALG:
1743 if (satype == SADB_SATYPE_AH) {
1744 ERROR(ep, ebuf, gettext("Cannot specify"
1745 " encryption with SA type ah.\n"));
1746 break;
1748 if (assoc->sadb_sa_encrypt != 0) {
1749 ERROR(ep, ebuf, gettext(
1750 "Can only specify "
1751 "single encryption algorithm.\n"));
1752 break;
1754 assoc->sadb_sa_encrypt = parsealg(*argv,
1755 IPSEC_PROTO_ESP, ebuf);
1756 break;
1757 case TOK_ENCAP:
1758 if (use_natt) {
1759 ERROR(ep, ebuf, gettext(
1760 "Can only specify single"
1761 " encapsulation.\n"));
1762 break;
1764 if (strncmp(*argv, "udp", 3)) {
1765 ERROR(ep, ebuf, gettext(
1766 "Can only specify udp"
1767 " encapsulation.\n"));
1768 break;
1770 use_natt = B_TRUE;
1771 /* set assoc flags later */
1772 break;
1774 argv++;
1775 break;
1776 case TOK_SRCPORT:
1777 if (srcport != 0) {
1778 ERROR(ep, ebuf, gettext("Can only specify "
1779 "single source port.\n"));
1780 break;
1782 srcport = parsenum(*argv, B_TRUE, ebuf);
1783 argv++;
1784 break;
1785 case TOK_DSTPORT:
1786 if (dstport != 0) {
1787 ERROR(ep, ebuf, gettext("Can only specify "
1788 "single destination port.\n"));
1789 break;
1791 dstport = parsenum(*argv, B_TRUE, ebuf);
1792 argv++;
1793 break;
1794 case TOK_ISRCPORT:
1795 alloc_inner = B_TRUE;
1796 if (isrcport != 0) {
1797 ERROR(ep, ebuf, gettext(
1798 "Can only specify "
1799 "single inner-source port.\n"));
1800 break;
1802 isrcport = parsenum(*argv, B_TRUE, ebuf);
1803 argv++;
1804 break;
1805 case TOK_IDSTPORT:
1806 alloc_inner = B_TRUE;
1807 if (idstport != 0) {
1808 ERROR(ep, ebuf, gettext(
1809 "Can only specify "
1810 "single inner-destination port.\n"));
1811 break;
1813 idstport = parsenum(*argv, B_TRUE, ebuf);
1814 argv++;
1815 break;
1816 case TOK_NATLPORT:
1817 if (natt_lport != 0) {
1818 ERROR(ep, ebuf, gettext(
1819 "Can only specify "
1820 "single NAT-T local port.\n"));
1821 break;
1823 natt_lport = parsenum(*argv, B_TRUE, ebuf);
1824 argv++;
1825 break;
1826 case TOK_NATRPORT:
1827 if (natt_rport != 0) {
1828 ERROR(ep, ebuf, gettext(
1829 "Can only specify "
1830 "single NAT-T remote port.\n"));
1831 break;
1833 natt_rport = parsenum(*argv, B_TRUE, ebuf);
1834 argv++;
1835 break;
1837 case TOK_PROTO:
1838 if (proto != 0) {
1839 ERROR(ep, ebuf, gettext(
1840 "Can only specify "
1841 "single protocol.\n"));
1842 break;
1844 proto = parsenum(*argv, B_TRUE, ebuf);
1845 argv++;
1846 break;
1847 case TOK_IPROTO:
1848 alloc_inner = B_TRUE;
1849 if (iproto != 0) {
1850 ERROR(ep, ebuf, gettext(
1851 "Can only specify "
1852 "single inner protocol.\n"));
1853 break;
1855 iproto = parsenum(*argv, B_TRUE, ebuf);
1856 argv++;
1857 break;
1858 case TOK_SRCADDR:
1859 case TOK_SRCADDR6:
1860 if (src != NULL) {
1861 ERROR(ep, ebuf, gettext(
1862 "Can only specify "
1863 "single source address.\n"));
1864 break;
1866 sa_len = parseaddr(*argv, &srchp,
1867 (token == TOK_SRCADDR6), ebuf);
1868 if (srchp == NULL) {
1869 ERROR1(ep, ebuf, gettext(
1870 "Unknown src address \"%s\"\n"), *argv);
1871 break;
1873 argv++;
1875 * Round of the sockaddr length to an 8 byte
1876 * boundary to make PF_KEY happy.
1878 alloclen = sizeof (*src) + roundup(sa_len, 8);
1879 src = malloc(alloclen);
1880 if (src == NULL)
1881 Bail("malloc(src)");
1882 totallen += alloclen;
1883 src->sadb_address_len = SADB_8TO64(alloclen);
1884 src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
1885 src->sadb_address_reserved = 0;
1886 src->sadb_address_prefixlen = 0;
1887 src->sadb_address_proto = 0;
1888 if (srchp == &dummy.he) {
1890 * Single address with -n flag.
1892 sin6 = (struct sockaddr_in6 *)(src + 1);
1893 bzero(sin6, sizeof (*sin6));
1894 sin6->sin6_family = AF_INET6;
1895 bcopy(srchp->h_addr_list[0], &sin6->sin6_addr,
1896 sizeof (struct in6_addr));
1898 break;
1899 case TOK_DSTADDR:
1900 case TOK_DSTADDR6:
1901 if (dst != NULL) {
1902 ERROR(ep, ebuf, gettext(
1903 "Can only specify single "
1904 "destination address.\n"));
1905 break;
1907 sa_len = parseaddr(*argv, &dsthp,
1908 (token == TOK_DSTADDR6), ebuf);
1909 if (dsthp == NULL) {
1910 ERROR1(ep, ebuf, gettext(
1911 "Unknown dst address \"%s\"\n"), *argv);
1912 break;
1914 argv++;
1915 alloclen = sizeof (*dst) + roundup(sa_len, 8);
1916 dst = malloc(alloclen);
1917 if (dst == NULL)
1918 Bail("malloc(dst)");
1919 totallen += alloclen;
1920 dst->sadb_address_len = SADB_8TO64(alloclen);
1921 dst->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
1922 dst->sadb_address_reserved = 0;
1923 dst->sadb_address_prefixlen = 0;
1924 dst->sadb_address_proto = 0;
1925 if (dsthp == &dummy.he) {
1927 * Single address with -n flag.
1929 sin6 = (struct sockaddr_in6 *)(dst + 1);
1930 bzero(sin6, sizeof (*sin6));
1931 sin6->sin6_family = AF_INET6;
1932 bcopy(dsthp->h_addr_list[0], &sin6->sin6_addr,
1933 sizeof (struct in6_addr));
1935 break;
1936 case TOK_PROXYADDR:
1937 case TOK_PROXYADDR6:
1938 if (isrc != NULL) {
1939 ERROR(ep, ebuf, gettext(
1940 "Can only specify single "
1941 "proxy/inner-source address.\n"));
1942 break;
1944 if ((pstr = strchr(*argv, '/')) != NULL) {
1945 /* Parse out the prefix. */
1946 errno = 0;
1947 prefix = strtol(pstr + 1, NULL, 10);
1948 if (errno != 0) {
1949 ERROR1(ep, ebuf, gettext(
1950 "Invalid prefix %s."), pstr);
1951 break;
1953 /* Recycle pstr */
1954 alloclen = (int)(pstr - *argv);
1955 pstr = malloc(alloclen + 1);
1956 if (pstr == NULL) {
1957 Bail("malloc(pstr)");
1959 (void) strlcpy(pstr, *argv, alloclen + 1);
1960 } else {
1961 pstr = *argv;
1963 * Assume mapping to AF_INET6, and we're a host.
1964 * XXX some miscreants may still make classful
1965 * assumptions. If this is a problem, fix it
1966 * here.
1968 prefix = 128;
1970 sa_len = parseaddr(pstr, &isrchp,
1971 (token == TOK_PROXYADDR6), ebuf);
1972 if (isrchp == NULL) {
1973 ERROR1(ep, ebuf, gettext(
1974 "Unknown proxy/inner-source address "
1975 "\"%s\"\n"), *argv);
1976 break;
1978 if (pstr != *argv)
1979 free(pstr);
1980 argv++;
1981 alloclen = sizeof (*isrc) + roundup(sa_len, 8);
1982 isrc = malloc(alloclen);
1983 if (isrc == NULL)
1984 Bail("malloc(isrc)");
1985 totallen += alloclen;
1986 isrc->sadb_address_len = SADB_8TO64(alloclen);
1987 isrc->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
1988 isrc->sadb_address_reserved = 0;
1989 isrc->sadb_address_prefixlen = prefix;
1990 isrc->sadb_address_proto = 0;
1991 if (isrchp == &dummy.he ||
1992 isrchp->h_addr_list[1] == NULL) {
1994 * Single address with -n flag or single name.
1996 sin6 = (struct sockaddr_in6 *)(isrc + 1);
1997 bzero(sin6, sizeof (*sin6));
1998 sin6->sin6_family = AF_INET6;
1999 bcopy(isrchp->h_addr_list[0], &sin6->sin6_addr,
2000 sizeof (struct in6_addr));
2002 * normalize prefixlen for IPv4-mapped
2003 * addresses.
2005 if (prefix <= 32 &&
2006 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
2007 isrc->sadb_address_prefixlen += 96;
2008 alloc_inner = B_TRUE;
2009 } else {
2011 * If the proxy/isrc address is vague, don't
2012 * bother.
2014 totallen -= alloclen;
2015 free(isrc);
2016 isrc = NULL;
2017 WARN1(ep, ebuf, gettext(
2018 "Proxy/inner-source address %s "
2019 "is vague, not using.\n"), isrchp->h_name);
2020 freehostent(isrchp);
2021 isrchp = NULL;
2022 break;
2024 break;
2025 case TOK_IDSTADDR:
2026 case TOK_IDSTADDR6:
2027 if (idst != NULL) {
2028 ERROR(ep, ebuf, gettext(
2029 "Can only specify single "
2030 "inner-destination address.\n"));
2031 break;
2033 if ((pstr = strchr(*argv, '/')) != NULL) {
2034 /* Parse out the prefix. */
2035 errno = 0;
2036 prefix = strtol(pstr + 1, NULL, 10);
2037 if (errno != 0) {
2038 ERROR1(ep, ebuf, gettext(
2039 "Invalid prefix %s.\n"), pstr);
2040 break;
2042 /* Recycle pstr */
2043 alloclen = (int)(pstr - *argv);
2044 pstr = malloc(alloclen + 1);
2045 if (pstr == NULL) {
2046 Bail("malloc(pstr)");
2048 (void) strlcpy(pstr, *argv, alloclen + 1);
2049 } else {
2050 pstr = *argv;
2052 * Assume mapping to AF_INET6, and we're a host.
2053 * XXX some miscreants may still make classful
2054 * assumptions. If this is a problem, fix it
2055 * here.
2057 prefix = 128;
2059 sa_len = parseaddr(pstr, &idsthp,
2060 (token == TOK_IDSTADDR6), ebuf);
2061 if (idsthp == NULL) {
2062 ERROR1(ep, ebuf, gettext(
2063 "Unknown Inner Src address "
2064 " \"%s\"\n"), *argv);
2065 break;
2067 if (pstr != *argv)
2068 free(pstr);
2069 argv++;
2070 alloclen = sizeof (*idst) + roundup(sa_len, 8);
2071 idst = malloc(alloclen);
2072 if (idst == NULL)
2073 Bail("malloc(idst)");
2074 totallen += alloclen;
2075 idst->sadb_address_len = SADB_8TO64(alloclen);
2076 idst->sadb_address_exttype =
2077 SADB_X_EXT_ADDRESS_INNER_DST;
2078 idst->sadb_address_reserved = 0;
2079 idst->sadb_address_prefixlen = prefix;
2080 idst->sadb_address_proto = 0;
2081 if (idsthp == &dummy.he ||
2082 idsthp->h_addr_list[1] == NULL) {
2084 * Single address with -n flag or single name.
2086 sin6 = (struct sockaddr_in6 *)(idst + 1);
2087 bzero(sin6, sizeof (*sin6));
2088 sin6->sin6_family = AF_INET6;
2089 bcopy(idsthp->h_addr_list[0], &sin6->sin6_addr,
2090 sizeof (struct in6_addr));
2092 * normalize prefixlen for IPv4-mapped
2093 * addresses.
2095 if (prefix <= 32 &&
2096 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
2097 idst->sadb_address_prefixlen += 96;
2098 alloc_inner = B_TRUE;
2099 } else {
2101 * If the idst address is vague, don't bother.
2103 totallen -= alloclen;
2104 free(idst);
2105 idst = NULL;
2106 WARN1(ep, ebuf, gettext(
2107 "Inner destination address %s "
2108 "is vague, not using.\n"), idsthp->h_name);
2109 freehostent(idsthp);
2110 idsthp = NULL;
2111 break;
2113 break;
2114 case TOK_NATLOC:
2115 if (natt_local != NULL) {
2116 ERROR(ep, ebuf, gettext(
2117 "Can only specify "
2118 "single NAT-T local address.\n"));
2119 break;
2121 sa_len = parseaddr(*argv, &natt_lhp, 0, ebuf);
2122 if (natt_lhp == NULL) {
2123 ERROR1(ep, ebuf, gettext(
2124 "Unknown NAT-T local address \"%s\"\n"),
2125 *argv);
2126 break;
2128 argv++;
2130 * Round of the sockaddr length to an 8 byte
2131 * boundary to make PF_KEY happy.
2133 alloclen = sizeof (*natt_local) + roundup(sa_len, 8);
2134 natt_local = malloc(alloclen);
2135 if (natt_local == NULL)
2136 Bail("malloc(natt_local)");
2137 totallen += alloclen;
2138 natt_local->sadb_address_len = SADB_8TO64(alloclen);
2139 natt_local->sadb_address_exttype =
2140 SADB_X_EXT_ADDRESS_NATT_LOC;
2141 natt_local->sadb_address_reserved = 0;
2142 natt_local->sadb_address_prefixlen = 0;
2143 natt_local->sadb_address_proto = 0;
2144 if (natt_lhp == &dummy.he ||
2145 natt_lhp->h_addr_list[1] == NULL) {
2147 * Single address with -n flag or single name.
2149 sin6 = (struct sockaddr_in6 *)(natt_local + 1);
2150 bzero(sin6, sizeof (*sin6));
2151 sin6->sin6_family = AF_INET6;
2152 bcopy(natt_lhp->h_addr_list[0],
2153 &sin6->sin6_addr, sizeof (struct in6_addr));
2154 } else {
2156 * If the nat-local address is vague, don't
2157 * bother.
2159 totallen -= alloclen;
2160 free(natt_local);
2161 natt_local = NULL;
2162 WARN1(ep, ebuf, gettext(
2163 "NAT-T local address %s "
2164 "is vague, not using.\n"),
2165 natt_lhp->h_name);
2166 freehostent(natt_lhp);
2167 natt_lhp = NULL;
2168 break;
2170 break;
2171 case TOK_NATREM:
2172 if (natt_remote != NULL) {
2173 ERROR(ep, ebuf, gettext(
2174 "Can only specify "
2175 "single NAT-T remote address.\n"));
2176 break;
2178 sa_len = parseaddr(*argv, &natt_rhp, 0, ebuf);
2179 if (natt_rhp == NULL) {
2180 ERROR1(ep, ebuf, gettext(
2181 "Unknown NAT-T remote address \"%s\"\n"),
2182 *argv);
2183 break;
2185 argv++;
2187 * Round of the sockaddr length to an 8 byte
2188 * boundary to make PF_KEY happy.
2190 alloclen = sizeof (*natt_remote) + roundup(sa_len, 8);
2191 natt_remote = malloc(alloclen);
2192 if (natt_remote == NULL)
2193 Bail("malloc(natt_remote)");
2194 totallen += alloclen;
2195 natt_remote->sadb_address_len = SADB_8TO64(alloclen);
2196 natt_remote->sadb_address_exttype =
2197 SADB_X_EXT_ADDRESS_NATT_REM;
2198 natt_remote->sadb_address_reserved = 0;
2199 natt_remote->sadb_address_prefixlen = 0;
2200 natt_remote->sadb_address_proto = 0;
2201 if (natt_rhp == &dummy.he ||
2202 natt_rhp->h_addr_list[1] == NULL) {
2204 * Single address with -n flag or single name.
2206 sin6 = (struct sockaddr_in6 *)(natt_remote + 1);
2207 bzero(sin6, sizeof (*sin6));
2208 sin6->sin6_family = AF_INET6;
2209 bcopy(natt_rhp->h_addr_list[0],
2210 &sin6->sin6_addr, sizeof (struct in6_addr));
2211 } else {
2213 * If the nat-renote address is vague, don't
2214 * bother.
2216 totallen -= alloclen;
2217 free(natt_remote);
2218 natt_remote = NULL;
2219 WARN1(ep, ebuf, gettext(
2220 "NAT-T remote address %s "
2221 "is vague, not using.\n"),
2222 natt_rhp->h_name);
2223 freehostent(natt_rhp);
2224 natt_rhp = NULL;
2225 break;
2227 break;
2228 case TOK_ENCRKEY:
2229 if (encrypt != NULL) {
2230 ERROR(ep, ebuf, gettext(
2231 "Can only specify "
2232 "single encryption key.\n"));
2233 break;
2235 if (assoc != NULL &&
2236 assoc->sadb_sa_encrypt == SADB_EALG_NULL) {
2237 FATAL(ep, ebuf, gettext(
2238 "Cannot specify a key with NULL "
2239 "encryption algorithm.\n"));
2240 break;
2242 encrypt = parsekey(*argv, ebuf, reserved_bits);
2243 argv++;
2244 if (encrypt == NULL) {
2245 ERROR(ep, ebuf, gettext(
2246 "Invalid encryption key.\n"));
2247 break;
2249 totallen += SADB_64TO8(encrypt->sadb_key_len);
2250 encrypt->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
2251 break;
2252 case TOK_AUTHKEY:
2253 if (auth != NULL) {
2254 ERROR(ep, ebuf, gettext(
2255 "Can only specify single"
2256 " authentication key.\n"));
2257 break;
2259 auth = parsekey(*argv, ebuf, 0);
2260 argv++;
2261 if (auth == NULL) {
2262 ERROR(ep, ebuf, gettext(
2263 "Invalid authentication key.\n"));
2264 break;
2266 totallen += SADB_64TO8(auth->sadb_key_len);
2267 auth->sadb_key_exttype = SADB_EXT_KEY_AUTH;
2268 break;
2269 case TOK_SRCIDTYPE:
2270 if (*argv == NULL || *(argv + 1) == NULL) {
2271 FATAL(ep, ebuf, gettext(
2272 "Unexpected end of command "
2273 "line - Expecting Src Type.\n"));
2274 /* NOTREACHED */
2275 break;
2277 if (srcid != NULL) {
2278 ERROR(ep, ebuf, gettext(
2279 "Can only specify single"
2280 " source certificate identity.\n"));
2281 break;
2283 alloclen = sizeof (*srcid) +
2284 roundup(strlen(*(argv + 1)) + 1, 8);
2285 srcid = malloc(alloclen);
2286 if (srcid == NULL)
2287 Bail("malloc(srcid)");
2288 totallen += alloclen;
2289 srcid->sadb_ident_type = parseidtype(*argv, ebuf);
2290 argv++;
2291 srcid->sadb_ident_len = SADB_8TO64(alloclen);
2292 srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
2293 srcid->sadb_ident_reserved = 0;
2294 srcid->sadb_ident_id = 0; /* Not useful here. */
2295 (void) strlcpy((char *)(srcid + 1), *argv, alloclen);
2296 argv++;
2297 break;
2298 case TOK_DSTIDTYPE:
2299 if (*argv == NULL || *(argv + 1) == NULL) {
2300 ERROR(ep, ebuf, gettext(
2301 "Unexpected end of command"
2302 " line - expecting dst type.\n"));
2303 break;
2305 if (dstid != NULL) {
2306 ERROR(ep, ebuf, gettext(
2307 "Can only specify single destination "
2308 "certificate identity.\n"));
2309 break;
2311 alloclen = sizeof (*dstid) +
2312 roundup(strlen(*(argv + 1)) + 1, 8);
2313 dstid = malloc(alloclen);
2314 if (dstid == NULL)
2315 Bail("malloc(dstid)");
2316 totallen += alloclen;
2317 dstid->sadb_ident_type = parseidtype(*argv, ebuf);
2318 argv++;
2319 dstid->sadb_ident_len = SADB_8TO64(alloclen);
2320 dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
2321 dstid->sadb_ident_reserved = 0;
2322 dstid->sadb_ident_id = 0; /* Not useful here. */
2323 (void) strlcpy((char *)(dstid + 1), *argv, alloclen);
2324 argv++;
2325 break;
2326 case TOK_HARD_ALLOC:
2327 case TOK_HARD_BYTES:
2328 case TOK_HARD_ADDTIME:
2329 case TOK_HARD_USETIME:
2330 if (hard == NULL) {
2331 hard = malloc(sizeof (*hard));
2332 if (hard == NULL)
2333 Bail("malloc(hard_lifetime)");
2334 bzero(hard, sizeof (*hard));
2335 hard->sadb_lifetime_exttype =
2336 SADB_EXT_LIFETIME_HARD;
2337 hard->sadb_lifetime_len =
2338 SADB_8TO64(sizeof (*hard));
2339 totallen += sizeof (*hard);
2341 switch (token) {
2342 case TOK_HARD_ALLOC:
2343 if (hard->sadb_lifetime_allocations != 0) {
2344 ERROR(ep, ebuf, gettext(
2345 "Can only specify single"
2346 " hard allocation limit.\n"));
2347 break;
2349 hard->sadb_lifetime_allocations =
2350 (uint32_t)parsenum(*argv, B_TRUE, ebuf);
2351 break;
2352 case TOK_HARD_BYTES:
2353 if (hard->sadb_lifetime_bytes != 0) {
2354 ERROR(ep, ebuf, gettext(
2355 "Can only specify "
2356 "single hard byte limit.\n"));
2357 break;
2359 hard->sadb_lifetime_bytes = parsenum(*argv,
2360 B_TRUE, ebuf);
2361 break;
2362 case TOK_HARD_ADDTIME:
2363 if (hard->sadb_lifetime_addtime != 0) {
2364 ERROR(ep, ebuf, gettext(
2365 "Can only specify "
2366 "single past-add lifetime.\n"));
2367 break;
2369 hard->sadb_lifetime_addtime = parsenum(*argv,
2370 B_TRUE, ebuf);
2371 break;
2372 case TOK_HARD_USETIME:
2373 if (hard->sadb_lifetime_usetime != 0) {
2374 ERROR(ep, ebuf, gettext(
2375 "Can only specify "
2376 "single past-use lifetime.\n"));
2377 break;
2379 hard->sadb_lifetime_usetime = parsenum(*argv,
2380 B_TRUE, ebuf);
2381 break;
2383 argv++;
2384 break;
2385 case TOK_SOFT_ALLOC:
2386 case TOK_SOFT_BYTES:
2387 case TOK_SOFT_ADDTIME:
2388 case TOK_SOFT_USETIME:
2389 if (soft == NULL) {
2390 soft = malloc(sizeof (*soft));
2391 if (soft == NULL)
2392 Bail("malloc(soft_lifetime)");
2393 bzero(soft, sizeof (*soft));
2394 soft->sadb_lifetime_exttype =
2395 SADB_EXT_LIFETIME_SOFT;
2396 soft->sadb_lifetime_len =
2397 SADB_8TO64(sizeof (*soft));
2398 totallen += sizeof (*soft);
2400 switch (token) {
2401 case TOK_SOFT_ALLOC:
2402 if (soft->sadb_lifetime_allocations != 0) {
2403 ERROR(ep, ebuf, gettext(
2404 "Can only specify single"
2405 " soft allocation limit.\n"));
2406 break;
2408 soft->sadb_lifetime_allocations =
2409 (uint32_t)parsenum(*argv, B_TRUE, ebuf);
2410 break;
2411 case TOK_SOFT_BYTES:
2412 if (soft->sadb_lifetime_bytes != 0) {
2413 ERROR(ep, ebuf, gettext(
2414 "Can only specify single"
2415 " soft byte limit.\n"));
2416 break;
2418 soft->sadb_lifetime_bytes = parsenum(*argv,
2419 B_TRUE, ebuf);
2420 break;
2421 case TOK_SOFT_ADDTIME:
2422 if (soft->sadb_lifetime_addtime != 0) {
2423 ERROR(ep, ebuf, gettext(
2424 "Can only specify single"
2425 " past-add lifetime.\n"));
2426 break;
2428 soft->sadb_lifetime_addtime = parsenum(*argv,
2429 B_TRUE, ebuf);
2430 break;
2431 case TOK_SOFT_USETIME:
2432 if (soft->sadb_lifetime_usetime != 0) {
2433 ERROR(ep, ebuf, gettext(
2434 "Can only specify single"
2435 " past-use lifetime.\n"));
2436 break;
2438 soft->sadb_lifetime_usetime = parsenum(*argv,
2439 B_TRUE, ebuf);
2440 break;
2442 argv++;
2443 break;
2444 case TOK_FLAG_INBOUND:
2445 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_INBOUND;
2446 break;
2447 case TOK_FLAG_OUTBOUND:
2448 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_OUTBOUND;
2449 break;
2450 case TOK_REPLAY_VALUE:
2451 if (replay_ctr != NULL) {
2452 ERROR(ep, ebuf, gettext(
2453 "Can only specify single "
2454 "replay value."));
2455 break;
2457 replay_ctr = calloc(1, sizeof (*replay_ctr));
2458 if (replay_ctr == NULL) {
2459 Bail("malloc(replay value)");
2462 * We currently do not support a 64-bit
2463 * replay value. RFC 4301 will require one,
2464 * however, and we have a field in place when
2465 * 4301 is built.
2467 replay_ctr->sadb_x_rc_exttype = SADB_X_EXT_REPLAY_VALUE;
2468 replay_ctr->sadb_x_rc_len =
2469 SADB_8TO64(sizeof (*replay_ctr));
2470 totallen += sizeof (*replay_ctr);
2471 replay_ctr->sadb_x_rc_replay32 = (uint32_t)parsenum(
2472 *argv, B_TRUE, ebuf);
2473 argv++;
2474 break;
2475 case TOK_IDLE_ADDTIME:
2476 case TOK_IDLE_USETIME:
2477 if (idle == NULL) {
2478 idle = calloc(1, sizeof (*idle));
2479 if (idle == NULL) {
2480 Bail("malloc idle lifetime");
2482 idle->sadb_lifetime_exttype =
2483 SADB_X_EXT_LIFETIME_IDLE;
2484 idle->sadb_lifetime_len =
2485 SADB_8TO64(sizeof (*idle));
2486 totallen += sizeof (*idle);
2488 switch (token) {
2489 case TOK_IDLE_ADDTIME:
2490 idle->sadb_lifetime_addtime =
2491 (uint32_t)parsenum(*argv,
2492 B_TRUE, ebuf);
2493 break;
2494 case TOK_IDLE_USETIME:
2495 idle->sadb_lifetime_usetime =
2496 (uint32_t)parsenum(*argv,
2497 B_TRUE, ebuf);
2498 break;
2500 argv++;
2501 break;
2502 case TOK_RESERVED:
2503 if (encrypt != NULL)
2504 ERROR(ep, ebuf, gettext(
2505 "Reserved bits need to be "
2506 "specified before key.\n"));
2507 reserved_bits = (uint_t)parsenum(*argv,
2508 B_TRUE, ebuf);
2509 argv++;
2510 break;
2511 default:
2512 ERROR1(ep, ebuf, gettext(
2513 "Don't use extension %s for add/update.\n"),
2514 *(argv - 1));
2515 break;
2517 } while (token != TOK_EOF);
2519 handle_errors(ep, ebuf, B_TRUE, B_FALSE);
2521 #define PORT_ONLY_ALLOCATE(af, socktype, exttype, extvar, port) { \
2522 alloclen = sizeof (sadb_address_t) + roundup(sizeof (socktype), 8); \
2523 (extvar) = calloc(1, alloclen); \
2524 if ((extvar) == NULL) { \
2525 Bail("malloc(implicit port)"); \
2527 totallen += alloclen; \
2528 (extvar)->sadb_address_len = SADB_8TO64(alloclen); \
2529 (extvar)->sadb_address_exttype = (exttype); \
2530 /* sin/sin6 has equivalent offsets for ports! */ \
2531 sin6 = (struct sockaddr_in6 *)((extvar) + 1); \
2532 sin6->sin6_family = (af); \
2533 sin6->sin6_port = (port); \
2537 * If we specify inner ports or NAT ports w/o addresses, we still need
2538 * to allocate. Also, if we have one inner address, we need the
2539 * other, even if we don't specify anything.
2541 if (use_natt) {
2542 if (natt_lport != 0 && natt_local == NULL) {
2543 PORT_ONLY_ALLOCATE(AF_INET, struct sockaddr_in,
2544 SADB_X_EXT_ADDRESS_NATT_LOC, natt_local,
2545 natt_lport);
2548 if (natt_rport != 0 && natt_remote == NULL) {
2549 PORT_ONLY_ALLOCATE(AF_INET, struct sockaddr_in,
2550 SADB_X_EXT_ADDRESS_NATT_REM, natt_remote,
2551 natt_rport);
2553 } else {
2554 if (natt_lport != 0 || natt_rport != 0) {
2555 ERROR(ep, ebuf, gettext("Must specify 'encap udp' "
2556 "with any NAT-T port.\n"));
2557 } else if (natt_local != NULL || natt_remote != NULL) {
2558 ERROR(ep, ebuf, gettext("Must specify 'encap udp' "
2559 "with any NAT-T address.\n"));
2563 if (alloc_inner && idst == NULL) {
2564 PORT_ONLY_ALLOCATE(AF_INET6, struct sockaddr_in6,
2565 SADB_X_EXT_ADDRESS_INNER_DST, idst, 0);
2568 if (alloc_inner && isrc == NULL) {
2569 PORT_ONLY_ALLOCATE(AF_INET6, struct sockaddr_in6,
2570 SADB_X_EXT_ADDRESS_INNER_SRC, isrc, 0);
2572 #undef PORT_ONLY_ALLOCATE
2575 * Okay, so now I have all of the potential extensions!
2576 * Allocate a single contiguous buffer. Keep in mind that it'll
2577 * be enough because the key itself will be yanked.
2580 if (src == NULL && dst != NULL) {
2582 * Set explicit unspecified source address.
2584 size_t lenbytes = SADB_64TO8(dst->sadb_address_len);
2586 unspec_src = B_TRUE;
2587 totallen += lenbytes;
2588 src = malloc(lenbytes);
2589 if (src == NULL)
2590 Bail("malloc(implicit src)");
2591 /* Confusing, but we're copying from DST to SRC. :) */
2592 bcopy(dst, src, lenbytes);
2593 src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
2594 sin6 = (struct sockaddr_in6 *)(src + 1);
2595 bzero(sin6, sizeof (*sin6));
2596 sin6->sin6_family = AF_INET6;
2599 msg.sadb_msg_len = SADB_8TO64(totallen);
2601 buffer = malloc(totallen);
2602 nexthdr = buffer;
2603 bcopy(&msg, nexthdr, sizeof (msg));
2604 nexthdr += SADB_8TO64(sizeof (msg));
2605 if (assoc != NULL) {
2606 if (assoc->sadb_sa_spi == 0) {
2607 ERROR1(ep, ebuf, gettext(
2608 "The SPI value is missing for "
2609 "the association you wish to %s.\n"), thiscmd);
2611 if (assoc->sadb_sa_auth == 0 && assoc->sadb_sa_encrypt == 0 &&
2612 cmd == CMD_ADD) {
2613 free(assoc);
2614 FATAL(ep, ebuf, gettext(
2615 "Select at least one algorithm "
2616 "for this add.\n"));
2619 /* Hack to let user specify NULL ESP implicitly. */
2620 if (msg.sadb_msg_satype == SADB_SATYPE_ESP &&
2621 assoc->sadb_sa_encrypt == 0)
2622 assoc->sadb_sa_encrypt = SADB_EALG_NULL;
2624 /* 0 is an actual value. Print a warning if it was entered. */
2625 if (assoc->sadb_sa_state == 0) {
2626 if (readstate) {
2627 ERROR(ep, ebuf, gettext(
2628 "WARNING: Cannot set LARVAL SA state.\n"));
2630 assoc->sadb_sa_state = SADB_SASTATE_MATURE;
2633 if (use_natt) {
2634 if (natt_remote != NULL)
2635 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_NATT_REM;
2636 if (natt_local != NULL)
2637 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_NATT_LOC;
2640 if (alloc_inner) {
2642 * For now, assume RFC 3884's dream of transport-mode
2643 * SAs with inner IP address selectors will not
2644 * happen.
2646 assoc->sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL;
2647 if (proto != 0 && proto != IPPROTO_ENCAP &&
2648 proto != IPPROTO_IPV6) {
2649 ERROR1(ep, ebuf, gettext(
2650 "WARNING: Protocol type %d not "
2651 "for use with Tunnel-Mode SA.\n"), proto);
2652 /* Continue and let PF_KEY scream... */
2656 bcopy(assoc, nexthdr, SADB_64TO8(assoc->sadb_sa_len));
2657 nexthdr += assoc->sadb_sa_len;
2658 /* Save the SPI for the case of an error. */
2659 spi = assoc->sadb_sa_spi;
2660 free(assoc);
2661 } else {
2662 if (spi == 0)
2663 ERROR1(ep, ebuf, gettext(
2664 "Need to define SPI for %s.\n"), thiscmd);
2665 ERROR1(ep, ebuf, gettext(
2666 "Need SA parameters for %s.\n"), thiscmd);
2669 if (sadb_pair != NULL) {
2670 if (sadb_pair->sadb_x_pair_spi == 0) {
2671 ERROR1(ep, ebuf, gettext(
2672 "The SPI value is missing for the "
2673 "association you wish to %s.\n"), thiscmd);
2675 bcopy(sadb_pair, nexthdr,
2676 SADB_64TO8(sadb_pair->sadb_x_pair_len));
2677 nexthdr += sadb_pair->sadb_x_pair_len;
2678 free(sadb_pair);
2681 if (hard != NULL) {
2682 bcopy(hard, nexthdr, SADB_64TO8(hard->sadb_lifetime_len));
2683 nexthdr += hard->sadb_lifetime_len;
2684 free(hard);
2687 if (soft != NULL) {
2688 bcopy(soft, nexthdr, SADB_64TO8(soft->sadb_lifetime_len));
2689 nexthdr += soft->sadb_lifetime_len;
2690 free(soft);
2693 if (idle != NULL) {
2694 bcopy(idle, nexthdr, SADB_64TO8(idle->sadb_lifetime_len));
2695 nexthdr += idle->sadb_lifetime_len;
2696 free(idle);
2699 if (encrypt == NULL && auth == NULL && cmd == CMD_ADD) {
2700 ERROR(ep, ebuf, gettext(
2701 "Must have at least one key for an add.\n"));
2704 if (encrypt != NULL) {
2705 bcopy(encrypt, nexthdr, SADB_64TO8(encrypt->sadb_key_len));
2706 nexthdr += encrypt->sadb_key_len;
2707 bzero(encrypt, SADB_64TO8(encrypt->sadb_key_len));
2708 free(encrypt);
2711 if (auth != NULL) {
2712 bcopy(auth, nexthdr, SADB_64TO8(auth->sadb_key_len));
2713 nexthdr += auth->sadb_key_len;
2714 bzero(auth, SADB_64TO8(auth->sadb_key_len));
2715 free(auth);
2718 if (srcid != NULL) {
2719 bcopy(srcid, nexthdr, SADB_64TO8(srcid->sadb_ident_len));
2720 nexthdr += srcid->sadb_ident_len;
2721 free(srcid);
2724 if (dstid != NULL) {
2725 bcopy(dstid, nexthdr, SADB_64TO8(dstid->sadb_ident_len));
2726 nexthdr += dstid->sadb_ident_len;
2727 free(dstid);
2730 if (dst != NULL) {
2731 bcopy(dst, nexthdr, SADB_64TO8(dst->sadb_address_len));
2732 free(dst);
2733 dst = (struct sadb_address *)nexthdr;
2734 dst->sadb_address_proto = proto;
2735 ((struct sockaddr_in6 *)(dst + 1))->sin6_port = htons(dstport);
2736 nexthdr += dst->sadb_address_len;
2737 } else {
2738 FATAL1(ep, ebuf, gettext(
2739 "Need destination address for %s.\n"), thiscmd);
2742 if (use_natt) {
2743 if (natt_remote == NULL && natt_local == NULL) {
2744 ERROR(ep, ebuf, gettext(
2745 "Must specify NAT-T remote or local address "
2746 "for UDP encapsulation.\n"));
2749 if (natt_remote != NULL) {
2750 bcopy(natt_remote, nexthdr,
2751 SADB_64TO8(natt_remote->sadb_address_len));
2752 free(natt_remote);
2753 natt_remote = (struct sadb_address *)nexthdr;
2754 nexthdr += natt_remote->sadb_address_len;
2755 ((struct sockaddr_in6 *)(natt_remote + 1))->sin6_port =
2756 htons(natt_rport);
2759 if (natt_local != NULL) {
2760 bcopy(natt_local, nexthdr,
2761 SADB_64TO8(natt_local->sadb_address_len));
2762 free(natt_local);
2763 natt_local = (struct sadb_address *)nexthdr;
2764 nexthdr += natt_local->sadb_address_len;
2765 ((struct sockaddr_in6 *)(natt_local + 1))->sin6_port =
2766 htons(natt_lport);
2770 handle_errors(ep, ebuf, B_TRUE, B_FALSE);
2773 * PF_KEY requires a source address extension, even if the source
2774 * address itself is unspecified. (See "Set explicit unspecified..."
2775 * code fragment above. Destination reality check was above.)
2777 bcopy(src, nexthdr, SADB_64TO8(src->sadb_address_len));
2778 free(src);
2779 src = (struct sadb_address *)nexthdr;
2780 src->sadb_address_proto = proto;
2781 ((struct sockaddr_in6 *)(src + 1))->sin6_port = htons(srcport);
2782 nexthdr += src->sadb_address_len;
2784 if (isrc != NULL) {
2785 bcopy(isrc, nexthdr, SADB_64TO8(isrc->sadb_address_len));
2786 free(isrc);
2787 isrc = (struct sadb_address *)nexthdr;
2788 isrc->sadb_address_proto = iproto;
2789 ((struct sockaddr_in6 *)(isrc + 1))->sin6_port =
2790 htons(isrcport);
2791 nexthdr += isrc->sadb_address_len;
2794 if (idst != NULL) {
2795 bcopy(idst, nexthdr, SADB_64TO8(idst->sadb_address_len));
2796 free(idst);
2797 idst = (struct sadb_address *)nexthdr;
2798 idst->sadb_address_proto = iproto;
2799 ((struct sockaddr_in6 *)(idst + 1))->sin6_port =
2800 htons(idstport);
2801 nexthdr += idst->sadb_address_len;
2804 if (replay_ctr != NULL) {
2805 bcopy(replay_ctr, nexthdr,
2806 SADB_64TO8(replay_ctr->sadb_x_rc_len));
2807 nexthdr += replay_ctr->sadb_x_rc_len;
2808 free(replay_ctr);
2811 if (cflag) {
2813 * Assume the checked cmd would have worked if it was actually
2814 * used. doaddresses() will increment lines_added if it
2815 * succeeds.
2817 lines_added++;
2818 } else {
2819 doaddresses(sadb_msg_type, satype,
2820 cmd, srchp, dsthp, src, dst, unspec_src, buffer, totallen,
2821 spi, ebuf);
2824 if (isrchp != NULL && isrchp != &dummy.he)
2825 freehostent(isrchp);
2826 if (idsthp != NULL && idsthp != &dummy.he)
2827 freehostent(idsthp);
2828 if (srchp != NULL && srchp != &dummy.he)
2829 freehostent(srchp);
2830 if (dsthp != NULL && dsthp != &dummy.he)
2831 freehostent(dsthp);
2832 if (natt_lhp != NULL && natt_lhp != &dummy.he)
2833 freehostent(natt_lhp);
2834 if (natt_rhp != NULL && natt_rhp != &dummy.he)
2835 freehostent(natt_rhp);
2836 free(ebuf);
2837 free(buffer);
2841 * DELETE and GET are similar, in that they only need the extensions
2842 * required to _find_ an SA, and then either delete it or obtain its
2843 * information.
2845 static void
2846 dodelget(int cmd, int satype, char *argv[], char *ebuf)
2848 struct sadb_msg *msg = (struct sadb_msg *)get_buffer;
2849 uint64_t *nextext;
2850 struct sadb_sa *assoc = NULL;
2851 struct sadb_address *src = NULL, *dst = NULL;
2852 int next, token, sa_len;
2853 char *thiscmd;
2854 uint32_t spi;
2855 uint8_t sadb_msg_type;
2856 struct hostent *srchp = NULL, *dsthp = NULL;
2857 struct sockaddr_in6 *sin6;
2858 boolean_t unspec_src = B_TRUE;
2859 uint16_t srcport = 0, dstport = 0;
2860 uint8_t proto = 0;
2861 char *ep = NULL;
2862 uint32_t sa_flags = 0;
2864 /* Set the first extension header to right past the base message. */
2865 nextext = (uint64_t *)(msg + 1);
2866 bzero(nextext, sizeof (get_buffer) - sizeof (*msg));
2868 switch (cmd) {
2869 case CMD_GET:
2870 thiscmd = "get";
2871 sadb_msg_type = SADB_GET;
2872 break;
2873 case CMD_DELETE:
2874 thiscmd = "delete";
2875 sadb_msg_type = SADB_DELETE;
2876 break;
2877 case CMD_DELETE_PAIR:
2878 thiscmd = "delete-pair";
2879 sadb_msg_type = SADB_X_DELPAIR;
2880 break;
2883 msg_init(msg, sadb_msg_type, (uint8_t)satype);
2885 #define ALLOC_ADDR_EXT(ext, exttype) \
2886 (ext) = (struct sadb_address *)nextext; \
2887 nextext = (uint64_t *)((ext) + 1); \
2888 nextext += SADB_8TO64(roundup(sa_len, 8)); \
2889 (ext)->sadb_address_exttype = exttype; \
2890 (ext)->sadb_address_len = nextext - ((uint64_t *)ext);
2892 /* Assume last element in argv is set to NULL. */
2893 do {
2894 token = parseextval(*argv, &next);
2895 argv++;
2896 switch (token) {
2897 case TOK_EOF:
2898 /* Do nothing, I'm done. */
2899 break;
2900 case TOK_UNKNOWN:
2901 ERROR1(ep, ebuf, gettext(
2902 "Unknown extension field \"%s\"\n"), *(argv - 1));
2903 break;
2904 case TOK_SPI:
2905 if (assoc != NULL) {
2906 ERROR(ep, ebuf, gettext(
2907 "Can only specify single SPI value.\n"));
2908 break;
2910 assoc = (struct sadb_sa *)nextext;
2911 nextext = (uint64_t *)(assoc + 1);
2912 assoc->sadb_sa_len = SADB_8TO64(sizeof (*assoc));
2913 assoc->sadb_sa_exttype = SADB_EXT_SA;
2914 assoc->sadb_sa_spi = htonl((uint32_t)parsenum(*argv,
2915 B_TRUE, ebuf));
2916 spi = assoc->sadb_sa_spi;
2917 argv++;
2918 break;
2919 case TOK_SRCPORT:
2920 if (srcport != 0) {
2921 ERROR(ep, ebuf, gettext(
2922 "Can only specify single source port.\n"));
2923 break;
2925 srcport = parsenum(*argv, B_TRUE, ebuf);
2926 argv++;
2927 break;
2928 case TOK_DSTPORT:
2929 if (dstport != 0) {
2930 ERROR(ep, ebuf, gettext(
2931 "Can only "
2932 "specify single destination port.\n"));
2933 break;
2935 dstport = parsenum(*argv, B_TRUE, ebuf);
2936 argv++;
2937 break;
2938 case TOK_PROTO:
2939 if (proto != 0) {
2940 ERROR(ep, ebuf, gettext(
2941 "Can only specify single protocol.\n"));
2942 break;
2944 proto = parsenum(*argv, B_TRUE, ebuf);
2945 argv++;
2946 break;
2947 case TOK_SRCADDR:
2948 case TOK_SRCADDR6:
2949 if (src != NULL) {
2950 ERROR(ep, ebuf, gettext(
2951 "Can only specify single source addr.\n"));
2952 break;
2954 sa_len = parseaddr(*argv, &srchp,
2955 (token == TOK_SRCADDR6), ebuf);
2956 if (srchp == NULL) {
2957 ERROR1(ep, ebuf, gettext(
2958 "Unknown source address \"%s\"\n"), *argv);
2959 break;
2961 argv++;
2963 unspec_src = B_FALSE;
2965 ALLOC_ADDR_EXT(src, SADB_EXT_ADDRESS_SRC);
2967 if (srchp == &dummy.he) {
2969 * Single address with -n flag.
2971 sin6 = (struct sockaddr_in6 *)(src + 1);
2972 bzero(sin6, sizeof (*sin6));
2973 sin6->sin6_family = AF_INET6;
2974 bcopy(srchp->h_addr_list[0], &sin6->sin6_addr,
2975 sizeof (struct in6_addr));
2977 /* The rest is pre-bzeroed for us. */
2978 break;
2979 case TOK_DSTADDR:
2980 case TOK_DSTADDR6:
2981 if (dst != NULL) {
2982 ERROR(ep, ebuf, gettext(
2983 "Can only specify single destination "
2984 "address.\n"));
2985 break;
2987 sa_len = parseaddr(*argv, &dsthp,
2988 (token == TOK_SRCADDR6), ebuf);
2989 if (dsthp == NULL) {
2990 ERROR1(ep, ebuf, gettext(
2991 "Unknown destination address \"%s\"\n"),
2992 *argv);
2993 break;
2995 argv++;
2997 ALLOC_ADDR_EXT(dst, SADB_EXT_ADDRESS_DST);
2999 if (dsthp == &dummy.he) {
3001 * Single address with -n flag.
3003 sin6 = (struct sockaddr_in6 *)(dst + 1);
3004 bzero(sin6, sizeof (*sin6));
3005 sin6->sin6_family = AF_INET6;
3006 bcopy(dsthp->h_addr_list[0], &sin6->sin6_addr,
3007 sizeof (struct in6_addr));
3009 /* The rest is pre-bzeroed for us. */
3010 break;
3011 case TOK_FLAG_INBOUND:
3012 sa_flags |= SADB_X_SAFLAGS_INBOUND;
3013 break;
3014 case TOK_FLAG_OUTBOUND:
3015 sa_flags |= SADB_X_SAFLAGS_OUTBOUND;
3016 break;
3017 default:
3018 ERROR2(ep, ebuf, gettext(
3019 "Don't use extension %s for '%s' command.\n"),
3020 *(argv - 1), thiscmd);
3021 break;
3023 } while (token != TOK_EOF);
3025 handle_errors(ep, ebuf, B_TRUE, B_FALSE);
3027 if (assoc == NULL) {
3028 FATAL1(ep, ebuf, gettext(
3029 "Need SA parameters for %s.\n"), thiscmd);
3032 /* We can set the flags now with valid assoc in hand. */
3033 assoc->sadb_sa_flags |= sa_flags;
3035 if ((srcport != 0) && (src == NULL)) {
3036 ALLOC_ADDR_EXT(src, SADB_EXT_ADDRESS_SRC);
3037 sin6 = (struct sockaddr_in6 *)(src + 1);
3038 src->sadb_address_proto = proto;
3039 bzero(sin6, sizeof (*sin6));
3040 sin6->sin6_family = AF_INET6;
3041 sin6->sin6_port = htons(srcport);
3044 if ((dstport != 0) && (dst == NULL)) {
3045 ALLOC_ADDR_EXT(dst, SADB_EXT_ADDRESS_DST);
3046 sin6 = (struct sockaddr_in6 *)(dst + 1);
3047 src->sadb_address_proto = proto;
3048 bzero(sin6, sizeof (*sin6));
3049 sin6->sin6_family = AF_INET6;
3050 sin6->sin6_port = htons(dstport);
3053 /* So I have enough of the message to send it down! */
3054 msg->sadb_msg_len = nextext - get_buffer;
3056 if (cflag) {
3058 * Assume the checked cmd would have worked if it was actually
3059 * used. doaddresses() will increment lines_added if it
3060 * succeeds.
3062 lines_added++;
3063 } else {
3064 doaddresses(sadb_msg_type, satype,
3065 cmd, srchp, dsthp, src, dst, unspec_src, get_buffer,
3066 sizeof (get_buffer), spi, NULL);
3069 if (srchp != NULL && srchp != &dummy.he)
3070 freehostent(srchp);
3071 if (dsthp != NULL && dsthp != &dummy.he)
3072 freehostent(dsthp);
3076 * "ipseckey monitor" should exit very gracefully if ^C is tapped provided
3077 * it is not running in interactive mode.
3079 static void
3080 monitor_catch(int signal)
3082 if (!interactive)
3083 errx(signal, gettext("Bailing on signal %d."), signal);
3087 * Loop forever, listening on PF_KEY messages.
3089 static void
3090 domonitor(boolean_t passive)
3092 struct sadb_msg *samsg;
3093 struct sigaction newsig, oldsig;
3094 int rc;
3096 /* Catch ^C. */
3097 newsig.sa_handler = monitor_catch;
3098 newsig.sa_flags = 0;
3099 (void) sigemptyset(&newsig.sa_mask);
3100 (void) sigaddset(&newsig.sa_mask, SIGINT);
3101 (void) sigaction(SIGINT, &newsig, &oldsig);
3103 samsg = (struct sadb_msg *)get_buffer;
3104 if (!passive) {
3105 (void) printf(gettext("Actively"));
3106 msg_init(samsg, SADB_X_PROMISC, 1); /* Turn ON promisc. */
3107 rc = key_write(keysock, samsg, sizeof (*samsg));
3108 if (rc == -1)
3109 Bail("write (SADB_X_PROMISC)");
3110 } else {
3111 (void) printf(gettext("Passively"));
3113 (void) printf(gettext(" monitoring the PF_KEY socket.\n"));
3115 for (; ; ) {
3117 * I assume that read() is non-blocking, and will never
3118 * return 0.
3120 rc = read(keysock, samsg, sizeof (get_buffer));
3121 if (rc == -1) {
3122 if (errno == EINTR && interactive)
3123 goto out;
3124 else
3125 Bail("read (in domonitor)");
3127 (void) printf(gettext("Read %d bytes.\n"), rc);
3129 * Q: Should I use the same method of printing as GET does?
3130 * A: For now, yes.
3132 print_samsg(stdout, get_buffer, B_TRUE, vflag, nflag);
3133 (void) putchar('\n');
3136 out:
3137 if (interactive)
3138 /* restore SIGINT behavior */
3139 (void) sigaction(SIGINT, &oldsig, NULL);
3143 * Either mask or unmask all relevant signals.
3145 static void
3146 mask_signals(boolean_t unmask)
3148 sigset_t set;
3149 static sigset_t oset;
3151 if (unmask) {
3152 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
3153 } else {
3154 (void) sigfillset(&set);
3155 (void) sigprocmask(SIG_SETMASK, &set, &oset);
3160 * Assorted functions to print help text.
3162 #define puts_tr(s) (void) puts(gettext(s))
3164 static void
3165 doattrhelp()
3167 int i;
3169 puts_tr("\nSA attributes:");
3171 for (i = 0; tokens[i].string != NULL; i++) {
3172 if (i%3 == 0)
3173 (void) printf("\n");
3174 (void) printf(" %-15.15s", tokens[i].string);
3176 (void) printf("\n");
3179 static void
3180 dohelpcmd(char *cmds)
3182 int cmd;
3184 if (strcmp(cmds, "attr") == 0) {
3185 doattrhelp();
3186 return;
3189 cmd = parsecmd(cmds);
3190 switch (cmd) {
3191 case CMD_UPDATE:
3192 puts_tr("update - Update an existing SA");
3193 break;
3194 case CMD_UPDATE_PAIR:
3195 puts_tr("update-pair - Update an existing pair of SA's");
3196 break;
3197 case CMD_ADD:
3198 puts_tr("add - Add a new security association (SA)");
3199 break;
3200 case CMD_DELETE:
3201 puts_tr("delete - Delete an SA");
3202 break;
3203 case CMD_DELETE_PAIR:
3204 puts_tr("delete-pair - Delete a pair of SA's");
3205 break;
3206 case CMD_GET:
3207 puts_tr("get - Display an SA");
3208 break;
3209 case CMD_FLUSH:
3210 puts_tr("flush - Delete all SAs");
3211 puts_tr("");
3212 puts_tr("Optional arguments:");
3213 puts_tr("all delete all SAs");
3214 puts_tr("esp delete just ESP SAs");
3215 puts_tr("ah delete just AH SAs");
3216 puts_tr("<number> delete just SAs with type given by number");
3217 puts_tr("");
3218 break;
3219 case CMD_DUMP:
3220 puts_tr("dump - Display all SAs");
3221 puts_tr("");
3222 puts_tr("Optional arguments:");
3223 puts_tr("all display all SAs");
3224 puts_tr("esp display just ESP SAs");
3225 puts_tr("ah display just AH SAs");
3226 puts_tr("<number> display just SAs with type "
3227 "given by number");
3228 puts_tr("");
3229 break;
3230 case CMD_MONITOR:
3231 puts_tr("monitor - Monitor all PF_KEY reply messages.");
3232 break;
3233 case CMD_PMONITOR:
3234 puts_tr(
3235 "pmonitor, passive_monitor - Monitor PF_KEY messages that");
3236 puts_tr(
3237 " reply to all PF_KEY sockets.");
3238 break;
3240 case CMD_QUIT:
3241 puts_tr("quit, exit - Exit the program");
3242 break;
3243 case CMD_SAVE:
3244 puts_tr("save - Saves all SAs to a file");
3245 break;
3246 case CMD_HELP:
3247 puts_tr("help - Display list of commands");
3248 puts_tr("help <cmd> - Display help for command");
3249 puts_tr("help attr - Display possible SA attributes");
3250 break;
3251 default:
3252 (void) printf(gettext("%s: Unknown command\n"), cmds);
3253 break;
3258 static void
3259 dohelp(char *cmds)
3261 if (cmds != NULL) {
3262 dohelpcmd(cmds);
3263 return;
3265 puts_tr("Commands");
3266 puts_tr("--------");
3267 puts_tr("?, help - Display this list");
3268 puts_tr("help <cmd> - Display help for command");
3269 puts_tr("help attr - Display possible SA attributes");
3270 puts_tr("quit, exit - Exit the program");
3271 puts_tr("monitor - Monitor all PF_KEY reply messages.");
3272 puts_tr("pmonitor, passive_monitor - Monitor PF_KEY messages that");
3273 puts_tr(" reply to all PF_KEY sockets.");
3274 puts_tr("");
3275 puts_tr("The following commands are of the form:");
3276 puts_tr(" <command> {SA type} {attribute value}*");
3277 puts_tr("");
3278 puts_tr("add (interactive only) - Add a new security association (SA)");
3279 puts_tr("update (interactive only) - Update an existing SA");
3280 puts_tr("update-pair (interactive only) - Update an existing SA pair");
3281 puts_tr("delete - Delete an SA");
3282 puts_tr("delete-pair - Delete an SA pair");
3283 puts_tr("get - Display an SA");
3284 puts_tr("flush - Delete all SAs");
3285 puts_tr("dump - Display all SAs");
3286 puts_tr("save - Saves all SAs to a file");
3290 * "Parse" a command line from argv.
3292 static void
3293 parseit(int argc, char *argv[], char *ebuf, boolean_t read_cmdfile)
3295 int cmd, satype;
3296 char *ep = NULL;
3298 if (argc == 0)
3299 return;
3300 cmd = parsecmd(*argv++);
3303 * Some commands loop forever and should only be run from the command
3304 * line, they should never be run from a command file as this may
3305 * be used at boot time.
3307 switch (cmd) {
3308 case CMD_HELP:
3309 if (read_cmdfile)
3310 ERROR(ep, ebuf, gettext("Help not appropriate in "
3311 "config file."));
3312 else
3313 dohelp(*argv);
3314 return;
3315 case CMD_MONITOR:
3316 if (read_cmdfile)
3317 ERROR(ep, ebuf, gettext("Monitor not appropriate in "
3318 "config file."));
3319 else {
3320 domonitor(B_FALSE);
3322 * Return from the function in interactive mode to
3323 * avoid error message in the next switch statement.
3324 * Also print newline to prevent prompt clobbering.
3325 * The same is done for CMD_PMONITOR.
3327 if (interactive) {
3328 (void) printf("\n");
3329 return;
3332 break;
3333 case CMD_PMONITOR:
3334 if (read_cmdfile)
3335 ERROR(ep, ebuf, gettext("Monitor not appropriate in "
3336 "config file."));
3337 else {
3338 domonitor(B_TRUE);
3339 if (interactive) {
3340 (void) printf("\n");
3341 return;
3344 break;
3345 case CMD_QUIT:
3346 EXIT_OK(NULL);
3349 handle_errors(ep, ebuf, B_FALSE, B_FALSE);
3351 satype = parsesatype(*argv, ebuf);
3353 if (satype != SADB_SATYPE_UNSPEC) {
3354 argv++;
3355 } else {
3357 * You must specify either "all" or a specific SA type
3358 * for the "save" command.
3360 if (cmd == CMD_SAVE)
3361 if (*argv == NULL) {
3362 FATAL(ep, ebuf, gettext(
3363 "Must specify a specific "
3364 "SA type for save.\n"));
3365 } else {
3366 argv++;
3370 switch (cmd) {
3371 case CMD_FLUSH:
3372 if (argc > 2) {
3373 ERROR(ep, ebuf, gettext("Too many arguments for "
3374 "flush command"));
3375 handle_errors(ep, ebuf,
3376 interactive ? B_TRUE : B_FALSE, B_FALSE);
3378 if (!cflag)
3379 doflush(satype);
3381 * If this was called because of an entry in a cmd file
3382 * then this action needs to be counted to prevent
3383 * do_interactive() treating this as an error.
3385 lines_added++;
3386 break;
3387 case CMD_ADD:
3388 case CMD_UPDATE:
3389 case CMD_UPDATE_PAIR:
3391 * NOTE: Shouldn't allow ADDs or UPDATEs with keying material
3392 * from the command line.
3394 if (!interactive) {
3395 errx(1, gettext(
3396 "can't do ADD or UPDATE from the command line.\n"));
3398 if (satype == SADB_SATYPE_UNSPEC) {
3399 FATAL(ep, ebuf, gettext(
3400 "Must specify a specific SA type."));
3401 /* NOTREACHED */
3403 /* Parse for extensions, including keying material. */
3404 doaddup(cmd, satype, argv, ebuf);
3405 break;
3406 case CMD_DELETE:
3407 case CMD_DELETE_PAIR:
3408 case CMD_GET:
3409 if (satype == SADB_SATYPE_UNSPEC) {
3410 FATAL(ep, ebuf, gettext(
3411 "Must specify a single SA type."));
3412 /* NOTREACHED */
3414 /* Parse for bare minimum to locate an SA. */
3415 dodelget(cmd, satype, argv, ebuf);
3416 break;
3417 case CMD_DUMP:
3418 if (read_cmdfile)
3419 ERROR(ep, ebuf, gettext("Dump not appropriate in "
3420 "config file."));
3421 else {
3422 if (argc > 2) {
3423 ERROR(ep, ebuf, gettext("Too many arguments "
3424 "for dump command"));
3425 handle_errors(ep, ebuf,
3426 interactive ? B_TRUE : B_FALSE, B_FALSE);
3428 dodump(satype, NULL);
3430 break;
3431 case CMD_SAVE:
3432 if (read_cmdfile) {
3433 ERROR(ep, ebuf, gettext("Save not appropriate in "
3434 "config file."));
3435 } else {
3436 mask_signals(B_FALSE); /* Mask signals */
3437 dodump(satype, opensavefile(argv[0]));
3438 mask_signals(B_TRUE); /* Unmask signals */
3440 break;
3441 default:
3442 warnx(gettext("Unknown command (%s).\n"),
3443 *(argv - ((satype == SADB_SATYPE_UNSPEC) ? 1 : 2)));
3444 usage();
3446 handle_errors(ep, ebuf, B_FALSE, B_FALSE);
3450 main(int argc, char *argv[])
3452 int ch;
3453 FILE *infile = stdin, *savefile;
3454 boolean_t dosave = B_FALSE, readfile = B_FALSE;
3455 char *configfile = NULL;
3456 struct stat sbuf;
3457 int bootflags;
3459 debugfile = stdout;
3461 (void) setlocale(LC_ALL, "");
3462 #if !defined(TEXT_DOMAIN)
3463 #define TEXT_DOMAIN "SYS_TEST"
3464 #endif
3465 (void) textdomain(TEXT_DOMAIN);
3468 * Check to see if the command is being run from smf(5).
3470 my_fmri = getenv("SMF_FMRI");
3472 openlog("ipseckey", LOG_CONS, LOG_AUTH);
3473 if (getuid() != 0) {
3474 errx(1, "Insufficient privileges to run ipseckey.");
3477 /* umask me to paranoid, I only want to create files read-only */
3478 (void) umask((mode_t)00377);
3480 while ((ch = getopt(argc, argv, "pnvf:s:c:")) != EOF)
3481 switch (ch) {
3482 case 'p':
3483 pflag = B_TRUE;
3484 break;
3485 case 'n':
3486 nflag = B_TRUE;
3487 break;
3488 case 'v':
3489 vflag = B_TRUE;
3490 break;
3491 case 'c':
3492 cflag = B_TRUE;
3493 /* FALLTHRU */
3494 case 'f':
3495 if (dosave)
3496 usage();
3499 * Use stat() to check and see if the user inadvertently
3500 * passed in a bad pathname, or the name of a directory.
3501 * We should also check to see if the filename is a
3502 * pipe. We use stat() here because fopen() will block
3503 * unless the other end of the pipe is open. This would
3504 * be undesirable, especially if this is called at boot
3505 * time. If we ever need to support reading from a pipe
3506 * or special file, this should be revisited.
3508 if (stat(optarg, &sbuf) == -1) {
3509 EXIT_BADCONFIG2("Invalid pathname: %s\n",
3510 optarg);
3512 if (!(sbuf.st_mode & S_IFREG)) {
3513 EXIT_BADCONFIG2("%s - Not a regular file\n",
3514 optarg);
3516 infile = fopen(optarg, "r");
3517 if (infile == NULL) {
3518 EXIT_BADCONFIG2("Unable to open configuration "
3519 "file: %s\n", optarg);
3522 * The input file contains keying information, because
3523 * this is sensative, we should only accept data from
3524 * this file if the file is root owned and only readable
3525 * by privileged users. If the command is being run by
3526 * the administrator, issue a warning, if this is run by
3527 * smf(5) (IE: boot time) and the permissions are too
3528 * open, we will fail, the SMF service will end up in
3529 * maintenace mode. The check is made with fstat() to
3530 * eliminate any possible TOT to TOU window.
3532 if (fstat(fileno(infile), &sbuf) == -1) {
3533 (void) fclose(infile);
3534 EXIT_BADCONFIG2("Unable to stat configuration "
3535 "file: %s\n", optarg);
3537 if (INSECURE_PERMS(sbuf)) {
3538 if (my_fmri != NULL) {
3539 (void) fclose(infile);
3540 EXIT_BADCONFIG2("Config file "
3541 "%s has insecure permissions.",
3542 optarg);
3543 } else {
3544 (void) fprintf(stderr, gettext(
3545 "Config file %s has insecure "
3546 "permissions, will be rejected in "
3547 "permanent config.\n"), optarg);
3550 configfile = strdup(optarg);
3551 readfile = B_TRUE;
3552 break;
3553 case 's':
3554 if (readfile)
3555 usage();
3556 dosave = B_TRUE;
3557 savefile = opensavefile(optarg);
3558 break;
3559 default:
3560 usage();
3563 argc -= optind;
3564 argv += optind;
3566 mypid = getpid();
3568 keysock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
3570 if (keysock == -1) {
3571 if (errno == EPERM) {
3572 EXIT_BADPERM("Insufficient privileges to open "
3573 "PF_KEY socket.\n");
3574 } else {
3575 /* some other reason */
3576 EXIT_FATAL("Opening PF_KEY socket");
3580 if (dosave) {
3581 mask_signals(B_FALSE); /* Mask signals */
3582 dodump(SADB_SATYPE_UNSPEC, savefile);
3583 mask_signals(B_TRUE); /* Unmask signals */
3584 EXIT_OK(NULL);
3588 * When run from smf(5) flush any existing SA's first
3589 * otherwise you will end up in maintenance mode.
3591 if ((my_fmri != NULL) && readfile) {
3592 (void) fprintf(stdout, gettext(
3593 "Flushing existing SA's before adding new SA's\n"));
3594 (void) fflush(stdout);
3595 doflush(SADB_SATYPE_UNSPEC);
3597 if (infile != stdin || argc == 0) {
3598 /* Go into interactive mode here. */
3599 do_interactive(infile, configfile, "ipseckey> ", my_fmri,
3600 parseit, no_match);
3602 parseit(argc, argv, NULL, B_FALSE);
3604 return (0);