1 /*
2 *
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <sys/sysconf.h>
35 #include <strings.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <net/pfkeyv2.h>
43 #include <net/pfpolicy.h>
44 #include <libintl.h>
45 #include <setjmp.h>
46 #include <libgen.h>
47 #include <libscf.h>
48
49 #include "ipsec_util.h"
50 #include "ikedoor.h"
51
52 /*
53 * This file contains support functions that are shared by the ipsec
54 * utilities and daemons including ipseckey(1m), ikeadm(1m) and in.iked(1m).
55 */
56
57
58 #define EFD(file) (((file) == stdout) ? stderr : (file))
59
60 /* Limits for interactive mode. */
61 #define MAX_LINE_LEN IBUF_SIZE
62 #define MAX_CMD_HIST 64000 /* in bytes */
63
64 /* Set standard default/initial values for globals... */
65 boolean_t pflag = B_FALSE; /* paranoid w.r.t. printing keying material */
66 boolean_t nflag = B_FALSE; /* avoid nameservice? */
67 boolean_t interactive = B_FALSE; /* util not running on cmdline */
68 boolean_t readfile = B_FALSE; /* cmds are being read from a file */
69 uint_t lineno = 0; /* track location if reading cmds from file */
70 uint_t lines_added = 0;
71 uint_t lines_parsed = 0;
72 jmp_buf env; /* for error recovery in interactive/readfile modes */
73 char *my_fmri = NULL;
74 FILE *debugfile = stderr;
75 static GetLine *gl = NULL; /* for interactive mode */
76
77 /*
78 * Print errno and exit if cmdline or readfile, reset state if interactive
79 * The error string *what should be dgettext()'d before calling bail().
80 */
81 void
bail(char * what)82 bail(char *what)
83 {
84 if (errno != 0)
85 warn(what);
86 else
87 warnx(dgettext(TEXT_DOMAIN, "Error: %s"), what);
88 if (readfile) {
89 return;
90 }
91 if (interactive && !readfile)
92 longjmp(env, 2);
93 EXIT_FATAL(NULL);
94 }
95
96 /*
97 * Print caller-supplied variable-arg error msg, then exit if cmdline or
98 * readfile, or reset state if interactive.
99 */
100 /*PRINTFLIKE1*/
101 void
bail_msg(char * fmt,...)102 bail_msg(char *fmt, ...)
103 {
104 va_list ap;
105 char msgbuf[BUFSIZ];
106
107 va_start(ap, fmt);
108 (void) vsnprintf(msgbuf, BUFSIZ, fmt, ap);
109 va_end(ap);
110 if (readfile)
111 warnx(dgettext(TEXT_DOMAIN,
112 "ERROR on line %u:\n%s\n"), lineno, msgbuf);
113 else
114 warnx(dgettext(TEXT_DOMAIN, "ERROR: %s\n"), msgbuf);
115
116 if (interactive && !readfile)
117 longjmp(env, 1);
118
119 EXIT_FATAL(NULL);
120 }
121
122 /*
123 * bytecnt2str() wrapper. Zeroes out the input buffer and if the number
124 * of bytes to be converted is more than 1K, it will produce readable string
125 * in parentheses, store it in the original buffer and return the pointer to it.
126 * Maximum length of the returned string is 14 characters (not including
127 * the terminating zero).
128 */
129 char *
bytecnt2out(uint64_t num,char * buf,size_t bufsiz,int flags)130 bytecnt2out(uint64_t num, char *buf, size_t bufsiz, int flags)
131 {
132 char *str;
133
134 (void) memset(buf, '\0', bufsiz);
135
136 if (num > 1024) {
137 /* Return empty string in case of out-of-memory. */
138 if ((str = malloc(bufsiz)) == NULL)
139 return (buf);
140
141 (void) bytecnt2str(num, str, bufsiz);
142 /* Detect overflow. */
143 if (strlen(str) == 0) {
144 free(str);
145 return (buf);
146 }
147
148 /* Emit nothing in case of overflow. */
149 if (snprintf(buf, bufsiz, "%s(%sB)%s",
150 flags & SPC_BEGIN ? " " : "", str,
151 flags & SPC_END ? " " : "") >= bufsiz)
152 (void) memset(buf, '\0', bufsiz);
153
154 free(str);
155 }
156
157 return (buf);
158 }
159
160 /*
161 * Convert 64-bit number to human readable string. Useful mainly for the
162 * byte lifetime counters. Returns pointer to the user supplied buffer.
163 * Able to convert up to Exabytes. Maximum length of the string produced
164 * is 9 characters (not counting the terminating zero).
165 */
166 char *
bytecnt2str(uint64_t num,char * buf,size_t buflen)167 bytecnt2str(uint64_t num, char *buf, size_t buflen)
168 {
169 uint64_t n = num;
170 char u;
171 int index = 0;
172
173 while (n >= 1024) {
174 n /= 1024;
175 index++;
176 }
177
178 /* The field has all units this function can represent. */
179 u = " KMGTPE"[index];
180
181 if (index == 0) {
182 /* Less than 1K */
183 if (snprintf(buf, buflen, "%llu ", num) >= buflen)
184 (void) memset(buf, '\0', buflen);
185 } else {
186 /* Otherwise display 2 precision digits. */
187 if (snprintf(buf, buflen, "%.2f %c",
188 (double)num / (1ULL << index * 10), u) >= buflen)
189 (void) memset(buf, '\0', buflen);
190 }
191
192 return (buf);
193 }
194
195 /*
196 * secs2str() wrapper. Zeroes out the input buffer and if the number of
197 * seconds to be converted is more than minute, it will produce readable
198 * string in parentheses, store it in the original buffer and return the
199 * pointer to it.
200 */
201 char *
secs2out(unsigned int secs,char * buf,int bufsiz,int flags)202 secs2out(unsigned int secs, char *buf, int bufsiz, int flags)
203 {
204 char *str;
205
206 (void) memset(buf, '\0', bufsiz);
207
208 if (secs > 60) {
209 /* Return empty string in case of out-of-memory. */
210 if ((str = malloc(bufsiz)) == NULL)
211 return (buf);
212
213 (void) secs2str(secs, str, bufsiz);
214 /* Detect overflow. */
215 if (strlen(str) == 0) {
216 free(str);
217 return (buf);
218 }
219
220 /* Emit nothing in case of overflow. */
221 if (snprintf(buf, bufsiz, "%s(%s)%s",
222 flags & SPC_BEGIN ? " " : "", str,
223 flags & SPC_END ? " " : "") >= bufsiz)
224 (void) memset(buf, '\0', bufsiz);
225
226 free(str);
227 }
228
229 return (buf);
230 }
231
232 /*
233 * Convert number of seconds to human readable string. Useful mainly for
234 * the lifetime counters. Returns pointer to the user supplied buffer.
235 * Able to convert up to days.
236 */
237 char *
secs2str(unsigned int secs,char * buf,int bufsiz)238 secs2str(unsigned int secs, char *buf, int bufsiz)
239 {
240 double val = secs;
241 char *unit = "second";
242
243 if (val >= 24*60*60) {
244 val /= 86400;
245 unit = "day";
246 } else if (val >= 60*60) {
247 val /= 60*60;
248 unit = "hour";
249 } else if (val >= 60) {
250 val /= 60;
251 unit = "minute";
252 }
253
254 /* Emit nothing in case of overflow. */
255 if (snprintf(buf, bufsiz, "%.2f %s%s", val, unit,
256 val >= 2 ? "s" : "") >= bufsiz)
257 (void) memset(buf, '\0', bufsiz);
258
259 return (buf);
260 }
261
262 /*
263 * dump_XXX functions produce ASCII output from various structures.
264 *
265 * Because certain errors need to do this to stderr, dump_XXX functions
266 * take a FILE pointer.
267 *
268 * If an error occured while writing to the specified file, these
269 * functions return -1, zero otherwise.
270 */
271
272 int
dump_sockaddr(struct sockaddr * sa,uint8_t prefixlen,boolean_t addr_only,FILE * where,boolean_t ignore_nss)273 dump_sockaddr(struct sockaddr *sa, uint8_t prefixlen, boolean_t addr_only,
274 FILE *where, boolean_t ignore_nss)
275 {
276 struct sockaddr_in *sin;
277 struct sockaddr_in6 *sin6;
278 char *printable_addr, *protocol;
279 uint8_t *addrptr;
280 /* Add 4 chars to hold '/nnn' for prefixes. */
281 char storage[INET6_ADDRSTRLEN + 4];
282 uint16_t port;
283 boolean_t unspec;
284 struct hostent *hp;
285 int getipnode_errno, addrlen;
286
287 switch (sa->sa_family) {
288 case AF_INET:
289 /* LINTED E_BAD_PTR_CAST_ALIGN */
290 sin = (struct sockaddr_in *)sa;
291 addrptr = (uint8_t *)&sin->sin_addr;
292 port = sin->sin_port;
293 protocol = "AF_INET";
294 unspec = (sin->sin_addr.s_addr == 0);
295 addrlen = sizeof (sin->sin_addr);
296 break;
297 case AF_INET6:
298 /* LINTED E_BAD_PTR_CAST_ALIGN */
299 sin6 = (struct sockaddr_in6 *)sa;
300 addrptr = (uint8_t *)&sin6->sin6_addr;
301 port = sin6->sin6_port;
302 protocol = "AF_INET6";
303 unspec = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr);
304 addrlen = sizeof (sin6->sin6_addr);
305 break;
306 default:
307 return (0);
308 }
309
310 if (inet_ntop(sa->sa_family, addrptr, storage, INET6_ADDRSTRLEN) ==
311 NULL) {
312 printable_addr = dgettext(TEXT_DOMAIN, "Invalid IP address.");
313 } else {
314 char prefix[5]; /* "/nnn" with terminator. */
315
316 (void) snprintf(prefix, sizeof (prefix), "/%d", prefixlen);
317 printable_addr = storage;
318 if (prefixlen != 0) {
319 (void) strlcat(printable_addr, prefix,
320 sizeof (storage));
321 }
322 }
323 if (addr_only) {
324 if (fprintf(where, "%s", printable_addr) < 0)
325 return (-1);
326 } else {
327 if (fprintf(where, dgettext(TEXT_DOMAIN,
328 "%s: port %d, %s"), protocol,
329 ntohs(port), printable_addr) < 0)
330 return (-1);
331 if (ignore_nss == B_FALSE) {
332 /*
333 * Do AF_independent reverse hostname lookup here.
334 */
335 if (unspec) {
336 if (fprintf(where,
337 dgettext(TEXT_DOMAIN,
338 " <unspecified>")) < 0)
339 return (-1);
340 } else {
341 hp = getipnodebyaddr((char *)addrptr, addrlen,
342 sa->sa_family, &getipnode_errno);
343 if (hp != NULL) {
344 if (fprintf(where,
345 " (%s)", hp->h_name) < 0)
346 return (-1);
347 freehostent(hp);
348 } else {
349 if (fprintf(where,
350 dgettext(TEXT_DOMAIN,
351 " <unknown>")) < 0)
352 return (-1);
353 }
354 }
355 }
356 if (fputs(".\n", where) == EOF)
357 return (-1);
358 }
359 return (0);
360 }
361
362 /*
363 * Dump a key, any salt and bitlen.
364 * The key is made up of a stream of bits. If the algorithm requires a salt
365 * value, this will also be part of the dumped key. The last "saltbits" of the
366 * key string, reading left to right will be the salt value. To make it easier
367 * to see which bits make up the key, the salt value is enclosed in []'s.
368 * This function can also be called when ipseckey(1m) -s is run, this "saves"
369 * the SAs, including the key to a file. When this is the case, the []'s are
370 * not printed.
371 *
372 * The implementation allows the kernel to be told about the length of the salt
373 * in whole bytes only. If this changes, this function will need to be updated.
374 */
375 int
dump_key(uint8_t * keyp,uint_t bitlen,uint_t saltbits,FILE * where,boolean_t separate_salt)376 dump_key(uint8_t *keyp, uint_t bitlen, uint_t saltbits, FILE *where,
377 boolean_t separate_salt)
378 {
379 int numbytes, saltbytes;
380
381 numbytes = SADB_1TO8(bitlen);
382 saltbytes = SADB_1TO8(saltbits);
383 numbytes += saltbytes;
384
385 /* The & 0x7 is to check for leftover bits. */
386 if ((bitlen & 0x7) != 0)
387 numbytes++;
388
389 while (numbytes-- != 0) {
390 if (pflag) {
391 /* Print no keys if paranoid */
392 if (fprintf(where, "XX") < 0)
393 return (-1);
394 } else {
395 if (fprintf(where, "%02x", *keyp++) < 0)
396 return (-1);
397 }
398 if (separate_salt && saltbytes != 0 &&
399 numbytes == saltbytes) {
400 if (fprintf(where, "[") < 0)
401 return (-1);
402 }
403 }
404
405 if (separate_salt && saltbits != 0) {
406 if (fprintf(where, "]/%u+%u", bitlen, saltbits) < 0)
407 return (-1);
408 } else {
409 if (fprintf(where, "/%u", bitlen + saltbits) < 0)
410 return (-1);
411 }
412
413 return (0);
414 }
415
416 /*
417 * Print an authentication or encryption algorithm
418 */
419 static int
dump_generic_alg(uint8_t alg_num,int proto_num,FILE * where)420 dump_generic_alg(uint8_t alg_num, int proto_num, FILE *where)
421 {
422 struct ipsecalgent *alg;
423
424 alg = getipsecalgbynum(alg_num, proto_num, NULL);
425 if (alg == NULL) {
426 if (fprintf(where, dgettext(TEXT_DOMAIN,
427 "<unknown %u>"), alg_num) < 0)
428 return (-1);
429 return (0);
430 }
431
432 /*
433 * Special-case <none> for backward output compat.
434 * Assume that SADB_AALG_NONE == SADB_EALG_NONE.
435 */
436 if (alg_num == SADB_AALG_NONE) {
437 if (fputs(dgettext(TEXT_DOMAIN,
438 "<none>"), where) == EOF)
439 return (-1);
440 } else {
441 if (fputs(alg->a_names[0], where) == EOF)
442 return (-1);
443 }
444
445 freeipsecalgent(alg);
446 return (0);
447 }
448
449 int
dump_aalg(uint8_t aalg,FILE * where)450 dump_aalg(uint8_t aalg, FILE *where)
451 {
452 return (dump_generic_alg(aalg, IPSEC_PROTO_AH, where));
453 }
454
455 int
dump_ealg(uint8_t ealg,FILE * where)456 dump_ealg(uint8_t ealg, FILE *where)
457 {
458 return (dump_generic_alg(ealg, IPSEC_PROTO_ESP, where));
459 }
460
461 /*
462 * Print an SADB_IDENTTYPE string
463 *
464 * Also return TRUE if the actual ident may be printed, FALSE if not.
465 *
466 * If rc is not NULL, set its value to -1 if an error occured while writing
467 * to the specified file, zero otherwise.
468 */
469 boolean_t
dump_sadb_idtype(uint8_t idtype,FILE * where,int * rc)470 dump_sadb_idtype(uint8_t idtype, FILE *where, int *rc)
471 {
472 boolean_t canprint = B_TRUE;
473 int rc_val = 0;
474
475 switch (idtype) {
476 case SADB_IDENTTYPE_PREFIX:
477 if (fputs(dgettext(TEXT_DOMAIN, "prefix"), where) == EOF)
478 rc_val = -1;
479 break;
480 case SADB_IDENTTYPE_FQDN:
481 if (fputs(dgettext(TEXT_DOMAIN, "FQDN"), where) == EOF)
482 rc_val = -1;
483 break;
484 case SADB_IDENTTYPE_USER_FQDN:
485 if (fputs(dgettext(TEXT_DOMAIN,
486 "user-FQDN (mbox)"), where) == EOF)
487 rc_val = -1;
488 break;
489 case SADB_X_IDENTTYPE_DN:
490 if (fputs(dgettext(TEXT_DOMAIN, "ASN.1 DER Distinguished Name"),
491 where) == EOF)
492 rc_val = -1;
493 canprint = B_FALSE;
494 break;
495 case SADB_X_IDENTTYPE_GN:
496 if (fputs(dgettext(TEXT_DOMAIN, "ASN.1 DER Generic Name"),
497 where) == EOF)
498 rc_val = -1;
499 canprint = B_FALSE;
500 break;
501 case SADB_X_IDENTTYPE_KEY_ID:
502 if (fputs(dgettext(TEXT_DOMAIN, "Generic key id"),
503 where) == EOF)
504 rc_val = -1;
505 break;
506 case SADB_X_IDENTTYPE_ADDR_RANGE:
507 if (fputs(dgettext(TEXT_DOMAIN, "Address range"), where) == EOF)
508 rc_val = -1;
509 break;
510 default:
511 if (fprintf(where, dgettext(TEXT_DOMAIN,
512 "<unknown %u>"), idtype) < 0)
513 rc_val = -1;
514 break;
515 }
516
517 if (rc != NULL)
518 *rc = rc_val;
519
520 return (canprint);
521 }
522
523 /*
524 * Slice an argv/argc vector from an interactive line or a read-file line.
525 */
526 static int
create_argv(char * ibuf,int * newargc,char *** thisargv)527 create_argv(char *ibuf, int *newargc, char ***thisargv)
528 {
529 unsigned int argvlen = START_ARG;
530 char **current;
531 boolean_t firstchar = B_TRUE;
532 boolean_t inquotes = B_FALSE;
533
534 *thisargv = malloc(sizeof (char *) * argvlen);
535 if ((*thisargv) == NULL)
536 return (MEMORY_ALLOCATION);
537 current = *thisargv;
538 *current = NULL;
539
540 for (; *ibuf != '\0'; ibuf++) {
541 if (isspace(*ibuf)) {
542 if (inquotes) {
543 continue;
544 }
545 if (*current != NULL) {
546 *ibuf = '\0';
547 current++;
548 if (*thisargv + argvlen == current) {
549 /* Regrow ***thisargv. */
550 if (argvlen == TOO_MANY_ARGS) {
551 free(*thisargv);
552 return (TOO_MANY_TOKENS);
553 }
554 /* Double the allocation. */
555 current = realloc(*thisargv,
556 sizeof (char *) * (argvlen << 1));
557 if (current == NULL) {
558 free(*thisargv);
559 return (MEMORY_ALLOCATION);
560 }
561 *thisargv = current;
562 current += argvlen;
563 argvlen <<= 1; /* Double the size. */
564 }
565 *current = NULL;
566 }
567 } else {
568 if (firstchar) {
569 firstchar = B_FALSE;
570 if (*ibuf == COMMENT_CHAR || *ibuf == '\n') {
571 free(*thisargv);
572 return (COMMENT_LINE);
573 }
574 }
575 if (*ibuf == QUOTE_CHAR) {
576 if (inquotes) {
577 inquotes = B_FALSE;
578 *ibuf = '\0';
579 } else {
580 inquotes = B_TRUE;
581 }
582 continue;
583 }
584 if (*current == NULL) {
585 *current = ibuf;
586 (*newargc)++;
587 }
588 }
589 }
590
591 /*
592 * Tricky corner case...
593 * I've parsed _exactly_ the amount of args as I have space. It
594 * won't return NULL-terminated, and bad things will happen to
595 * the caller.
596 */
597 if (argvlen == *newargc) {
598 current = realloc(*thisargv, sizeof (char *) * (argvlen + 1));
599 if (current == NULL) {
600 free(*thisargv);
601 return (MEMORY_ALLOCATION);
602 }
603 *thisargv = current;
604 current[argvlen] = NULL;
605 }
606
607 return (SUCCESS);
608 }
609
610 /*
611 * init interactive mode if needed and not yet initialized
612 */
613 static void
init_interactive(FILE * infile,CplMatchFn * match_fn)614 init_interactive(FILE *infile, CplMatchFn *match_fn)
615 {
616 if (infile == stdin) {
617 if (gl == NULL) {
618 if ((gl = new_GetLine(MAX_LINE_LEN,
619 MAX_CMD_HIST)) == NULL)
620 errx(1, dgettext(TEXT_DOMAIN,
621 "tecla initialization failed"));
622
623 if (gl_customize_completion(gl, NULL,
624 match_fn) != 0) {
625 (void) del_GetLine(gl);
626 errx(1, dgettext(TEXT_DOMAIN,
627 "tab completion failed to initialize"));
628 }
629
630 /*
631 * In interactive mode we only want to terminate
632 * when explicitly requested (e.g. by a command).
633 */
634 (void) sigset(SIGINT, SIG_IGN);
635 }
636 } else {
637 readfile = B_TRUE;
638 }
639 }
640
641 /*
642 * free tecla data structure
643 */
644 static void
fini_interactive(void)645 fini_interactive(void)
646 {
647 if (gl != NULL)
648 (void) del_GetLine(gl);
649 }
650
651 /*
652 * Get single input line, wrapping around interactive and non-interactive
653 * mode.
654 */
655 static char *
do_getstr(FILE * infile,char * prompt,char * ibuf,size_t ibuf_size)656 do_getstr(FILE *infile, char *prompt, char *ibuf, size_t ibuf_size)
657 {
658 char *line;
659
660 if (infile != stdin)
661 return (fgets(ibuf, ibuf_size, infile));
662
663 /*
664 * If the user hits ^C then we want to catch it and
665 * start over. If the user hits EOF then we want to
666 * bail out.
667 */
668 once_again:
669 line = gl_get_line(gl, prompt, NULL, -1);
670 if (gl_return_status(gl) == GLR_SIGNAL) {
671 gl_abandon_line(gl);
672 goto once_again;
673 } else if (gl_return_status(gl) == GLR_ERROR) {
674 gl_abandon_line(gl);
675 errx(1, dgettext(TEXT_DOMAIN, "Error reading terminal: %s\n"),
676 gl_error_message(gl, NULL, 0));
677 } else {
678 if (line != NULL) {
679 if (strlcpy(ibuf, line, ibuf_size) >= ibuf_size)
680 warnx(dgettext(TEXT_DOMAIN,
681 "Line too long (max=%d chars)"),
682 ibuf_size);
683 line = ibuf;
684 }
685 }
686
687 return (line);
688 }
689
690 /*
691 * Enter a mode where commands are read from a file. Treat stdin special.
692 */
693 void
do_interactive(FILE * infile,char * configfile,char * promptstring,char * my_fmri,parse_cmdln_fn parseit,CplMatchFn * match_fn)694 do_interactive(FILE *infile, char *configfile, char *promptstring,
695 char *my_fmri, parse_cmdln_fn parseit, CplMatchFn *match_fn)
696 {
697 char ibuf[IBUF_SIZE], holder[IBUF_SIZE];
698 char *hptr, **thisargv, *ebuf;
699 int thisargc;
700 boolean_t continue_in_progress = B_FALSE;
701 char *s;
702
703 (void) setjmp(env);
704
705 ebuf = NULL;
706 interactive = B_TRUE;
707 bzero(ibuf, IBUF_SIZE);
708
709 /* panics for us */
710 init_interactive(infile, match_fn);
711
712 while ((s = do_getstr(infile, promptstring, ibuf, IBUF_SIZE)) != NULL) {
713 if (readfile)
714 lineno++;
715 thisargc = 0;
716 thisargv = NULL;
717
718 /*
719 * Check byte IBUF_SIZE - 2, because byte IBUF_SIZE - 1 will
720 * be null-terminated because of fgets().
721 */
722 if (ibuf[IBUF_SIZE - 2] != '\0') {
723 if (infile == stdin) {
724 /* do_getstr() issued a warning already */
725 bzero(ibuf, IBUF_SIZE);
726 continue;
727 } else {
728 ipsecutil_exit(SERVICE_FATAL, my_fmri,
729 debugfile, dgettext(TEXT_DOMAIN,
730 "Line %d too big."), lineno);
731 }
732 }
733
734 if (!continue_in_progress) {
735 /* Use -2 because of \n from fgets. */
736 if (ibuf[strlen(ibuf) - 2] == CONT_CHAR) {
737 /*
738 * Can use strcpy here, I've checked the
739 * length already.
740 */
741 (void) strcpy(holder, ibuf);
742 hptr = &(holder[strlen(holder)]);
743
744 /* Remove the CONT_CHAR from the string. */
745 hptr[-2] = ' ';
746
747 continue_in_progress = B_TRUE;
748 bzero(ibuf, IBUF_SIZE);
749 continue;
750 }
751 } else {
752 /* Handle continuations... */
753 (void) strncpy(hptr, ibuf,
754 (size_t)(&(holder[IBUF_SIZE]) - hptr));
755 if (holder[IBUF_SIZE - 1] != '\0') {
756 ipsecutil_exit(SERVICE_FATAL, my_fmri,
757 debugfile, dgettext(TEXT_DOMAIN,
758 "Command buffer overrun."));
759 }
760 /* Use - 2 because of \n from fgets. */
761 if (hptr[strlen(hptr) - 2] == CONT_CHAR) {
762 bzero(ibuf, IBUF_SIZE);
763 hptr += strlen(hptr);
764
765 /* Remove the CONT_CHAR from the string. */
766 hptr[-2] = ' ';
767
768 continue;
769 } else {
770 continue_in_progress = B_FALSE;
771 /*
772 * I've already checked the length...
773 */
774 (void) strcpy(ibuf, holder);
775 }
776 }
777
778 /*
779 * Just in case the command fails keep a copy of the
780 * command buffer for diagnostic output.
781 */
782 if (readfile) {
783 /*
784 * The error buffer needs to be big enough to
785 * hold the longest command string, plus
786 * some extra text, see below.
787 */
788 ebuf = calloc((IBUF_SIZE * 2), sizeof (char));
789 if (ebuf == NULL) {
790 ipsecutil_exit(SERVICE_FATAL, my_fmri,
791 debugfile, dgettext(TEXT_DOMAIN,
792 "Memory allocation error."));
793 } else {
794 (void) snprintf(ebuf, (IBUF_SIZE * 2),
795 dgettext(TEXT_DOMAIN,
796 "Config file entry near line %u "
797 "caused error(s) or warnings:\n\n%s\n\n"),
798 lineno, ibuf);
799 }
800 }
801
802 switch (create_argv(ibuf, &thisargc, &thisargv)) {
803 case TOO_MANY_TOKENS:
804 ipsecutil_exit(SERVICE_BADCONF, my_fmri, debugfile,
805 dgettext(TEXT_DOMAIN, "Too many input tokens."));
806 break;
807 case MEMORY_ALLOCATION:
808 ipsecutil_exit(SERVICE_BADCONF, my_fmri, debugfile,
809 dgettext(TEXT_DOMAIN, "Memory allocation error."));
810 break;
811 case COMMENT_LINE:
812 /* Comment line. */
813 free(ebuf);
814 break;
815 default:
816 if (thisargc != 0) {
817 lines_parsed++;
818 /* ebuf consumed */
819 parseit(thisargc, thisargv, ebuf, readfile);
820 } else {
821 free(ebuf);
822 }
823 free(thisargv);
824 if (infile == stdin) {
825 (void) printf("%s", promptstring);
826 (void) fflush(stdout);
827 }
828 break;
829 }
830 bzero(ibuf, IBUF_SIZE);
831 }
832
833 /*
834 * The following code is ipseckey specific. This should never be
835 * used by ikeadm which also calls this function because ikeadm
836 * only runs interactively. If this ever changes this code block
837 * sould be revisited.
838 */
839 if (readfile) {
840 if (lines_parsed != 0 && lines_added == 0) {
841 ipsecutil_exit(SERVICE_BADCONF, my_fmri, debugfile,
842 dgettext(TEXT_DOMAIN, "Configuration file did not "
843 "contain any valid SAs"));
844 }
845
846 /*
847 * There were errors. Putting the service in maintenance mode.
848 * When svc.startd(1M) allows services to degrade themselves,
849 * this should be revisited.
850 *
851 * If this function was called from a program running as a
852 * smf_method(5), print a warning message. Don't spew out the
853 * errors as these will end up in the smf(5) log file which is
854 * publically readable, the errors may contain sensitive
855 * information.
856 */
857 if ((lines_added < lines_parsed) && (configfile != NULL)) {
858 if (my_fmri != NULL) {
859 ipsecutil_exit(SERVICE_BADCONF, my_fmri,
860 debugfile, dgettext(TEXT_DOMAIN,
861 "The configuration file contained %d "
862 "errors.\n"
863 "Manually check the configuration with:\n"
864 "ipseckey -c %s\n"
865 "Use svcadm(1M) to clear maintenance "
866 "condition when errors are resolved.\n"),
867 lines_parsed - lines_added, configfile);
868 } else {
869 EXIT_BADCONFIG(NULL);
870 }
871 } else {
872 if (my_fmri != NULL)
873 ipsecutil_exit(SERVICE_EXIT_OK, my_fmri,
874 debugfile, dgettext(TEXT_DOMAIN,
875 "%d actions successfully processed."),
876 lines_added);
877 }
878 } else {
879 /* no newline upon Ctrl-D */
880 if (s != NULL)
881 (void) putchar('\n');
882 (void) fflush(stdout);
883 }
884
885 fini_interactive();
886
887 EXIT_OK(NULL);
888 }
889
890 /*
891 * Functions to parse strings that represent a debug or privilege level.
892 * These functions are copied from main.c and door.c in usr.lib/in.iked/common.
893 * If this file evolves into a common library that may be used by in.iked
894 * as well as the usr.sbin utilities, those duplicate functions should be
895 * deleted.
896 *
897 * A privilege level may be represented by a simple keyword, corresponding
898 * to one of the possible levels. A debug level may be represented by a
899 * series of keywords, separated by '+' or '-', indicating categories to
900 * be added or removed from the set of categories in the debug level.
901 * For example, +all-op corresponds to level 0xfffffffb (all flags except
902 * for D_OP set); while p1+p2+pfkey corresponds to level 0x38. Note that
903 * the leading '+' is implicit; the first keyword in the list must be for
904 * a category that is to be added.
905 *
906 * These parsing functions make use of a local version of strtok, strtok_d,
907 * which includes an additional parameter, char *delim. This param is filled
908 * in with the character which ends the returned token. In other words,
909 * this version of strtok, in addition to returning the token, also returns
910 * the single character delimiter from the original string which marked the
911 * end of the token.
912 */
913 static char *
strtok_d(char * string,const char * sepset,char * delim)914 strtok_d(char *string, const char *sepset, char *delim)
915 {
916 static char *lasts;
917 char *q, *r;
918
919 /* first or subsequent call */
920 if (string == NULL)
921 string = lasts;
922
923 if (string == 0) /* return if no tokens remaining */
924 return (NULL);
925
926 q = string + strspn(string, sepset); /* skip leading separators */
927
928 if (*q == '\0') /* return if no tokens remaining */
929 return (NULL);
930
931 if ((r = strpbrk(q, sepset)) == NULL) { /* move past token */
932 lasts = 0; /* indicate that this is last token */
933 } else {
934 *delim = *r; /* save delimitor */
935 *r = '\0';
936 lasts = r + 1;
937 }
938 return (q);
939 }
940
941 static keywdtab_t privtab[] = {
942 { IKE_PRIV_MINIMUM, "base" },
943 { IKE_PRIV_MODKEYS, "modkeys" },
944 { IKE_PRIV_KEYMAT, "keymat" },
945 { IKE_PRIV_MINIMUM, "0" },
946 };
947
948 int
privstr2num(char * str)949 privstr2num(char *str)
950 {
951 keywdtab_t *pp;
952 char *endp;
953 int priv;
954
955 for (pp = privtab; pp < A_END(privtab); pp++) {
956 if (strcasecmp(str, pp->kw_str) == 0)
957 return (pp->kw_tag);
958 }
959
960 priv = strtol(str, &endp, 0);
961 if (*endp == '\0')
962 return (priv);
963
964 return (-1);
965 }
966
967 static keywdtab_t dbgtab[] = {
968 { D_CERT, "cert" },
969 { D_KEY, "key" },
970 { D_OP, "op" },
971 { D_P1, "p1" },
972 { D_P1, "phase1" },
973 { D_P2, "p2" },
974 { D_P2, "phase2" },
975 { D_PFKEY, "pfkey" },
976 { D_POL, "pol" },
977 { D_POL, "policy" },
978 { D_PROP, "prop" },
979 { D_DOOR, "door" },
980 { D_CONFIG, "config" },
981 { D_LABEL, "label" },
982 { D_ALL, "all" },
983 { 0, "0" },
984 };
985
986 int
dbgstr2num(char * str)987 dbgstr2num(char *str)
988 {
989 keywdtab_t *dp;
990
991 for (dp = dbgtab; dp < A_END(dbgtab); dp++) {
992 if (strcasecmp(str, dp->kw_str) == 0)
993 return (dp->kw_tag);
994 }
995 return (D_INVALID);
996 }
997
998 int
parsedbgopts(char * optarg)999 parsedbgopts(char *optarg)
1000 {
1001 char *argp, *endp, op, nextop;
1002 int mask = 0, new;
1003
1004 mask = strtol(optarg, &endp, 0);
1005 if (*endp == '\0')
1006 return (mask);
1007
1008 op = optarg[0];
1009 if (op != '-')
1010 op = '+';
1011 argp = strtok_d(optarg, "+-", &nextop);
1012 do {
1013 new = dbgstr2num(argp);
1014 if (new == D_INVALID) {
1015 /* we encountered an invalid keywd */
1016 return (new);
1017 }
1018 if (op == '+') {
1019 mask |= new;
1020 } else {
1021 mask &= ~new;
1022 }
1023 op = nextop;
1024 } while ((argp = strtok_d(NULL, "+-", &nextop)) != NULL);
1025
1026 return (mask);
1027 }
1028
1029
1030 /*
1031 * functions to manipulate the kmcookie-label mapping file
1032 */
1033
1034 /*
1035 * Open, lockf, fdopen the given file, returning a FILE * on success,
1036 * or NULL on failure.
1037 */
1038 FILE *
kmc_open_and_lock(char * name)1039 kmc_open_and_lock(char *name)
1040 {
1041 int fd, rtnerr;
1042 FILE *fp;
1043
1044 if ((fd = open(name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
1045 return (NULL);
1046 }
1047 if (lockf(fd, F_LOCK, 0) < 0) {
1048 return (NULL);
1049 }
1050 if ((fp = fdopen(fd, "a+")) == NULL) {
1051 return (NULL);
1052 }
1053 if (fseek(fp, 0, SEEK_SET) < 0) {
1054 /* save errno in case fclose changes it */
1055 rtnerr = errno;
1056 (void) fclose(fp);
1057 errno = rtnerr;
1058 return (NULL);
1059 }
1060 return (fp);
1061 }
1062
1063 /*
1064 * Extract an integer cookie and string label from a line from the
1065 * kmcookie-label file. Return -1 on failure, 0 on success.
1066 */
1067 int
kmc_parse_line(char * line,int * cookie,char ** label)1068 kmc_parse_line(char *line, int *cookie, char **label)
1069 {
1070 char *cookiestr;
1071
1072 *cookie = 0;
1073 *label = NULL;
1074
1075 cookiestr = strtok(line, " \t\n");
1076 if (cookiestr == NULL) {
1077 return (-1);
1078 }
1079
1080 /* Everything that follows, up to the newline, is the label. */
1081 *label = strtok(NULL, "\n");
1082 if (*label == NULL) {
1083 return (-1);
1084 }
1085
1086 *cookie = atoi(cookiestr);
1087 return (0);
1088 }
1089
1090 /*
1091 * Insert a mapping into the file (if it's not already there), given the
1092 * new label. Return the assigned cookie, or -1 on error.
1093 */
1094 int
kmc_insert_mapping(char * label)1095 kmc_insert_mapping(char *label)
1096 {
1097 FILE *map;
1098 char linebuf[IBUF_SIZE];
1099 char *cur_label;
1100 int max_cookie = 0, cur_cookie, rtn_cookie;
1101 int rtnerr = 0;
1102 boolean_t found = B_FALSE;
1103
1104 /* open and lock the file; will sleep until lock is available */
1105 if ((map = kmc_open_and_lock(KMCFILE)) == NULL) {
1106 /* kmc_open_and_lock() sets errno appropriately */
1107 return (-1);
1108 }
1109
1110 while (fgets(linebuf, sizeof (linebuf), map) != NULL) {
1111
1112 /* Skip blank lines, which often come near EOF. */
1113 if (strlen(linebuf) == 0)
1114 continue;
1115
1116 if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) {
1117 rtnerr = EINVAL;
1118 goto error;
1119 }
1120
1121 if (cur_cookie > max_cookie)
1122 max_cookie = cur_cookie;
1123
1124 if ((!found) && (strcmp(cur_label, label) == 0)) {
1125 found = B_TRUE;
1126 rtn_cookie = cur_cookie;
1127 }
1128 }
1129
1130 if (!found) {
1131 rtn_cookie = ++max_cookie;
1132 if ((fprintf(map, "%u\t%s\n", rtn_cookie, label) < 0) ||
1133 (fflush(map) < 0)) {
1134 rtnerr = errno;
1135 goto error;
1136 }
1137 }
1138 (void) fclose(map);
1139
1140 return (rtn_cookie);
1141
1142 error:
1143 (void) fclose(map);
1144 errno = rtnerr;
1145 return (-1);
1146 }
1147
1148 /*
1149 * Lookup the given cookie and return its corresponding label. Return
1150 * a pointer to the label on success, NULL on error (or if the label is
1151 * not found). Note that the returned label pointer points to a static
1152 * string, so the label will be overwritten by a subsequent call to the
1153 * function; the function is also not thread-safe as a result.
1154 */
1155 char *
kmc_lookup_by_cookie(int cookie)1156 kmc_lookup_by_cookie(int cookie)
1157 {
1158 FILE *map;
1159 static char linebuf[IBUF_SIZE];
1160 char *cur_label;
1161 int cur_cookie;
1162
1163 if ((map = kmc_open_and_lock(KMCFILE)) == NULL) {
1164 return (NULL);
1165 }
1166
1167 while (fgets(linebuf, sizeof (linebuf), map) != NULL) {
1168
1169 if (kmc_parse_line(linebuf, &cur_cookie, &cur_label) < 0) {
1170 (void) fclose(map);
1171 return (NULL);
1172 }
1173
1174 if (cookie == cur_cookie) {
1175 (void) fclose(map);
1176 return (cur_label);
1177 }
1178 }
1179 (void) fclose(map);
1180
1181 return (NULL);
1182 }
1183
1184 /*
1185 * Parse basic extension headers and return in the passed-in pointer vector.
1186 * Return values include:
1187 *
1188 * KGE_OK Everything's nice and parsed out.
1189 * If there are no extensions, place NULL in extv[0].
1190 * KGE_DUP There is a duplicate extension.
1191 * First instance in appropriate bin. First duplicate in
1192 * extv[0].
1193 * KGE_UNK Unknown extension type encountered. extv[0] contains
1194 * unknown header.
1195 * KGE_LEN Extension length error.
1196 * KGE_CHK High-level reality check failed on specific extension.
1197 *
1198 * My apologies for some of the pointer arithmetic in here. I'm thinking
1199 * like an assembly programmer, yet trying to make the compiler happy.
1200 */
1201 int
spdsock_get_ext(spd_ext_t * extv[],spd_msg_t * basehdr,uint_t msgsize,char * diag_buf,uint_t diag_buf_len)1202 spdsock_get_ext(spd_ext_t *extv[], spd_msg_t *basehdr, uint_t msgsize,
1203 char *diag_buf, uint_t diag_buf_len)
1204 {
1205 int i;
1206
1207 if (diag_buf != NULL)
1208 diag_buf[0] = '\0';
1209
1210 for (i = 1; i <= SPD_EXT_MAX; i++)
1211 extv[i] = NULL;
1212
1213 i = 0;
1214 /* Use extv[0] as the "current working pointer". */
1215
1216 extv[0] = (spd_ext_t *)(basehdr + 1);
1217 msgsize = SPD_64TO8(msgsize);
1218
1219 while ((char *)extv[0] < ((char *)basehdr + msgsize)) {
1220 /* Check for unknown headers. */
1221 i++;
1222 if (extv[0]->spd_ext_type == 0 ||
1223 extv[0]->spd_ext_type > SPD_EXT_MAX) {
1224 if (diag_buf != NULL) {
1225 (void) snprintf(diag_buf, diag_buf_len,
1226 "spdsock ext 0x%X unknown: 0x%X",
1227 i, extv[0]->spd_ext_type);
1228 }
1229 return (KGE_UNK);
1230 }
1231
1232 /*
1233 * Check length. Use uint64_t because extlen is in units
1234 * of 64-bit words. If length goes beyond the msgsize,
1235 * return an error. (Zero length also qualifies here.)
1236 */
1237 if (extv[0]->spd_ext_len == 0 ||
1238 (uint8_t *)((uint64_t *)extv[0] + extv[0]->spd_ext_len) >
1239 (uint8_t *)((uint8_t *)basehdr + msgsize))
1240 return (KGE_LEN);
1241
1242 /* Check for redundant headers. */
1243 if (extv[extv[0]->spd_ext_type] != NULL)
1244 return (KGE_DUP);
1245
1246 /* If I make it here, assign the appropriate bin. */
1247 extv[extv[0]->spd_ext_type] = extv[0];
1248
1249 /* Advance pointer (See above for uint64_t ptr reasoning.) */
1250 extv[0] = (spd_ext_t *)
1251 ((uint64_t *)extv[0] + extv[0]->spd_ext_len);
1252 }
1253
1254 /* Everything's cool. */
1255
1256 /*
1257 * If extv[0] == NULL, then there are no extension headers in this
1258 * message. Ensure that this is the case.
1259 */
1260 if (extv[0] == (spd_ext_t *)(basehdr + 1))
1261 extv[0] = NULL;
1262
1263 return (KGE_OK);
1264 }
1265
1266 const char *
spdsock_diag(int diagnostic)1267 spdsock_diag(int diagnostic)
1268 {
1269 switch (diagnostic) {
1270 case SPD_DIAGNOSTIC_NONE:
1271 return (dgettext(TEXT_DOMAIN, "no error"));
1272 case SPD_DIAGNOSTIC_UNKNOWN_EXT:
1273 return (dgettext(TEXT_DOMAIN, "unknown extension"));
1274 case SPD_DIAGNOSTIC_BAD_EXTLEN:
1275 return (dgettext(TEXT_DOMAIN, "bad extension length"));
1276 case SPD_DIAGNOSTIC_NO_RULE_EXT:
1277 return (dgettext(TEXT_DOMAIN, "no rule extension"));
1278 case SPD_DIAGNOSTIC_BAD_ADDR_LEN:
1279 return (dgettext(TEXT_DOMAIN, "bad address len"));
1280 case SPD_DIAGNOSTIC_MIXED_AF:
1281 return (dgettext(TEXT_DOMAIN, "mixed address family"));
1282 case SPD_DIAGNOSTIC_ADD_NO_MEM:
1283 return (dgettext(TEXT_DOMAIN, "add: no memory"));
1284 case SPD_DIAGNOSTIC_ADD_WRONG_ACT_COUNT:
1285 return (dgettext(TEXT_DOMAIN, "add: wrong action count"));
1286 case SPD_DIAGNOSTIC_ADD_BAD_TYPE:
1287 return (dgettext(TEXT_DOMAIN, "add: bad type"));
1288 case SPD_DIAGNOSTIC_ADD_BAD_FLAGS:
1289 return (dgettext(TEXT_DOMAIN, "add: bad flags"));
1290 case SPD_DIAGNOSTIC_ADD_INCON_FLAGS:
1291 return (dgettext(TEXT_DOMAIN, "add: inconsistent flags"));
1292 case SPD_DIAGNOSTIC_MALFORMED_LCLPORT:
1293 return (dgettext(TEXT_DOMAIN, "malformed local port"));
1294 case SPD_DIAGNOSTIC_DUPLICATE_LCLPORT:
1295 return (dgettext(TEXT_DOMAIN, "duplicate local port"));
1296 case SPD_DIAGNOSTIC_MALFORMED_REMPORT:
1297 return (dgettext(TEXT_DOMAIN, "malformed remote port"));
1298 case SPD_DIAGNOSTIC_DUPLICATE_REMPORT:
1299 return (dgettext(TEXT_DOMAIN, "duplicate remote port"));
1300 case SPD_DIAGNOSTIC_MALFORMED_PROTO:
1301 return (dgettext(TEXT_DOMAIN, "malformed proto"));
1302 case SPD_DIAGNOSTIC_DUPLICATE_PROTO:
1303 return (dgettext(TEXT_DOMAIN, "duplicate proto"));
1304 case SPD_DIAGNOSTIC_MALFORMED_LCLADDR:
1305 return (dgettext(TEXT_DOMAIN, "malformed local address"));
1306 case SPD_DIAGNOSTIC_DUPLICATE_LCLADDR:
1307 return (dgettext(TEXT_DOMAIN, "duplicate local address"));
1308 case SPD_DIAGNOSTIC_MALFORMED_REMADDR:
1309 return (dgettext(TEXT_DOMAIN, "malformed remote address"));
1310 case SPD_DIAGNOSTIC_DUPLICATE_REMADDR:
1311 return (dgettext(TEXT_DOMAIN, "duplicate remote address"));
1312 case SPD_DIAGNOSTIC_MALFORMED_ACTION:
1313 return (dgettext(TEXT_DOMAIN, "malformed action"));
1314 case SPD_DIAGNOSTIC_DUPLICATE_ACTION:
1315 return (dgettext(TEXT_DOMAIN, "duplicate action"));
1316 case SPD_DIAGNOSTIC_MALFORMED_RULE:
1317 return (dgettext(TEXT_DOMAIN, "malformed rule"));
1318 case SPD_DIAGNOSTIC_DUPLICATE_RULE:
1319 return (dgettext(TEXT_DOMAIN, "duplicate rule"));
1320 case SPD_DIAGNOSTIC_MALFORMED_RULESET:
1321 return (dgettext(TEXT_DOMAIN, "malformed ruleset"));
1322 case SPD_DIAGNOSTIC_DUPLICATE_RULESET:
1323 return (dgettext(TEXT_DOMAIN, "duplicate ruleset"));
1324 case SPD_DIAGNOSTIC_INVALID_RULE_INDEX:
1325 return (dgettext(TEXT_DOMAIN, "invalid rule index"));
1326 case SPD_DIAGNOSTIC_BAD_SPDID:
1327 return (dgettext(TEXT_DOMAIN, "bad spdid"));
1328 case SPD_DIAGNOSTIC_BAD_MSG_TYPE:
1329 return (dgettext(TEXT_DOMAIN, "bad message type"));
1330 case SPD_DIAGNOSTIC_UNSUPP_AH_ALG:
1331 return (dgettext(TEXT_DOMAIN, "unsupported AH algorithm"));
1332 case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_ALG:
1333 return (dgettext(TEXT_DOMAIN,
1334 "unsupported ESP encryption algorithm"));
1335 case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_ALG:
1336 return (dgettext(TEXT_DOMAIN,
1337 "unsupported ESP authentication algorithm"));
1338 case SPD_DIAGNOSTIC_UNSUPP_AH_KEYSIZE:
1339 return (dgettext(TEXT_DOMAIN, "unsupported AH key size"));
1340 case SPD_DIAGNOSTIC_UNSUPP_ESP_ENCR_KEYSIZE:
1341 return (dgettext(TEXT_DOMAIN,
1342 "unsupported ESP encryption key size"));
1343 case SPD_DIAGNOSTIC_UNSUPP_ESP_AUTH_KEYSIZE:
1344 return (dgettext(TEXT_DOMAIN,
1345 "unsupported ESP authentication key size"));
1346 case SPD_DIAGNOSTIC_NO_ACTION_EXT:
1347 return (dgettext(TEXT_DOMAIN, "No ACTION extension"));
1348 case SPD_DIAGNOSTIC_ALG_ID_RANGE:
1349 return (dgettext(TEXT_DOMAIN, "invalid algorithm identifer"));
1350 case SPD_DIAGNOSTIC_ALG_NUM_KEY_SIZES:
1351 return (dgettext(TEXT_DOMAIN,
1352 "number of key sizes inconsistent"));
1353 case SPD_DIAGNOSTIC_ALG_NUM_BLOCK_SIZES:
1354 return (dgettext(TEXT_DOMAIN,
1355 "number of block sizes inconsistent"));
1356 case SPD_DIAGNOSTIC_ALG_MECH_NAME_LEN:
1357 return (dgettext(TEXT_DOMAIN, "invalid mechanism name length"));
1358 case SPD_DIAGNOSTIC_NOT_GLOBAL_OP:
1359 return (dgettext(TEXT_DOMAIN,
1360 "operation not applicable to all policies"));
1361 case SPD_DIAGNOSTIC_NO_TUNNEL_SELECTORS:
1362 return (dgettext(TEXT_DOMAIN,
1363 "using selectors on a transport-mode tunnel"));
1364 default:
1365 return (dgettext(TEXT_DOMAIN, "unknown diagnostic"));
1366 }
1367 }
1368
1369 /*
1370 * PF_KEY Diagnostic table.
1371 *
1372 * PF_KEY NOTE: If you change pfkeyv2.h's SADB_X_DIAGNOSTIC_* space, this is
1373 * where you need to add new messages.
1374 */
1375
1376 const char *
keysock_diag(int diagnostic)1377 keysock_diag(int diagnostic)
1378 {
1379 switch (diagnostic) {
1380 case SADB_X_DIAGNOSTIC_NONE:
1381 return (dgettext(TEXT_DOMAIN, "No diagnostic"));
1382 case SADB_X_DIAGNOSTIC_UNKNOWN_MSG:
1383 return (dgettext(TEXT_DOMAIN, "Unknown message type"));
1384 case SADB_X_DIAGNOSTIC_UNKNOWN_EXT:
1385 return (dgettext(TEXT_DOMAIN, "Unknown extension type"));
1386 case SADB_X_DIAGNOSTIC_BAD_EXTLEN:
1387 return (dgettext(TEXT_DOMAIN, "Bad extension length"));
1388 case SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE:
1389 return (dgettext(TEXT_DOMAIN,
1390 "Unknown Security Association type"));
1391 case SADB_X_DIAGNOSTIC_SATYPE_NEEDED:
1392 return (dgettext(TEXT_DOMAIN,
1393 "Specific Security Association type needed"));
1394 case SADB_X_DIAGNOSTIC_NO_SADBS:
1395 return (dgettext(TEXT_DOMAIN,
1396 "No Security Association Databases present"));
1397 case SADB_X_DIAGNOSTIC_NO_EXT:
1398 return (dgettext(TEXT_DOMAIN,
1399 "No extensions needed for message"));
1400 case SADB_X_DIAGNOSTIC_BAD_SRC_AF:
1401 return (dgettext(TEXT_DOMAIN, "Bad source address family"));
1402 case SADB_X_DIAGNOSTIC_BAD_DST_AF:
1403 return (dgettext(TEXT_DOMAIN,
1404 "Bad destination address family"));
1405 case SADB_X_DIAGNOSTIC_BAD_PROXY_AF:
1406 return (dgettext(TEXT_DOMAIN,
1407 "Bad inner-source address family"));
1408 case SADB_X_DIAGNOSTIC_AF_MISMATCH:
1409 return (dgettext(TEXT_DOMAIN,
1410 "Source/destination address family mismatch"));
1411 case SADB_X_DIAGNOSTIC_BAD_SRC:
1412 return (dgettext(TEXT_DOMAIN, "Bad source address value"));
1413 case SADB_X_DIAGNOSTIC_BAD_DST:
1414 return (dgettext(TEXT_DOMAIN, "Bad destination address value"));
1415 case SADB_X_DIAGNOSTIC_ALLOC_HSERR:
1416 return (dgettext(TEXT_DOMAIN,
1417 "Soft allocations limit more than hard limit"));
1418 case SADB_X_DIAGNOSTIC_BYTES_HSERR:
1419 return (dgettext(TEXT_DOMAIN,
1420 "Soft bytes limit more than hard limit"));
1421 case SADB_X_DIAGNOSTIC_ADDTIME_HSERR:
1422 return (dgettext(TEXT_DOMAIN, "Soft add expiration time later "
1423 "than hard expiration time"));
1424 case SADB_X_DIAGNOSTIC_USETIME_HSERR:
1425 return (dgettext(TEXT_DOMAIN, "Soft use expiration time later "
1426 "than hard expiration time"));
1427 case SADB_X_DIAGNOSTIC_MISSING_SRC:
1428 return (dgettext(TEXT_DOMAIN, "Missing source address"));
1429 case SADB_X_DIAGNOSTIC_MISSING_DST:
1430 return (dgettext(TEXT_DOMAIN, "Missing destination address"));
1431 case SADB_X_DIAGNOSTIC_MISSING_SA:
1432 return (dgettext(TEXT_DOMAIN, "Missing SA extension"));
1433 case SADB_X_DIAGNOSTIC_MISSING_EKEY:
1434 return (dgettext(TEXT_DOMAIN, "Missing encryption key"));
1435 case SADB_X_DIAGNOSTIC_MISSING_AKEY:
1436 return (dgettext(TEXT_DOMAIN, "Missing authentication key"));
1437 case SADB_X_DIAGNOSTIC_MISSING_RANGE:
1438 return (dgettext(TEXT_DOMAIN, "Missing SPI range"));
1439 case SADB_X_DIAGNOSTIC_DUPLICATE_SRC:
1440 return (dgettext(TEXT_DOMAIN, "Duplicate source address"));
1441 case SADB_X_DIAGNOSTIC_DUPLICATE_DST:
1442 return (dgettext(TEXT_DOMAIN, "Duplicate destination address"));
1443 case SADB_X_DIAGNOSTIC_DUPLICATE_SA:
1444 return (dgettext(TEXT_DOMAIN, "Duplicate SA extension"));
1445 case SADB_X_DIAGNOSTIC_DUPLICATE_EKEY:
1446 return (dgettext(TEXT_DOMAIN, "Duplicate encryption key"));
1447 case SADB_X_DIAGNOSTIC_DUPLICATE_AKEY:
1448 return (dgettext(TEXT_DOMAIN, "Duplicate authentication key"));
1449 case SADB_X_DIAGNOSTIC_DUPLICATE_RANGE:
1450 return (dgettext(TEXT_DOMAIN, "Duplicate SPI range"));
1451 case SADB_X_DIAGNOSTIC_MALFORMED_SRC:
1452 return (dgettext(TEXT_DOMAIN, "Malformed source address"));
1453 case SADB_X_DIAGNOSTIC_MALFORMED_DST:
1454 return (dgettext(TEXT_DOMAIN, "Malformed destination address"));
1455 case SADB_X_DIAGNOSTIC_MALFORMED_SA:
1456 return (dgettext(TEXT_DOMAIN, "Malformed SA extension"));
1457 case SADB_X_DIAGNOSTIC_MALFORMED_EKEY:
1458 return (dgettext(TEXT_DOMAIN, "Malformed encryption key"));
1459 case SADB_X_DIAGNOSTIC_MALFORMED_AKEY:
1460 return (dgettext(TEXT_DOMAIN, "Malformed authentication key"));
1461 case SADB_X_DIAGNOSTIC_MALFORMED_RANGE:
1462 return (dgettext(TEXT_DOMAIN, "Malformed SPI range"));
1463 case SADB_X_DIAGNOSTIC_AKEY_PRESENT:
1464 return (dgettext(TEXT_DOMAIN, "Authentication key not needed"));
1465 case SADB_X_DIAGNOSTIC_EKEY_PRESENT:
1466 return (dgettext(TEXT_DOMAIN, "Encryption key not needed"));
1467 case SADB_X_DIAGNOSTIC_PROP_PRESENT:
1468 return (dgettext(TEXT_DOMAIN, "Proposal extension not needed"));
1469 case SADB_X_DIAGNOSTIC_SUPP_PRESENT:
1470 return (dgettext(TEXT_DOMAIN,
1471 "Supported algorithms extension not needed"));
1472 case SADB_X_DIAGNOSTIC_BAD_AALG:
1473 return (dgettext(TEXT_DOMAIN,
1474 "Unsupported authentication algorithm"));
1475 case SADB_X_DIAGNOSTIC_BAD_EALG:
1476 return (dgettext(TEXT_DOMAIN,
1477 "Unsupported encryption algorithm"));
1478 case SADB_X_DIAGNOSTIC_BAD_SAFLAGS:
1479 return (dgettext(TEXT_DOMAIN, "Invalid SA flags"));
1480 case SADB_X_DIAGNOSTIC_BAD_SASTATE:
1481 return (dgettext(TEXT_DOMAIN, "Invalid SA state"));
1482 case SADB_X_DIAGNOSTIC_BAD_AKEYBITS:
1483 return (dgettext(TEXT_DOMAIN,
1484 "Bad number of authentication bits"));
1485 case SADB_X_DIAGNOSTIC_BAD_EKEYBITS:
1486 return (dgettext(TEXT_DOMAIN,
1487 "Bad number of encryption bits"));
1488 case SADB_X_DIAGNOSTIC_ENCR_NOTSUPP:
1489 return (dgettext(TEXT_DOMAIN,
1490 "Encryption not supported for this SA type"));
1491 case SADB_X_DIAGNOSTIC_WEAK_EKEY:
1492 return (dgettext(TEXT_DOMAIN, "Weak encryption key"));
1493 case SADB_X_DIAGNOSTIC_WEAK_AKEY:
1494 return (dgettext(TEXT_DOMAIN, "Weak authentication key"));
1495 case SADB_X_DIAGNOSTIC_DUPLICATE_KMP:
1496 return (dgettext(TEXT_DOMAIN,
1497 "Duplicate key management protocol"));
1498 case SADB_X_DIAGNOSTIC_DUPLICATE_KMC:
1499 return (dgettext(TEXT_DOMAIN,
1500 "Duplicate key management cookie"));
1501 case SADB_X_DIAGNOSTIC_MISSING_NATT_LOC:
1502 return (dgettext(TEXT_DOMAIN, "Missing NAT-T local address"));
1503 case SADB_X_DIAGNOSTIC_MISSING_NATT_REM:
1504 return (dgettext(TEXT_DOMAIN, "Missing NAT-T remote address"));
1505 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_LOC:
1506 return (dgettext(TEXT_DOMAIN, "Duplicate NAT-T local address"));
1507 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_REM:
1508 return (dgettext(TEXT_DOMAIN,
1509 "Duplicate NAT-T remote address"));
1510 case SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC:
1511 return (dgettext(TEXT_DOMAIN, "Malformed NAT-T local address"));
1512 case SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM:
1513 return (dgettext(TEXT_DOMAIN,
1514 "Malformed NAT-T remote address"));
1515 case SADB_X_DIAGNOSTIC_DUPLICATE_NATT_PORTS:
1516 return (dgettext(TEXT_DOMAIN, "Duplicate NAT-T ports"));
1517 case SADB_X_DIAGNOSTIC_MISSING_INNER_SRC:
1518 return (dgettext(TEXT_DOMAIN, "Missing inner source address"));
1519 case SADB_X_DIAGNOSTIC_MISSING_INNER_DST:
1520 return (dgettext(TEXT_DOMAIN,
1521 "Missing inner destination address"));
1522 case SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC:
1523 return (dgettext(TEXT_DOMAIN,
1524 "Duplicate inner source address"));
1525 case SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST:
1526 return (dgettext(TEXT_DOMAIN,
1527 "Duplicate inner destination address"));
1528 case SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC:
1529 return (dgettext(TEXT_DOMAIN,
1530 "Malformed inner source address"));
1531 case SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST:
1532 return (dgettext(TEXT_DOMAIN,
1533 "Malformed inner destination address"));
1534 case SADB_X_DIAGNOSTIC_PREFIX_INNER_SRC:
1535 return (dgettext(TEXT_DOMAIN,
1536 "Invalid inner-source prefix length "));
1537 case SADB_X_DIAGNOSTIC_PREFIX_INNER_DST:
1538 return (dgettext(TEXT_DOMAIN,
1539 "Invalid inner-destination prefix length"));
1540 case SADB_X_DIAGNOSTIC_BAD_INNER_DST_AF:
1541 return (dgettext(TEXT_DOMAIN,
1542 "Bad inner-destination address family"));
1543 case SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH:
1544 return (dgettext(TEXT_DOMAIN,
1545 "Inner source/destination address family mismatch"));
1546 case SADB_X_DIAGNOSTIC_BAD_NATT_REM_AF:
1547 return (dgettext(TEXT_DOMAIN,
1548 "Bad NAT-T remote address family"));
1549 case SADB_X_DIAGNOSTIC_BAD_NATT_LOC_AF:
1550 return (dgettext(TEXT_DOMAIN,
1551 "Bad NAT-T local address family"));
1552 case SADB_X_DIAGNOSTIC_PROTO_MISMATCH:
1553 return (dgettext(TEXT_DOMAIN,
1554 "Source/desination protocol mismatch"));
1555 case SADB_X_DIAGNOSTIC_INNER_PROTO_MISMATCH:
1556 return (dgettext(TEXT_DOMAIN,
1557 "Inner source/desination protocol mismatch"));
1558 case SADB_X_DIAGNOSTIC_DUAL_PORT_SETS:
1559 return (dgettext(TEXT_DOMAIN,
1560 "Both inner ports and outer ports are set"));
1561 case SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE:
1562 return (dgettext(TEXT_DOMAIN,
1563 "Pairing failed, target SA unsuitable for pairing"));
1564 case SADB_X_DIAGNOSTIC_PAIR_ADD_MISMATCH:
1565 return (dgettext(TEXT_DOMAIN,
1566 "Source/destination address differs from pair SA"));
1567 case SADB_X_DIAGNOSTIC_PAIR_ALREADY:
1568 return (dgettext(TEXT_DOMAIN,
1569 "Already paired with another security association"));
1570 case SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND:
1571 return (dgettext(TEXT_DOMAIN,
1572 "Command failed, pair security association not found"));
1573 case SADB_X_DIAGNOSTIC_BAD_SA_DIRECTION:
1574 return (dgettext(TEXT_DOMAIN,
1575 "Inappropriate SA direction"));
1576 case SADB_X_DIAGNOSTIC_SA_NOTFOUND:
1577 return (dgettext(TEXT_DOMAIN,
1578 "Security association not found"));
1579 case SADB_X_DIAGNOSTIC_SA_EXPIRED:
1580 return (dgettext(TEXT_DOMAIN,
1581 "Security association is not valid"));
1582 case SADB_X_DIAGNOSTIC_BAD_CTX:
1583 return (dgettext(TEXT_DOMAIN,
1584 "Algorithm invalid or not supported by Crypto Framework"));
1585 case SADB_X_DIAGNOSTIC_INVALID_REPLAY:
1586 return (dgettext(TEXT_DOMAIN,
1587 "Invalid Replay counter"));
1588 case SADB_X_DIAGNOSTIC_MISSING_LIFETIME:
1589 return (dgettext(TEXT_DOMAIN,
1590 "Inappropriate lifetimes"));
1591 default:
1592 return (dgettext(TEXT_DOMAIN, "Unknown diagnostic code"));
1593 }
1594 }
1595
1596 /*
1597 * Convert an IPv6 mask to a prefix len. I assume all IPv6 masks are
1598 * contiguous, so I stop at the first zero bit!
1599 */
1600 int
in_masktoprefix(uint8_t * mask,boolean_t is_v4mapped)1601 in_masktoprefix(uint8_t *mask, boolean_t is_v4mapped)
1602 {
1603 int rc = 0;
1604 uint8_t last;
1605 int limit = IPV6_ABITS;
1606
1607 if (is_v4mapped) {
1608 mask += ((IPV6_ABITS - IP_ABITS)/8);
1609 limit = IP_ABITS;
1610 }
1611
1612 while (*mask == 0xff) {
1613 rc += 8;
1614 if (rc == limit)
1615 return (limit);
1616 mask++;
1617 }
1618
1619 last = *mask;
1620 while (last != 0) {
1621 rc++;
1622 last = (last << 1) & 0xff;
1623 }
1624
1625 return (rc);
1626 }
1627
1628 /*
1629 * Expand the diagnostic code into a message.
1630 */
1631 void
print_diagnostic(FILE * file,uint16_t diagnostic)1632 print_diagnostic(FILE *file, uint16_t diagnostic)
1633 {
1634 /* Use two spaces so above strings can fit on the line. */
1635 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1636 " Diagnostic code %u: %s.\n"),
1637 diagnostic, keysock_diag(diagnostic));
1638 }
1639
1640 /*
1641 * Prints the base PF_KEY message.
1642 */
1643 void
print_sadb_msg(FILE * file,struct sadb_msg * samsg,time_t wallclock,boolean_t vflag)1644 print_sadb_msg(FILE *file, struct sadb_msg *samsg, time_t wallclock,
1645 boolean_t vflag)
1646 {
1647 if (wallclock != 0)
1648 printsatime(file, wallclock, dgettext(TEXT_DOMAIN,
1649 "%sTimestamp: %s\n"), "", NULL,
1650 vflag);
1651
1652 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1653 "Base message (version %u) type "),
1654 samsg->sadb_msg_version);
1655 switch (samsg->sadb_msg_type) {
1656 case SADB_RESERVED:
1657 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1658 "RESERVED (warning: set to 0)"));
1659 break;
1660 case SADB_GETSPI:
1661 (void) fprintf(file, "GETSPI");
1662 break;
1663 case SADB_UPDATE:
1664 (void) fprintf(file, "UPDATE");
1665 break;
1666 case SADB_X_UPDATEPAIR:
1667 (void) fprintf(file, "UPDATE PAIR");
1668 break;
1669 case SADB_ADD:
1670 (void) fprintf(file, "ADD");
1671 break;
1672 case SADB_DELETE:
1673 (void) fprintf(file, "DELETE");
1674 break;
1675 case SADB_X_DELPAIR:
1676 (void) fprintf(file, "DELETE PAIR");
1677 break;
1678 case SADB_GET:
1679 (void) fprintf(file, "GET");
1680 break;
1681 case SADB_ACQUIRE:
1682 (void) fprintf(file, "ACQUIRE");
1683 break;
1684 case SADB_REGISTER:
1685 (void) fprintf(file, "REGISTER");
1686 break;
1687 case SADB_EXPIRE:
1688 (void) fprintf(file, "EXPIRE");
1689 break;
1690 case SADB_FLUSH:
1691 (void) fprintf(file, "FLUSH");
1692 break;
1693 case SADB_DUMP:
1694 (void) fprintf(file, "DUMP");
1695 break;
1696 case SADB_X_PROMISC:
1697 (void) fprintf(file, "X_PROMISC");
1698 break;
1699 case SADB_X_INVERSE_ACQUIRE:
1700 (void) fprintf(file, "X_INVERSE_ACQUIRE");
1701 break;
1702 default:
1703 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1704 "Unknown (%u)"), samsg->sadb_msg_type);
1705 break;
1706 }
1707 (void) fprintf(file, dgettext(TEXT_DOMAIN, ", SA type "));
1708
1709 switch (samsg->sadb_msg_satype) {
1710 case SADB_SATYPE_UNSPEC:
1711 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1712 "<unspecified/all>"));
1713 break;
1714 case SADB_SATYPE_AH:
1715 (void) fprintf(file, "AH");
1716 break;
1717 case SADB_SATYPE_ESP:
1718 (void) fprintf(file, "ESP");
1719 break;
1720 case SADB_SATYPE_RSVP:
1721 (void) fprintf(file, "RSVP");
1722 break;
1723 case SADB_SATYPE_OSPFV2:
1724 (void) fprintf(file, "OSPFv2");
1725 break;
1726 case SADB_SATYPE_RIPV2:
1727 (void) fprintf(file, "RIPv2");
1728 break;
1729 case SADB_SATYPE_MIP:
1730 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Mobile IP"));
1731 break;
1732 default:
1733 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1734 "<unknown %u>"), samsg->sadb_msg_satype);
1735 break;
1736 }
1737
1738 (void) fprintf(file, ".\n");
1739
1740 if (samsg->sadb_msg_errno != 0) {
1741 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1742 "Error %s from PF_KEY.\n"),
1743 strerror(samsg->sadb_msg_errno));
1744 print_diagnostic(file, samsg->sadb_x_msg_diagnostic);
1745 }
1746
1747 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1748 "Message length %u bytes, seq=%u, pid=%u.\n"),
1749 SADB_64TO8(samsg->sadb_msg_len), samsg->sadb_msg_seq,
1750 samsg->sadb_msg_pid);
1751 }
1752
1753 /*
1754 * Print the SA extension for PF_KEY.
1755 */
1756 void
print_sa(FILE * file,char * prefix,struct sadb_sa * assoc)1757 print_sa(FILE *file, char *prefix, struct sadb_sa *assoc)
1758 {
1759 if (assoc->sadb_sa_len != SADB_8TO64(sizeof (*assoc))) {
1760 warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
1761 "WARNING: SA info extension length (%u) is bad."),
1762 SADB_64TO8(assoc->sadb_sa_len));
1763 }
1764
1765 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1766 "%sSADB_ASSOC spi=0x%x, replay window size=%u, state="),
1767 prefix, ntohl(assoc->sadb_sa_spi), assoc->sadb_sa_replay);
1768 switch (assoc->sadb_sa_state) {
1769 case SADB_SASTATE_LARVAL:
1770 (void) fprintf(file, dgettext(TEXT_DOMAIN, "LARVAL"));
1771 break;
1772 case SADB_SASTATE_MATURE:
1773 (void) fprintf(file, dgettext(TEXT_DOMAIN, "MATURE"));
1774 break;
1775 case SADB_SASTATE_DYING:
1776 (void) fprintf(file, dgettext(TEXT_DOMAIN, "DYING"));
1777 break;
1778 case SADB_SASTATE_DEAD:
1779 (void) fprintf(file, dgettext(TEXT_DOMAIN, "DEAD"));
1780 break;
1781 case SADB_X_SASTATE_ACTIVE_ELSEWHERE:
1782 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1783 "ACTIVE_ELSEWHERE"));
1784 break;
1785 case SADB_X_SASTATE_IDLE:
1786 (void) fprintf(file, dgettext(TEXT_DOMAIN, "IDLE"));
1787 break;
1788 default:
1789 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1790 "<unknown %u>"), assoc->sadb_sa_state);
1791 }
1792
1793 if (assoc->sadb_sa_auth != SADB_AALG_NONE) {
1794 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1795 "\n%sAuthentication algorithm = "),
1796 prefix);
1797 (void) dump_aalg(assoc->sadb_sa_auth, file);
1798 }
1799
1800 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) {
1801 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1802 "\n%sEncryption algorithm = "), prefix);
1803 (void) dump_ealg(assoc->sadb_sa_encrypt, file);
1804 }
1805
1806 (void) fprintf(file, dgettext(TEXT_DOMAIN, "\n%sflags=0x%x < "), prefix,
1807 assoc->sadb_sa_flags);
1808 if (assoc->sadb_sa_flags & SADB_SAFLAGS_PFS)
1809 (void) fprintf(file, "PFS ");
1810 if (assoc->sadb_sa_flags & SADB_SAFLAGS_NOREPLAY)
1811 (void) fprintf(file, "NOREPLAY ");
1812
1813 /* BEGIN Solaris-specific flags. */
1814 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_USED)
1815 (void) fprintf(file, "X_USED ");
1816 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_PAIRED)
1817 (void) fprintf(file, "X_PAIRED ");
1818 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_OUTBOUND)
1819 (void) fprintf(file, "X_OUTBOUND ");
1820 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_INBOUND)
1821 (void) fprintf(file, "X_INBOUND ");
1822 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_UNIQUE)
1823 (void) fprintf(file, "X_UNIQUE ");
1824 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_AALG1)
1825 (void) fprintf(file, "X_AALG1 ");
1826 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_AALG2)
1827 (void) fprintf(file, "X_AALG2 ");
1828 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_EALG1)
1829 (void) fprintf(file, "X_EALG1 ");
1830 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_EALG2)
1831 (void) fprintf(file, "X_EALG2 ");
1832 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC)
1833 (void) fprintf(file, "X_NATT_LOC ");
1834 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM)
1835 (void) fprintf(file, "X_NATT_REM ");
1836 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL)
1837 (void) fprintf(file, "X_TUNNEL ");
1838 if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATTED)
1839 (void) fprintf(file, "X_NATTED ");
1840 /* END Solaris-specific flags. */
1841
1842 (void) fprintf(file, ">\n");
1843 }
1844
1845 void
printsatime(FILE * file,int64_t lt,const char * msg,const char * pfx,const char * pfx2,boolean_t vflag)1846 printsatime(FILE *file, int64_t lt, const char *msg, const char *pfx,
1847 const char *pfx2, boolean_t vflag)
1848 {
1849 char tbuf[TBUF_SIZE]; /* For strftime() call. */
1850 const char *tp = tbuf;
1851 time_t t = lt;
1852 struct tm res;
1853
1854 if (t != lt) {
1855 if (lt > 0)
1856 t = LONG_MAX;
1857 else
1858 t = LONG_MIN;
1859 }
1860
1861 if (strftime(tbuf, TBUF_SIZE, NULL, localtime_r(&t, &res)) == 0)
1862 tp = dgettext(TEXT_DOMAIN, "<time conversion failed>");
1863 (void) fprintf(file, msg, pfx, tp);
1864 if (vflag && (pfx2 != NULL))
1865 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1866 "%s\t(raw time value %" PRIu64 ")\n"), pfx2, lt);
1867 }
1868
1869 /*
1870 * Print the SA lifetime information. (An SADB_EXT_LIFETIME_* extension.)
1871 */
1872 void
print_lifetimes(FILE * file,time_t wallclock,struct sadb_lifetime * current,struct sadb_lifetime * hard,struct sadb_lifetime * soft,struct sadb_lifetime * idle,boolean_t vflag)1873 print_lifetimes(FILE *file, time_t wallclock, struct sadb_lifetime *current,
1874 struct sadb_lifetime *hard, struct sadb_lifetime *soft,
1875 struct sadb_lifetime *idle, boolean_t vflag)
1876 {
1877 int64_t scratch;
1878 char *soft_prefix = dgettext(TEXT_DOMAIN, "SLT: ");
1879 char *hard_prefix = dgettext(TEXT_DOMAIN, "HLT: ");
1880 char *current_prefix = dgettext(TEXT_DOMAIN, "CLT: ");
1881 char *idle_prefix = dgettext(TEXT_DOMAIN, "ILT: ");
1882 char byte_str[BYTE_STR_SIZE]; /* byte lifetime string representation */
1883 char secs_str[SECS_STR_SIZE]; /* buffer for seconds representation */
1884
1885 if (current != NULL &&
1886 current->sadb_lifetime_len != SADB_8TO64(sizeof (*current))) {
1887 warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
1888 "WARNING: CURRENT lifetime extension length (%u) is bad."),
1889 SADB_64TO8(current->sadb_lifetime_len));
1890 }
1891
1892 if (hard != NULL &&
1893 hard->sadb_lifetime_len != SADB_8TO64(sizeof (*hard))) {
1894 warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
1895 "WARNING: HARD lifetime extension length (%u) is bad."),
1896 SADB_64TO8(hard->sadb_lifetime_len));
1897 }
1898
1899 if (soft != NULL &&
1900 soft->sadb_lifetime_len != SADB_8TO64(sizeof (*soft))) {
1901 warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
1902 "WARNING: SOFT lifetime extension length (%u) is bad."),
1903 SADB_64TO8(soft->sadb_lifetime_len));
1904 }
1905
1906 if (idle != NULL &&
1907 idle->sadb_lifetime_len != SADB_8TO64(sizeof (*idle))) {
1908 warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
1909 "WARNING: IDLE lifetime extension length (%u) is bad."),
1910 SADB_64TO8(idle->sadb_lifetime_len));
1911 }
1912
1913 (void) fprintf(file, " LT: Lifetime information\n");
1914 if (current != NULL) {
1915 /* Express values as current values. */
1916 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1917 "%sCurrent lifetime information:\n"),
1918 current_prefix);
1919 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1920 "%s%" PRIu64 " bytes %sprotected, %u allocations "
1921 "used.\n"), current_prefix,
1922 current->sadb_lifetime_bytes,
1923 bytecnt2out(current->sadb_lifetime_bytes, byte_str,
1924 sizeof (byte_str), SPC_END),
1925 current->sadb_lifetime_allocations);
1926 printsatime(file, current->sadb_lifetime_addtime,
1927 dgettext(TEXT_DOMAIN, "%sSA added at time: %s\n"),
1928 current_prefix, current_prefix, vflag);
1929 if (current->sadb_lifetime_usetime != 0) {
1930 printsatime(file, current->sadb_lifetime_usetime,
1931 dgettext(TEXT_DOMAIN,
1932 "%sSA first used at time %s\n"),
1933 current_prefix, current_prefix, vflag);
1934 }
1935 printsatime(file, wallclock, dgettext(TEXT_DOMAIN,
1936 "%sTime now is %s\n"), current_prefix, current_prefix,
1937 vflag);
1938 }
1939
1940 if (soft != NULL) {
1941 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1942 "%sSoft lifetime information:\n"),
1943 soft_prefix);
1944 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1945 "%s%" PRIu64 " bytes %sof lifetime, %u allocations.\n"),
1946 soft_prefix,
1947 soft->sadb_lifetime_bytes,
1948 bytecnt2out(soft->sadb_lifetime_bytes, byte_str,
1949 sizeof (byte_str), SPC_END),
1950 soft->sadb_lifetime_allocations);
1951 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1952 "%s%" PRIu64 " seconds %sof post-add lifetime.\n"),
1953 soft_prefix, soft->sadb_lifetime_addtime,
1954 secs2out(soft->sadb_lifetime_addtime, secs_str,
1955 sizeof (secs_str), SPC_END));
1956 (void) fprintf(file, dgettext(TEXT_DOMAIN,
1957 "%s%" PRIu64 " seconds %sof post-use lifetime.\n"),
1958 soft_prefix, soft->sadb_lifetime_usetime,
1959 secs2out(soft->sadb_lifetime_usetime, secs_str,
1960 sizeof (secs_str), SPC_END));
1961 /* If possible, express values as time remaining. */
1962 if (current != NULL) {
1963 if (soft->sadb_lifetime_bytes != 0)
1964 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s"
1965 "%" PRIu64 " bytes %smore can be "
1966 "protected.\n"), soft_prefix,
1967 (soft->sadb_lifetime_bytes >
1968 current->sadb_lifetime_bytes) ?
1969 soft->sadb_lifetime_bytes -
1970 current->sadb_lifetime_bytes : 0,
1971 (soft->sadb_lifetime_bytes >
1972 current->sadb_lifetime_bytes) ?
1973 bytecnt2out(soft->sadb_lifetime_bytes -
1974 current->sadb_lifetime_bytes, byte_str,
1975 sizeof (byte_str), SPC_END) : "");
1976 if (soft->sadb_lifetime_addtime != 0 ||
1977 (soft->sadb_lifetime_usetime != 0 &&
1978 current->sadb_lifetime_usetime != 0)) {
1979 int64_t adddelta, usedelta;
1980
1981 if (soft->sadb_lifetime_addtime != 0) {
1982 adddelta =
1983 current->sadb_lifetime_addtime +
1984 soft->sadb_lifetime_addtime -
1985 wallclock;
1986 } else {
1987 adddelta = TIME_MAX;
1988 }
1989
1990 if (soft->sadb_lifetime_usetime != 0 &&
1991 current->sadb_lifetime_usetime != 0) {
1992 usedelta =
1993 current->sadb_lifetime_usetime +
1994 soft->sadb_lifetime_usetime -
1995 wallclock;
1996 } else {
1997 usedelta = TIME_MAX;
1998 }
1999 (void) fprintf(file, "%s", soft_prefix);
2000 scratch = MIN(adddelta, usedelta);
2001 if (scratch >= 0) {
2002 (void) fprintf(file,
2003 dgettext(TEXT_DOMAIN,
2004 "Soft expiration occurs in %"
2005 PRId64 " seconds%s\n"), scratch,
2006 secs2out(scratch, secs_str,
2007 sizeof (secs_str), SPC_BEGIN));
2008 } else {
2009 (void) fprintf(file,
2010 dgettext(TEXT_DOMAIN,
2011 "Soft expiration occurred\n"));
2012 }
2013 scratch += wallclock;
2014 printsatime(file, scratch, dgettext(TEXT_DOMAIN,
2015 "%sTime of expiration: %s.\n"),
2016 soft_prefix, soft_prefix, vflag);
2017 }
2018 }
2019 }
2020
2021 if (hard != NULL) {
2022 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2023 "%sHard lifetime information:\n"), hard_prefix);
2024 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2025 "%s%" PRIu64 " bytes %sof lifetime, %u allocations.\n"),
2026 hard_prefix,
2027 hard->sadb_lifetime_bytes,
2028 bytecnt2out(hard->sadb_lifetime_bytes, byte_str,
2029 sizeof (byte_str), SPC_END),
2030 hard->sadb_lifetime_allocations);
2031 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2032 "%s%" PRIu64 " seconds %sof post-add lifetime.\n"),
2033 hard_prefix, hard->sadb_lifetime_addtime,
2034 secs2out(hard->sadb_lifetime_addtime, secs_str,
2035 sizeof (secs_str), SPC_END));
2036 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2037 "%s%" PRIu64 " seconds %sof post-use lifetime.\n"),
2038 hard_prefix, hard->sadb_lifetime_usetime,
2039 secs2out(hard->sadb_lifetime_usetime, secs_str,
2040 sizeof (secs_str), SPC_END));
2041 /* If possible, express values as time remaining. */
2042 if (current != NULL) {
2043 if (hard->sadb_lifetime_bytes != 0)
2044 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s"
2045 "%" PRIu64 " bytes %smore can be "
2046 "protected.\n"), hard_prefix,
2047 (hard->sadb_lifetime_bytes >
2048 current->sadb_lifetime_bytes) ?
2049 hard->sadb_lifetime_bytes -
2050 current->sadb_lifetime_bytes : 0,
2051 (hard->sadb_lifetime_bytes >
2052 current->sadb_lifetime_bytes) ?
2053 bytecnt2out(hard->sadb_lifetime_bytes -
2054 current->sadb_lifetime_bytes, byte_str,
2055 sizeof (byte_str), SPC_END) : "");
2056 if (hard->sadb_lifetime_addtime != 0 ||
2057 (hard->sadb_lifetime_usetime != 0 &&
2058 current->sadb_lifetime_usetime != 0)) {
2059 int64_t adddelta, usedelta;
2060
2061 if (hard->sadb_lifetime_addtime != 0) {
2062 adddelta =
2063 current->sadb_lifetime_addtime +
2064 hard->sadb_lifetime_addtime -
2065 wallclock;
2066 } else {
2067 adddelta = TIME_MAX;
2068 }
2069
2070 if (hard->sadb_lifetime_usetime != 0 &&
2071 current->sadb_lifetime_usetime != 0) {
2072 usedelta =
2073 current->sadb_lifetime_usetime +
2074 hard->sadb_lifetime_usetime -
2075 wallclock;
2076 } else {
2077 usedelta = TIME_MAX;
2078 }
2079 (void) fprintf(file, "%s", hard_prefix);
2080 scratch = MIN(adddelta, usedelta);
2081 if (scratch >= 0) {
2082 (void) fprintf(file,
2083 dgettext(TEXT_DOMAIN,
2084 "Hard expiration occurs in %"
2085 PRId64 " seconds%s\n"), scratch,
2086 secs2out(scratch, secs_str,
2087 sizeof (secs_str), SPC_BEGIN));
2088 } else {
2089 (void) fprintf(file,
2090 dgettext(TEXT_DOMAIN,
2091 "Hard expiration occurred\n"));
2092 }
2093 scratch += wallclock;
2094 printsatime(file, scratch, dgettext(TEXT_DOMAIN,
2095 "%sTime of expiration: %s.\n"),
2096 hard_prefix, hard_prefix, vflag);
2097 }
2098 }
2099 }
2100 if (idle != NULL) {
2101 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2102 "%sIdle lifetime information:\n"), idle_prefix);
2103 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2104 "%s%" PRIu64 " seconds %sof post-add lifetime.\n"),
2105 idle_prefix, idle->sadb_lifetime_addtime,
2106 secs2out(idle->sadb_lifetime_addtime, secs_str,
2107 sizeof (secs_str), SPC_END));
2108 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2109 "%s%" PRIu64 " seconds %sof post-use lifetime.\n"),
2110 idle_prefix, idle->sadb_lifetime_usetime,
2111 secs2out(idle->sadb_lifetime_usetime, secs_str,
2112 sizeof (secs_str), SPC_END));
2113 }
2114 }
2115
2116 /*
2117 * Print an SADB_EXT_ADDRESS_* extension.
2118 */
2119 void
print_address(FILE * file,char * prefix,struct sadb_address * addr,boolean_t ignore_nss)2120 print_address(FILE *file, char *prefix, struct sadb_address *addr,
2121 boolean_t ignore_nss)
2122 {
2123 struct protoent *pe;
2124
2125 (void) fprintf(file, "%s", prefix);
2126 switch (addr->sadb_address_exttype) {
2127 case SADB_EXT_ADDRESS_SRC:
2128 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Source address "));
2129 break;
2130 case SADB_X_EXT_ADDRESS_INNER_SRC:
2131 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2132 "Inner source address "));
2133 break;
2134 case SADB_EXT_ADDRESS_DST:
2135 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2136 "Destination address "));
2137 break;
2138 case SADB_X_EXT_ADDRESS_INNER_DST:
2139 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2140 "Inner destination address "));
2141 break;
2142 case SADB_X_EXT_ADDRESS_NATT_LOC:
2143 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2144 "NAT-T local address "));
2145 break;
2146 case SADB_X_EXT_ADDRESS_NATT_REM:
2147 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2148 "NAT-T remote address "));
2149 break;
2150 }
2151
2152 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2153 "(proto=%d"), addr->sadb_address_proto);
2154 if (ignore_nss == B_FALSE) {
2155 if (addr->sadb_address_proto == 0) {
2156 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2157 "/<unspecified>"));
2158 } else if ((pe = getprotobynumber(addr->sadb_address_proto))
2159 != NULL) {
2160 (void) fprintf(file, "/%s", pe->p_name);
2161 } else {
2162 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2163 "/<unknown>"));
2164 }
2165 }
2166 (void) fprintf(file, dgettext(TEXT_DOMAIN, ")\n%s"), prefix);
2167 (void) dump_sockaddr((struct sockaddr *)(addr + 1),
2168 addr->sadb_address_prefixlen, B_FALSE, file, ignore_nss);
2169 }
2170
2171 /*
2172 * Print an SADB_EXT_KEY extension.
2173 */
2174 void
print_key(FILE * file,char * prefix,struct sadb_key * key)2175 print_key(FILE *file, char *prefix, struct sadb_key *key)
2176 {
2177 (void) fprintf(file, "%s", prefix);
2178
2179 switch (key->sadb_key_exttype) {
2180 case SADB_EXT_KEY_AUTH:
2181 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Authentication"));
2182 break;
2183 case SADB_EXT_KEY_ENCRYPT:
2184 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Encryption"));
2185 break;
2186 }
2187
2188 (void) fprintf(file, dgettext(TEXT_DOMAIN, " key.\n%s"), prefix);
2189 (void) dump_key((uint8_t *)(key + 1), key->sadb_key_bits,
2190 key->sadb_key_reserved, file, B_TRUE);
2191 (void) fprintf(file, "\n");
2192 }
2193
2194 /*
2195 * Print an SADB_EXT_IDENTITY_* extension.
2196 */
2197 void
print_ident(FILE * file,char * prefix,struct sadb_ident * id)2198 print_ident(FILE *file, char *prefix, struct sadb_ident *id)
2199 {
2200 boolean_t canprint = B_TRUE;
2201
2202 (void) fprintf(file, "%s", prefix);
2203 switch (id->sadb_ident_exttype) {
2204 case SADB_EXT_IDENTITY_SRC:
2205 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Source"));
2206 break;
2207 case SADB_EXT_IDENTITY_DST:
2208 (void) fprintf(file, dgettext(TEXT_DOMAIN, "Destination"));
2209 break;
2210 }
2211
2212 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2213 " identity, uid=%d, type "), id->sadb_ident_id);
2214 canprint = dump_sadb_idtype(id->sadb_ident_type, file, NULL);
2215 (void) fprintf(file, "\n%s", prefix);
2216 if (canprint) {
2217 (void) fprintf(file, "%s\n", (char *)(id + 1));
2218 } else {
2219 print_asn1_name(file, (const unsigned char *)(id + 1),
2220 SADB_64TO8(id->sadb_ident_len) - sizeof (sadb_ident_t));
2221 }
2222 }
2223
2224 /*
2225 * Convert sadb_sens extension into binary security label.
2226 */
2227
2228 #include <tsol/label.h>
2229 #include <sys/tsol/tndb.h>
2230 #include <sys/tsol/label_macro.h>
2231
2232 void
ipsec_convert_sens_to_bslabel(const struct sadb_sens * sens,bslabel_t * sl)2233 ipsec_convert_sens_to_bslabel(const struct sadb_sens *sens, bslabel_t *sl)
2234 {
2235 uint64_t *bitmap = (uint64_t *)(sens + 1);
2236 int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len);
2237
2238 bsllow(sl);
2239 LCLASS_SET((_bslabel_impl_t *)sl, sens->sadb_sens_sens_level);
2240 bcopy(bitmap, &((_bslabel_impl_t *)sl)->compartments,
2241 bitmap_len);
2242 }
2243
2244 void
ipsec_convert_bslabel_to_string(bslabel_t * sl,char ** plabel)2245 ipsec_convert_bslabel_to_string(bslabel_t *sl, char **plabel)
2246 {
2247 if (label_to_str(sl, plabel, M_LABEL, DEF_NAMES) != 0) {
2248 *plabel = strdup(dgettext(TEXT_DOMAIN,
2249 "** Label conversion failed **"));
2250 }
2251 }
2252
2253 void
ipsec_convert_bslabel_to_hex(bslabel_t * sl,char ** plabel)2254 ipsec_convert_bslabel_to_hex(bslabel_t *sl, char **plabel)
2255 {
2256 if (label_to_str(sl, plabel, M_INTERNAL, DEF_NAMES) != 0) {
2257 *plabel = strdup(dgettext(TEXT_DOMAIN,
2258 "** Label conversion failed **"));
2259 }
2260 }
2261
2262 int
ipsec_convert_sl_to_sens(int doi,bslabel_t * sl,sadb_sens_t * sens)2263 ipsec_convert_sl_to_sens(int doi, bslabel_t *sl, sadb_sens_t *sens)
2264 {
2265 uint8_t *bitmap;
2266 int sens_len = sizeof (sadb_sens_t) + _C_LEN * 4;
2267
2268
2269 if (sens == NULL)
2270 return (sens_len);
2271
2272
2273 (void) memset(sens, 0, sens_len);
2274
2275 sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
2276 sens->sadb_sens_len = SADB_8TO64(sens_len);
2277 sens->sadb_sens_dpd = doi;
2278
2279 sens->sadb_sens_sens_level = LCLASS(sl);
2280 sens->sadb_sens_integ_level = 0;
2281 sens->sadb_sens_sens_len = _C_LEN >> 1;
2282 sens->sadb_sens_integ_len = 0;
2283
2284 sens->sadb_x_sens_flags = 0;
2285
2286 bitmap = (uint8_t *)(sens + 1);
2287 bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4);
2288
2289 return (sens_len);
2290 }
2291
2292
2293 /*
2294 * Print an SADB_SENSITIVITY extension.
2295 */
2296 void
print_sens(FILE * file,char * prefix,const struct sadb_sens * sens,boolean_t ignore_nss)2297 print_sens(FILE *file, char *prefix, const struct sadb_sens *sens,
2298 boolean_t ignore_nss)
2299 {
2300 char *plabel;
2301 char *hlabel;
2302 uint64_t *bitmap = (uint64_t *)(sens + 1);
2303 bslabel_t sl;
2304 int i;
2305 int sens_len = sens->sadb_sens_sens_len;
2306 int integ_len = sens->sadb_sens_integ_len;
2307 boolean_t inner = (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY);
2308 const char *sensname = inner ?
2309 dgettext(TEXT_DOMAIN, "Plaintext Sensitivity") :
2310 dgettext(TEXT_DOMAIN, "Ciphertext Sensitivity");
2311
2312 ipsec_convert_sens_to_bslabel(sens, &sl);
2313
2314 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2315 "%s%s DPD %d, sens level=%d, integ level=%d, flags=%x\n"),
2316 prefix, sensname, sens->sadb_sens_dpd, sens->sadb_sens_sens_level,
2317 sens->sadb_sens_integ_level, sens->sadb_x_sens_flags);
2318
2319 ipsec_convert_bslabel_to_hex(&sl, &hlabel);
2320
2321 if (ignore_nss) {
2322 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2323 "%s %s Label: %s\n"), prefix, sensname, hlabel);
2324
2325 for (i = 0; i < sens_len; i++, bitmap++)
2326 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2327 "%s %s BM extended word %d 0x%" PRIx64 "\n"),
2328 prefix, sensname, i, *bitmap);
2329
2330 } else {
2331 ipsec_convert_bslabel_to_string(&sl, &plabel);
2332
2333 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2334 "%s %s Label: %s (%s)\n"),
2335 prefix, sensname, plabel, hlabel);
2336 free(plabel);
2337
2338 }
2339 free(hlabel);
2340
2341 bitmap = (uint64_t *)(sens + 1 + sens_len);
2342
2343 for (i = 0; i < integ_len; i++, bitmap++)
2344 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2345 "%s Integrity BM extended word %d 0x%" PRIx64 "\n"),
2346 prefix, i, *bitmap);
2347 }
2348
2349 /*
2350 * Print an SADB_EXT_PROPOSAL extension.
2351 */
2352 void
print_prop(FILE * file,char * prefix,struct sadb_prop * prop)2353 print_prop(FILE *file, char *prefix, struct sadb_prop *prop)
2354 {
2355 struct sadb_comb *combs;
2356 int i, numcombs;
2357
2358 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2359 "%sProposal, replay counter = %u.\n"), prefix,
2360 prop->sadb_prop_replay);
2361
2362 numcombs = prop->sadb_prop_len - SADB_8TO64(sizeof (*prop));
2363 numcombs /= SADB_8TO64(sizeof (*combs));
2364
2365 combs = (struct sadb_comb *)(prop + 1);
2366
2367 for (i = 0; i < numcombs; i++) {
2368 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2369 "%s Combination #%u "), prefix, i + 1);
2370 if (combs[i].sadb_comb_auth != SADB_AALG_NONE) {
2371 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2372 "Authentication = "));
2373 (void) dump_aalg(combs[i].sadb_comb_auth, file);
2374 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2375 " minbits=%u, maxbits=%u.\n%s "),
2376 combs[i].sadb_comb_auth_minbits,
2377 combs[i].sadb_comb_auth_maxbits, prefix);
2378 }
2379
2380 if (combs[i].sadb_comb_encrypt != SADB_EALG_NONE) {
2381 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2382 "Encryption = "));
2383 (void) dump_ealg(combs[i].sadb_comb_encrypt, file);
2384 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2385 " minbits=%u, maxbits=%u.\n%s "),
2386 combs[i].sadb_comb_encrypt_minbits,
2387 combs[i].sadb_comb_encrypt_maxbits, prefix);
2388 }
2389
2390 (void) fprintf(file, dgettext(TEXT_DOMAIN, "HARD: "));
2391 if (combs[i].sadb_comb_hard_allocations)
2392 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u "),
2393 combs[i].sadb_comb_hard_allocations);
2394 if (combs[i].sadb_comb_hard_bytes)
2395 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%"
2396 PRIu64 " "), combs[i].sadb_comb_hard_bytes);
2397 if (combs[i].sadb_comb_hard_addtime)
2398 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2399 "post-add secs=%" PRIu64 " "),
2400 combs[i].sadb_comb_hard_addtime);
2401 if (combs[i].sadb_comb_hard_usetime)
2402 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2403 "post-use secs=%" PRIu64 ""),
2404 combs[i].sadb_comb_hard_usetime);
2405
2406 (void) fprintf(file, dgettext(TEXT_DOMAIN, "\n%s SOFT: "),
2407 prefix);
2408 if (combs[i].sadb_comb_soft_allocations)
2409 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u "),
2410 combs[i].sadb_comb_soft_allocations);
2411 if (combs[i].sadb_comb_soft_bytes)
2412 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%"
2413 PRIu64 " "), combs[i].sadb_comb_soft_bytes);
2414 if (combs[i].sadb_comb_soft_addtime)
2415 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2416 "post-add secs=%" PRIu64 " "),
2417 combs[i].sadb_comb_soft_addtime);
2418 if (combs[i].sadb_comb_soft_usetime)
2419 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2420 "post-use secs=%" PRIu64 ""),
2421 combs[i].sadb_comb_soft_usetime);
2422 (void) fprintf(file, "\n");
2423 }
2424 }
2425
2426 /*
2427 * Print an extended proposal (SADB_X_EXT_EPROP).
2428 */
2429 void
print_eprop(FILE * file,char * prefix,struct sadb_prop * eprop)2430 print_eprop(FILE *file, char *prefix, struct sadb_prop *eprop)
2431 {
2432 uint64_t *sofar;
2433 struct sadb_x_ecomb *ecomb;
2434 struct sadb_x_algdesc *algdesc;
2435 int i, j;
2436
2437 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2438 "%sExtended Proposal, replay counter = %u, "), prefix,
2439 eprop->sadb_prop_replay);
2440 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2441 "number of combinations = %u.\n"), eprop->sadb_x_prop_numecombs);
2442
2443 sofar = (uint64_t *)(eprop + 1);
2444 ecomb = (struct sadb_x_ecomb *)sofar;
2445
2446 for (i = 0; i < eprop->sadb_x_prop_numecombs; ) {
2447 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2448 "%s Extended combination #%u:\n"), prefix, ++i);
2449
2450 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s HARD: "),
2451 prefix);
2452 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u, "),
2453 ecomb->sadb_x_ecomb_hard_allocations);
2454 (void) fprintf(file, dgettext(TEXT_DOMAIN, "bytes=%" PRIu64
2455 ", "), ecomb->sadb_x_ecomb_hard_bytes);
2456 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-add secs=%"
2457 PRIu64 ", "), ecomb->sadb_x_ecomb_hard_addtime);
2458 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-use secs=%"
2459 PRIu64 "\n"), ecomb->sadb_x_ecomb_hard_usetime);
2460
2461 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%s SOFT: "),
2462 prefix);
2463 (void) fprintf(file, dgettext(TEXT_DOMAIN, "alloc=%u, "),
2464 ecomb->sadb_x_ecomb_soft_allocations);
2465 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2466 "bytes=%" PRIu64 ", "), ecomb->sadb_x_ecomb_soft_bytes);
2467 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2468 "post-add secs=%" PRIu64 ", "),
2469 ecomb->sadb_x_ecomb_soft_addtime);
2470 (void) fprintf(file, dgettext(TEXT_DOMAIN, "post-use secs=%"
2471 PRIu64 "\n"), ecomb->sadb_x_ecomb_soft_usetime);
2472
2473 sofar = (uint64_t *)(ecomb + 1);
2474 algdesc = (struct sadb_x_algdesc *)sofar;
2475
2476 for (j = 0; j < ecomb->sadb_x_ecomb_numalgs; ) {
2477 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2478 "%s Alg #%u "), prefix, ++j);
2479 switch (algdesc->sadb_x_algdesc_satype) {
2480 case SADB_SATYPE_ESP:
2481 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2482 "for ESP "));
2483 break;
2484 case SADB_SATYPE_AH:
2485 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2486 "for AH "));
2487 break;
2488 default:
2489 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2490 "for satype=%d "),
2491 algdesc->sadb_x_algdesc_satype);
2492 }
2493 switch (algdesc->sadb_x_algdesc_algtype) {
2494 case SADB_X_ALGTYPE_CRYPT:
2495 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2496 "Encryption = "));
2497 (void) dump_ealg(algdesc->sadb_x_algdesc_alg,
2498 file);
2499 break;
2500 case SADB_X_ALGTYPE_AUTH:
2501 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2502 "Authentication = "));
2503 (void) dump_aalg(algdesc->sadb_x_algdesc_alg,
2504 file);
2505 break;
2506 default:
2507 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2508 "algtype(%d) = alg(%d)"),
2509 algdesc->sadb_x_algdesc_algtype,
2510 algdesc->sadb_x_algdesc_alg);
2511 break;
2512 }
2513
2514 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2515 " minbits=%u, maxbits=%u, saltbits=%u\n"),
2516 algdesc->sadb_x_algdesc_minbits,
2517 algdesc->sadb_x_algdesc_maxbits,
2518 algdesc->sadb_x_algdesc_reserved);
2519
2520 sofar = (uint64_t *)(++algdesc);
2521 }
2522 ecomb = (struct sadb_x_ecomb *)sofar;
2523 }
2524 }
2525
2526 /*
2527 * Print an SADB_EXT_SUPPORTED extension.
2528 */
2529 void
print_supp(FILE * file,char * prefix,struct sadb_supported * supp)2530 print_supp(FILE *file, char *prefix, struct sadb_supported *supp)
2531 {
2532 struct sadb_alg *algs;
2533 int i, numalgs;
2534
2535 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%sSupported "), prefix);
2536 switch (supp->sadb_supported_exttype) {
2537 case SADB_EXT_SUPPORTED_AUTH:
2538 (void) fprintf(file, dgettext(TEXT_DOMAIN, "authentication"));
2539 break;
2540 case SADB_EXT_SUPPORTED_ENCRYPT:
2541 (void) fprintf(file, dgettext(TEXT_DOMAIN, "encryption"));
2542 break;
2543 }
2544 (void) fprintf(file, dgettext(TEXT_DOMAIN, " algorithms.\n"));
2545
2546 algs = (struct sadb_alg *)(supp + 1);
2547 numalgs = supp->sadb_supported_len - SADB_8TO64(sizeof (*supp));
2548 numalgs /= SADB_8TO64(sizeof (*algs));
2549 for (i = 0; i < numalgs; i++) {
2550 uint16_t exttype = supp->sadb_supported_exttype;
2551
2552 (void) fprintf(file, "%s", prefix);
2553 switch (exttype) {
2554 case SADB_EXT_SUPPORTED_AUTH:
2555 (void) dump_aalg(algs[i].sadb_alg_id, file);
2556 break;
2557 case SADB_EXT_SUPPORTED_ENCRYPT:
2558 (void) dump_ealg(algs[i].sadb_alg_id, file);
2559 break;
2560 }
2561 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2562 " minbits=%u, maxbits=%u, ivlen=%u, saltbits=%u"),
2563 algs[i].sadb_alg_minbits, algs[i].sadb_alg_maxbits,
2564 algs[i].sadb_alg_ivlen, algs[i].sadb_x_alg_saltbits);
2565 if (exttype == SADB_EXT_SUPPORTED_ENCRYPT)
2566 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2567 ", increment=%u"), algs[i].sadb_x_alg_increment);
2568 (void) fprintf(file, dgettext(TEXT_DOMAIN, ".\n"));
2569 }
2570 }
2571
2572 /*
2573 * Print an SADB_EXT_SPIRANGE extension.
2574 */
2575 void
print_spirange(FILE * file,char * prefix,struct sadb_spirange * range)2576 print_spirange(FILE *file, char *prefix, struct sadb_spirange *range)
2577 {
2578 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2579 "%sSPI Range, min=0x%x, max=0x%x\n"), prefix,
2580 htonl(range->sadb_spirange_min),
2581 htonl(range->sadb_spirange_max));
2582 }
2583
2584 /*
2585 * Print an SADB_X_EXT_KM_COOKIE extension.
2586 */
2587
2588 void
print_kmc(FILE * file,char * prefix,struct sadb_x_kmc * kmc)2589 print_kmc(FILE *file, char *prefix, struct sadb_x_kmc *kmc)
2590 {
2591 char *cookie_label;
2592
2593 if ((cookie_label = kmc_lookup_by_cookie(kmc->sadb_x_kmc_cookie)) ==
2594 NULL)
2595 cookie_label = dgettext(TEXT_DOMAIN, "<Label not found.>");
2596
2597 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2598 "%sProtocol %u, cookie=\"%s\" (%u)\n"), prefix,
2599 kmc->sadb_x_kmc_proto, cookie_label, kmc->sadb_x_kmc_cookie);
2600 }
2601
2602 /*
2603 * Print an SADB_X_EXT_REPLAY_CTR extension.
2604 */
2605
2606 void
print_replay(FILE * file,char * prefix,sadb_x_replay_ctr_t * repl)2607 print_replay(FILE *file, char *prefix, sadb_x_replay_ctr_t *repl)
2608 {
2609 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2610 "%sReplay Value "), prefix);
2611 if ((repl->sadb_x_rc_replay32 == 0) &&
2612 (repl->sadb_x_rc_replay64 == 0)) {
2613 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2614 "<Value not found.>"));
2615 }
2616 /*
2617 * We currently do not support a 64-bit replay value.
2618 * RFC 4301 will require one, however, and we have a field
2619 * in place when 4301 is built.
2620 */
2621 (void) fprintf(file, "% " PRIu64 "\n",
2622 ((repl->sadb_x_rc_replay32 == 0) ?
2623 repl->sadb_x_rc_replay64 : repl->sadb_x_rc_replay32));
2624 }
2625 /*
2626 * Print an SADB_X_EXT_PAIR extension.
2627 */
2628 static void
print_pair(FILE * file,char * prefix,struct sadb_x_pair * pair)2629 print_pair(FILE *file, char *prefix, struct sadb_x_pair *pair)
2630 {
2631 (void) fprintf(file, dgettext(TEXT_DOMAIN, "%sPaired with spi=0x%x\n"),
2632 prefix, ntohl(pair->sadb_x_pair_spi));
2633 }
2634
2635 /*
2636 * Take a PF_KEY message pointed to buffer and print it. Useful for DUMP
2637 * and GET.
2638 */
2639 void
print_samsg(FILE * file,uint64_t * buffer,boolean_t want_timestamp,boolean_t vflag,boolean_t ignore_nss)2640 print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp,
2641 boolean_t vflag, boolean_t ignore_nss)
2642 {
2643 uint64_t *current;
2644 struct sadb_msg *samsg = (struct sadb_msg *)buffer;
2645 struct sadb_ext *ext;
2646 struct sadb_lifetime *currentlt = NULL, *hardlt = NULL, *softlt = NULL;
2647 struct sadb_lifetime *idlelt = NULL;
2648 int i;
2649 time_t wallclock;
2650
2651 (void) time(&wallclock);
2652
2653 print_sadb_msg(file, samsg, want_timestamp ? wallclock : 0, vflag);
2654 current = (uint64_t *)(samsg + 1);
2655 while (current - buffer < samsg->sadb_msg_len) {
2656 int lenbytes;
2657
2658 ext = (struct sadb_ext *)current;
2659 lenbytes = SADB_64TO8(ext->sadb_ext_len);
2660 switch (ext->sadb_ext_type) {
2661 case SADB_EXT_SA:
2662 print_sa(file, dgettext(TEXT_DOMAIN,
2663 "SA: "), (struct sadb_sa *)current);
2664 break;
2665 /*
2666 * Pluck out lifetimes and print them at the end. This is
2667 * to show relative lifetimes.
2668 */
2669 case SADB_EXT_LIFETIME_CURRENT:
2670 currentlt = (struct sadb_lifetime *)current;
2671 break;
2672 case SADB_EXT_LIFETIME_HARD:
2673 hardlt = (struct sadb_lifetime *)current;
2674 break;
2675 case SADB_EXT_LIFETIME_SOFT:
2676 softlt = (struct sadb_lifetime *)current;
2677 break;
2678 case SADB_X_EXT_LIFETIME_IDLE:
2679 idlelt = (struct sadb_lifetime *)current;
2680 break;
2681
2682 case SADB_EXT_ADDRESS_SRC:
2683 print_address(file, dgettext(TEXT_DOMAIN, "SRC: "),
2684 (struct sadb_address *)current, ignore_nss);
2685 break;
2686 case SADB_X_EXT_ADDRESS_INNER_SRC:
2687 print_address(file, dgettext(TEXT_DOMAIN, "INS: "),
2688 (struct sadb_address *)current, ignore_nss);
2689 break;
2690 case SADB_EXT_ADDRESS_DST:
2691 print_address(file, dgettext(TEXT_DOMAIN, "DST: "),
2692 (struct sadb_address *)current, ignore_nss);
2693 break;
2694 case SADB_X_EXT_ADDRESS_INNER_DST:
2695 print_address(file, dgettext(TEXT_DOMAIN, "IND: "),
2696 (struct sadb_address *)current, ignore_nss);
2697 break;
2698 case SADB_EXT_KEY_AUTH:
2699 print_key(file, dgettext(TEXT_DOMAIN,
2700 "AKY: "), (struct sadb_key *)current);
2701 break;
2702 case SADB_EXT_KEY_ENCRYPT:
2703 print_key(file, dgettext(TEXT_DOMAIN,
2704 "EKY: "), (struct sadb_key *)current);
2705 break;
2706 case SADB_EXT_IDENTITY_SRC:
2707 print_ident(file, dgettext(TEXT_DOMAIN, "SID: "),
2708 (struct sadb_ident *)current);
2709 break;
2710 case SADB_EXT_IDENTITY_DST:
2711 print_ident(file, dgettext(TEXT_DOMAIN, "DID: "),
2712 (struct sadb_ident *)current);
2713 break;
2714 case SADB_EXT_SENSITIVITY:
2715 print_sens(file, dgettext(TEXT_DOMAIN, "SNS: "),
2716 (struct sadb_sens *)current, ignore_nss);
2717 break;
2718 case SADB_EXT_PROPOSAL:
2719 print_prop(file, dgettext(TEXT_DOMAIN, "PRP: "),
2720 (struct sadb_prop *)current);
2721 break;
2722 case SADB_EXT_SUPPORTED_AUTH:
2723 print_supp(file, dgettext(TEXT_DOMAIN, "SUA: "),
2724 (struct sadb_supported *)current);
2725 break;
2726 case SADB_EXT_SUPPORTED_ENCRYPT:
2727 print_supp(file, dgettext(TEXT_DOMAIN, "SUE: "),
2728 (struct sadb_supported *)current);
2729 break;
2730 case SADB_EXT_SPIRANGE:
2731 print_spirange(file, dgettext(TEXT_DOMAIN, "SPR: "),
2732 (struct sadb_spirange *)current);
2733 break;
2734 case SADB_X_EXT_EPROP:
2735 print_eprop(file, dgettext(TEXT_DOMAIN, "EPR: "),
2736 (struct sadb_prop *)current);
2737 break;
2738 case SADB_X_EXT_KM_COOKIE:
2739 print_kmc(file, dgettext(TEXT_DOMAIN, "KMC: "),
2740 (struct sadb_x_kmc *)current);
2741 break;
2742 case SADB_X_EXT_ADDRESS_NATT_REM:
2743 print_address(file, dgettext(TEXT_DOMAIN, "NRM: "),
2744 (struct sadb_address *)current, ignore_nss);
2745 break;
2746 case SADB_X_EXT_ADDRESS_NATT_LOC:
2747 print_address(file, dgettext(TEXT_DOMAIN, "NLC: "),
2748 (struct sadb_address *)current, ignore_nss);
2749 break;
2750 case SADB_X_EXT_PAIR:
2751 print_pair(file, dgettext(TEXT_DOMAIN, "OTH: "),
2752 (struct sadb_x_pair *)current);
2753 break;
2754 case SADB_X_EXT_OUTER_SENS:
2755 print_sens(file, dgettext(TEXT_DOMAIN, "OSN: "),
2756 (struct sadb_sens *)current, ignore_nss);
2757 break;
2758 case SADB_X_EXT_REPLAY_VALUE:
2759 (void) print_replay(file, dgettext(TEXT_DOMAIN,
2760 "RPL: "), (sadb_x_replay_ctr_t *)current);
2761 break;
2762 default:
2763 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2764 "UNK: Unknown ext. %d, len %d.\n"),
2765 ext->sadb_ext_type, lenbytes);
2766 for (i = 0; i < ext->sadb_ext_len; i++)
2767 (void) fprintf(file, dgettext(TEXT_DOMAIN,
2768 "UNK: 0x%" PRIx64 "\n"),
2769 ((uint64_t *)ext)[i]);
2770 break;
2771 }
2772 current += (lenbytes == 0) ?
2773 SADB_8TO64(sizeof (struct sadb_ext)) : ext->sadb_ext_len;
2774 }
2775 /*
2776 * Print lifetimes NOW.
2777 */
2778 if (currentlt != NULL || hardlt != NULL || softlt != NULL ||
2779 idlelt != NULL)
2780 print_lifetimes(file, wallclock, currentlt, hardlt,
2781 softlt, idlelt, vflag);
2782
2783 if (current - buffer != samsg->sadb_msg_len) {
2784 warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
2785 "WARNING: insufficient buffer space or corrupt message."));
2786 }
2787
2788 (void) fflush(file); /* Make sure our message is out there. */
2789 }
2790
2791 /*
2792 * save_XXX functions are used when "saving" the SA tables to either a
2793 * file or standard output. They use the dump_XXX functions where needed,
2794 * but mostly they use the rparseXXX functions.
2795 */
2796
2797 /*
2798 * Print save information for a lifetime extension.
2799 *
2800 * NOTE : It saves the lifetime in absolute terms. For example, if you
2801 * had a hard_usetime of 60 seconds, you'll save it as 60 seconds, even though
2802 * there may have been 59 seconds burned off the clock.
2803 */
2804 boolean_t
save_lifetime(struct sadb_lifetime * lifetime,FILE * ofile)2805 save_lifetime(struct sadb_lifetime *lifetime, FILE *ofile)
2806 {
2807 char *prefix;
2808
2809 switch (lifetime->sadb_lifetime_exttype) {
2810 case SADB_EXT_LIFETIME_HARD:
2811 prefix = "hard";
2812 break;
2813 case SADB_EXT_LIFETIME_SOFT:
2814 prefix = "soft";
2815 break;
2816 case SADB_X_EXT_LIFETIME_IDLE:
2817 prefix = "idle";
2818 break;
2819 }
2820
2821 if (putc('\t', ofile) == EOF)
2822 return (B_FALSE);
2823
2824 if (lifetime->sadb_lifetime_allocations != 0 && fprintf(ofile,
2825 "%s_alloc %u ", prefix, lifetime->sadb_lifetime_allocations) < 0)
2826 return (B_FALSE);
2827
2828 if (lifetime->sadb_lifetime_bytes != 0 && fprintf(ofile,
2829 "%s_bytes %" PRIu64 " ", prefix, lifetime->sadb_lifetime_bytes) < 0)
2830 return (B_FALSE);
2831
2832 if (lifetime->sadb_lifetime_addtime != 0 && fprintf(ofile,
2833 "%s_addtime %" PRIu64 " ", prefix,
2834 lifetime->sadb_lifetime_addtime) < 0)
2835 return (B_FALSE);
2836
2837 if (lifetime->sadb_lifetime_usetime != 0 && fprintf(ofile,
2838 "%s_usetime %" PRIu64 " ", prefix,
2839 lifetime->sadb_lifetime_usetime) < 0)
2840 return (B_FALSE);
2841
2842 return (B_TRUE);
2843 }
2844
2845 /*
2846 * Print save information for an address extension.
2847 */
2848 boolean_t
save_address(struct sadb_address * addr,FILE * ofile)2849 save_address(struct sadb_address *addr, FILE *ofile)
2850 {
2851 char *printable_addr, buf[INET6_ADDRSTRLEN];
2852 const char *prefix, *pprefix;
2853 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(addr + 1);
2854 struct sockaddr_in *sin = (struct sockaddr_in *)sin6;
2855 int af = sin->sin_family;
2856
2857 /*
2858 * Address-family reality check.
2859 */
2860 if (af != AF_INET6 && af != AF_INET)
2861 return (B_FALSE);
2862
2863 switch (addr->sadb_address_exttype) {
2864 case SADB_EXT_ADDRESS_SRC:
2865 prefix = "src";
2866 pprefix = "sport";
2867 break;
2868 case SADB_X_EXT_ADDRESS_INNER_SRC:
2869 prefix = "isrc";
2870 pprefix = "isport";
2871 break;
2872 case SADB_EXT_ADDRESS_DST:
2873 prefix = "dst";
2874 pprefix = "dport";
2875 break;
2876 case SADB_X_EXT_ADDRESS_INNER_DST:
2877 prefix = "idst";
2878 pprefix = "idport";
2879 break;
2880 case SADB_X_EXT_ADDRESS_NATT_LOC:
2881 prefix = "nat_loc ";
2882 pprefix = "nat_lport";
2883 break;
2884 case SADB_X_EXT_ADDRESS_NATT_REM:
2885 prefix = "nat_rem ";
2886 pprefix = "nat_rport";
2887 break;
2888 }
2889
2890 if (fprintf(ofile, " %s ", prefix) < 0)
2891 return (B_FALSE);
2892
2893 /*
2894 * Do not do address-to-name translation, given that we live in
2895 * an age of names that explode into many addresses.
2896 */
2897 printable_addr = (char *)inet_ntop(af,
2898 (af == AF_INET) ? (char *)&sin->sin_addr : (char *)&sin6->sin6_addr,
2899 buf, sizeof (buf));
2900 if (printable_addr == NULL)
2901 printable_addr = "Invalid IP address.";
2902 if (fprintf(ofile, "%s", printable_addr) < 0)
2903 return (B_FALSE);
2904 if (addr->sadb_address_prefixlen != 0 &&
2905 !((addr->sadb_address_prefixlen == 32 && af == AF_INET) ||
2906 (addr->sadb_address_prefixlen == 128 && af == AF_INET6))) {
2907 if (fprintf(ofile, "/%d", addr->sadb_address_prefixlen) < 0)
2908 return (B_FALSE);
2909 }
2910
2911 /*
2912 * The port is in the same position for struct sockaddr_in and
2913 * struct sockaddr_in6. We exploit that property here.
2914 */
2915 if ((pprefix != NULL) && (sin->sin_port != 0))
2916 (void) fprintf(ofile, " %s %d", pprefix, ntohs(sin->sin_port));
2917
2918 return (B_TRUE);
2919 }
2920
2921 /*
2922 * Print save information for a key extension. Returns whether writing
2923 * to the specified output file was successful or not.
2924 */
2925 boolean_t
save_key(struct sadb_key * key,FILE * ofile)2926 save_key(struct sadb_key *key, FILE *ofile)
2927 {
2928 char *prefix;
2929
2930 if (putc('\t', ofile) == EOF)
2931 return (B_FALSE);
2932
2933 prefix = (key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ? "auth" : "encr";
2934
2935 if (fprintf(ofile, "%skey ", prefix) < 0)
2936 return (B_FALSE);
2937
2938 if (dump_key((uint8_t *)(key + 1), key->sadb_key_bits,
2939 key->sadb_key_reserved, ofile, B_FALSE) == -1)
2940 return (B_FALSE);
2941
2942 return (B_TRUE);
2943 }
2944
2945 /*
2946 * Print save information for an identity extension.
2947 */
2948 boolean_t
save_ident(struct sadb_ident * ident,FILE * ofile)2949 save_ident(struct sadb_ident *ident, FILE *ofile)
2950 {
2951 char *prefix;
2952
2953 if (putc('\t', ofile) == EOF)
2954 return (B_FALSE);
2955
2956 prefix = (ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ? "src" :
2957 "dst";
2958
2959 if (fprintf(ofile, "%sidtype %s ", prefix,
2960 rparseidtype(ident->sadb_ident_type)) < 0)
2961 return (B_FALSE);
2962
2963 if (ident->sadb_ident_type == SADB_X_IDENTTYPE_DN ||
2964 ident->sadb_ident_type == SADB_X_IDENTTYPE_GN) {
2965 if (fprintf(ofile, dgettext(TEXT_DOMAIN,
2966 "<can-not-print>")) < 0)
2967 return (B_FALSE);
2968 } else {
2969 if (fprintf(ofile, "%s", (char *)(ident + 1)) < 0)
2970 return (B_FALSE);
2971 }
2972
2973 return (B_TRUE);
2974 }
2975
2976 boolean_t
save_sens(struct sadb_sens * sens,FILE * ofile)2977 save_sens(struct sadb_sens *sens, FILE *ofile)
2978 {
2979 char *prefix;
2980 char *hlabel;
2981 bslabel_t sl;
2982
2983 if (putc('\t', ofile) == EOF)
2984 return (B_FALSE);
2985
2986 if (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY)
2987 prefix = "label";
2988 else if ((sens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) == 0)
2989 prefix = "outer-label";
2990 else
2991 prefix = "implicit-label";
2992
2993 ipsec_convert_sens_to_bslabel(sens, &sl);
2994 ipsec_convert_bslabel_to_hex(&sl, &hlabel);
2995
2996 if (fprintf(ofile, "%s %s ", prefix, hlabel) < 0) {
2997 free(hlabel);
2998 return (B_FALSE);
2999 }
3000 free(hlabel);
3001
3002 return (B_TRUE);
3003 }
3004
3005 /*
3006 * "Save" a security association to an output file.
3007 *
3008 * NOTE the lack of calls to dgettext() because I'm outputting parseable stuff.
3009 * ALSO NOTE that if you change keywords (see parsecmd()), you'll have to
3010 * change them here as well.
3011 */
3012 void
save_assoc(uint64_t * buffer,FILE * ofile)3013 save_assoc(uint64_t *buffer, FILE *ofile)
3014 {
3015 int terrno;
3016 boolean_t seen_proto = B_FALSE, seen_iproto = B_FALSE;
3017 uint64_t *current;
3018 struct sadb_address *addr;
3019 struct sadb_x_replay_ctr *repl;
3020 struct sadb_msg *samsg = (struct sadb_msg *)buffer;
3021 struct sadb_ext *ext;
3022
3023 #define tidyup() \
3024 terrno = errno; (void) fclose(ofile); errno = terrno; \
3025 interactive = B_FALSE
3026
3027 #define savenl() if (fputs(" \\\n", ofile) == EOF) \
3028 { bail(dgettext(TEXT_DOMAIN, "savenl")); }
3029
3030 if (fputs("# begin assoc\n", ofile) == EOF)
3031 bail(dgettext(TEXT_DOMAIN,
3032 "save_assoc: Opening comment of SA"));
3033 if (fprintf(ofile, "add %s ", rparsesatype(samsg->sadb_msg_satype)) < 0)
3034 bail(dgettext(TEXT_DOMAIN, "save_assoc: First line of SA"));
3035 savenl();
3036
3037 current = (uint64_t *)(samsg + 1);
3038 while (current - buffer < samsg->sadb_msg_len) {
3039 struct sadb_sa *assoc;
3040
3041 ext = (struct sadb_ext *)current;
3042 addr = (struct sadb_address *)ext; /* Just in case... */
3043 switch (ext->sadb_ext_type) {
3044 case SADB_EXT_SA:
3045 assoc = (struct sadb_sa *)ext;
3046 if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) {
3047 if (fprintf(ofile, "# WARNING: SA was dying "
3048 "or dead.\n") < 0) {
3049 tidyup();
3050 bail(dgettext(TEXT_DOMAIN,
3051 "save_assoc: fprintf not mature"));
3052 }
3053 }
3054 if (fprintf(ofile, " spi 0x%x ",
3055 ntohl(assoc->sadb_sa_spi)) < 0) {
3056 tidyup();
3057 bail(dgettext(TEXT_DOMAIN,
3058 "save_assoc: fprintf spi"));
3059 }
3060 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) {
3061 if (fprintf(ofile, "encr_alg %s ",
3062 rparsealg(assoc->sadb_sa_encrypt,
3063 IPSEC_PROTO_ESP)) < 0) {
3064 tidyup();
3065 bail(dgettext(TEXT_DOMAIN,
3066 "save_assoc: fprintf encrypt"));
3067 }
3068 }
3069 if (assoc->sadb_sa_auth != SADB_AALG_NONE) {
3070 if (fprintf(ofile, "auth_alg %s ",
3071 rparsealg(assoc->sadb_sa_auth,
3072 IPSEC_PROTO_AH)) < 0) {
3073 tidyup();
3074 bail(dgettext(TEXT_DOMAIN,
3075 "save_assoc: fprintf auth"));
3076 }
3077 }
3078 if (fprintf(ofile, "replay %d ",
3079 assoc->sadb_sa_replay) < 0) {
3080 tidyup();
3081 bail(dgettext(TEXT_DOMAIN,
3082 "save_assoc: fprintf replay"));
3083 }
3084 if (assoc->sadb_sa_flags & (SADB_X_SAFLAGS_NATT_LOC |
3085 SADB_X_SAFLAGS_NATT_REM)) {
3086 if (fprintf(ofile, "encap udp") < 0) {
3087 tidyup();
3088 bail(dgettext(TEXT_DOMAIN,
3089 "save_assoc: fprintf encap"));
3090 }
3091 }
3092 savenl();
3093 break;
3094 case SADB_EXT_LIFETIME_HARD:
3095 case SADB_EXT_LIFETIME_SOFT:
3096 case SADB_X_EXT_LIFETIME_IDLE:
3097 if (!save_lifetime((struct sadb_lifetime *)ext,
3098 ofile)) {
3099 tidyup();
3100 bail(dgettext(TEXT_DOMAIN, "save_lifetime"));
3101 }
3102 savenl();
3103 break;
3104 case SADB_X_EXT_ADDRESS_INNER_SRC:
3105 case SADB_X_EXT_ADDRESS_INNER_DST:
3106 if (!seen_iproto && addr->sadb_address_proto) {
3107 (void) fprintf(ofile, " iproto %d",
3108 addr->sadb_address_proto);
3109 savenl();
3110 seen_iproto = B_TRUE;
3111 }
3112 goto skip_srcdst; /* Hack to avoid cases below... */
3113 /* FALLTHRU */
3114 case SADB_EXT_ADDRESS_SRC:
3115 case SADB_EXT_ADDRESS_DST:
3116 if (!seen_proto && addr->sadb_address_proto) {
3117 (void) fprintf(ofile, " proto %d",
3118 addr->sadb_address_proto);
3119 savenl();
3120 seen_proto = B_TRUE;
3121 }
3122 /* FALLTHRU */
3123 case SADB_X_EXT_ADDRESS_NATT_REM:
3124 case SADB_X_EXT_ADDRESS_NATT_LOC:
3125 skip_srcdst:
3126 if (!save_address(addr, ofile)) {
3127 tidyup();
3128 bail(dgettext(TEXT_DOMAIN, "save_address"));
3129 }
3130 savenl();
3131 break;
3132 case SADB_EXT_KEY_AUTH:
3133 case SADB_EXT_KEY_ENCRYPT:
3134 if (!save_key((struct sadb_key *)ext, ofile)) {
3135 tidyup();
3136 bail(dgettext(TEXT_DOMAIN, "save_address"));
3137 }
3138 savenl();
3139 break;
3140 case SADB_EXT_IDENTITY_SRC:
3141 case SADB_EXT_IDENTITY_DST:
3142 if (!save_ident((struct sadb_ident *)ext, ofile)) {
3143 tidyup();
3144 bail(dgettext(TEXT_DOMAIN, "save_address"));
3145 }
3146 savenl();
3147 break;
3148 case SADB_X_EXT_REPLAY_VALUE:
3149 repl = (sadb_x_replay_ctr_t *)ext;
3150 if ((repl->sadb_x_rc_replay32 == 0) &&
3151 (repl->sadb_x_rc_replay64 == 0)) {
3152 tidyup();
3153 bail(dgettext(TEXT_DOMAIN, "Replay Value"));
3154 }
3155 if (fprintf(ofile, "replay_value %" PRIu64 "",
3156 (repl->sadb_x_rc_replay32 == 0 ?
3157 repl->sadb_x_rc_replay64 :
3158 repl->sadb_x_rc_replay32)) < 0) {
3159 tidyup();
3160 bail(dgettext(TEXT_DOMAIN,
3161 "save_assoc: fprintf replay value"));
3162 }
3163 savenl();
3164 break;
3165 case SADB_EXT_SENSITIVITY:
3166 case SADB_X_EXT_OUTER_SENS:
3167 if (!save_sens((struct sadb_sens *)ext, ofile)) {
3168 tidyup();
3169 bail(dgettext(TEXT_DOMAIN, "save_sens"));
3170 }
3171 savenl();
3172 break;
3173 default:
3174 /* Skip over irrelevant extensions. */
3175 break;
3176 }
3177 current += ext->sadb_ext_len;
3178 }
3179
3180 if (fputs(dgettext(TEXT_DOMAIN, "\n# end assoc\n\n"), ofile) == EOF) {
3181 tidyup();
3182 bail(dgettext(TEXT_DOMAIN, "save_assoc: last fputs"));
3183 }
3184 }
3185
3186 /*
3187 * Open the output file for the "save" command.
3188 */
3189 FILE *
opensavefile(char * filename)3190 opensavefile(char *filename)
3191 {
3192 int fd;
3193 FILE *retval;
3194 struct stat buf;
3195
3196 /*
3197 * If the user specifies "-" or doesn't give a filename, then
3198 * dump to stdout. Make sure to document the dangers of files
3199 * that are NFS, directing your output to strange places, etc.
3200 */
3201 if (filename == NULL || strcmp("-", filename) == 0)
3202 return (stdout);
3203
3204 /*
3205 * open the file with the create bits set. Since I check for
3206 * real UID == root in main(), I won't worry about the ownership
3207 * problem.
3208 */
3209 fd = open(filename, O_WRONLY | O_EXCL | O_CREAT | O_TRUNC, S_IRUSR);
3210 if (fd == -1) {
3211 if (errno != EEXIST)
3212 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN,
3213 "open error"),
3214 strerror(errno));
3215 fd = open(filename, O_WRONLY | O_TRUNC, 0);
3216 if (fd == -1)
3217 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN,
3218 "open error"), strerror(errno));
3219 if (fstat(fd, &buf) == -1) {
3220 (void) close(fd);
3221 bail_msg("%s fstat: %s", filename, strerror(errno));
3222 }
3223 if (S_ISREG(buf.st_mode) &&
3224 ((buf.st_mode & S_IAMB) != S_IRUSR)) {
3225 warnx(dgettext(TEXT_DOMAIN,
3226 "WARNING: Save file already exists with "
3227 "permission %o."), buf.st_mode & S_IAMB);
3228 warnx(dgettext(TEXT_DOMAIN,
3229 "Normal users may be able to read IPsec "
3230 "keying material."));
3231 }
3232 }
3233
3234 /* Okay, we have an FD. Assign it to a stdio FILE pointer. */
3235 retval = fdopen(fd, "w");
3236 if (retval == NULL) {
3237 (void) close(fd);
3238 bail_msg("%s %s: %s", filename, dgettext(TEXT_DOMAIN,
3239 "fdopen error"), strerror(errno));
3240 }
3241 return (retval);
3242 }
3243
3244 const char *
do_inet_ntop(const void * addr,char * cp,size_t size)3245 do_inet_ntop(const void *addr, char *cp, size_t size)
3246 {
3247 boolean_t isv4;
3248 struct in6_addr *inaddr6 = (struct in6_addr *)addr;
3249 struct in_addr inaddr;
3250
3251 if ((isv4 = IN6_IS_ADDR_V4MAPPED(inaddr6)) == B_TRUE) {
3252 IN6_V4MAPPED_TO_INADDR(inaddr6, &inaddr);
3253 }
3254
3255 return (inet_ntop(isv4 ? AF_INET : AF_INET6,
3256 isv4 ? (void *)&inaddr : inaddr6, cp, size));
3257 }
3258
3259 char numprint[NBUF_SIZE];
3260
3261 /*
3262 * Parse and reverse parse a specific SA type (AH, ESP, etc.).
3263 */
3264 static struct typetable {
3265 char *type;
3266 int token;
3267 } type_table[] = {
3268 {"all", SADB_SATYPE_UNSPEC},
3269 {"ah", SADB_SATYPE_AH},
3270 {"esp", SADB_SATYPE_ESP},
3271 /* PF_KEY NOTE: More to come if net/pfkeyv2.h gets updated. */
3272 {NULL, 0} /* Token value is irrelevant for this entry. */
3273 };
3274
3275 char *
rparsesatype(int type)3276 rparsesatype(int type)
3277 {
3278 struct typetable *tt = type_table;
3279
3280 while (tt->type != NULL && type != tt->token)
3281 tt++;
3282
3283 if (tt->type == NULL) {
3284 (void) snprintf(numprint, NBUF_SIZE, "%d", type);
3285 } else {
3286 return (tt->type);
3287 }
3288
3289 return (numprint);
3290 }
3291
3292
3293 /*
3294 * Return a string containing the name of the specified numerical algorithm
3295 * identifier.
3296 */
3297 char *
rparsealg(uint8_t alg,int proto_num)3298 rparsealg(uint8_t alg, int proto_num)
3299 {
3300 static struct ipsecalgent *holder = NULL; /* we're single-threaded */
3301
3302 if (holder != NULL)
3303 freeipsecalgent(holder);
3304
3305 holder = getipsecalgbynum(alg, proto_num, NULL);
3306 if (holder == NULL) {
3307 (void) snprintf(numprint, NBUF_SIZE, "%d", alg);
3308 return (numprint);
3309 }
3310
3311 return (*(holder->a_names));
3312 }
3313
3314 /*
3315 * Parse and reverse parse out a source/destination ID type.
3316 */
3317 static struct idtypes {
3318 char *idtype;
3319 uint8_t retval;
3320 } idtypes[] = {
3321 {"prefix", SADB_IDENTTYPE_PREFIX},
3322 {"fqdn", SADB_IDENTTYPE_FQDN},
3323 {"domain", SADB_IDENTTYPE_FQDN},
3324 {"domainname", SADB_IDENTTYPE_FQDN},
3325 {"user_fqdn", SADB_IDENTTYPE_USER_FQDN},
3326 {"mailbox", SADB_IDENTTYPE_USER_FQDN},
3327 {"der_dn", SADB_X_IDENTTYPE_DN},
3328 {"der_gn", SADB_X_IDENTTYPE_GN},
3329 {NULL, 0}
3330 };
3331
3332 char *
rparseidtype(uint16_t type)3333 rparseidtype(uint16_t type)
3334 {
3335 struct idtypes *idp;
3336
3337 for (idp = idtypes; idp->idtype != NULL; idp++) {
3338 if (type == idp->retval)
3339 return (idp->idtype);
3340 }
3341
3342 (void) snprintf(numprint, NBUF_SIZE, "%d", type);
3343 return (numprint);
3344 }
3345
3346 /*
3347 * This is a general purpose exit function, calling functions can specify an
3348 * error type. If the command calling this function was started by smf(5) the
3349 * error type could be used as a hint to the restarter. In the future this
3350 * function could be used to do something more intelligent with a process that
3351 * encounters an error. If exit() is called with an error code other than those
3352 * defined by smf(5), the program will just get restarted. Unless restarting
3353 * is likely to resolve the error condition, its probably sensible to just
3354 * log the error and keep running.
3355 *
3356 * The SERVICE_* exit_types mean nothing if the command was run from the
3357 * command line, just exit(). There are two special cases:
3358 *
3359 * SERVICE_DEGRADE - Not implemented in smf(5), one day it could hint that
3360 * the service is not running as well is it could. For
3361 * now, don't do anything, just record the error.
3362 * DEBUG_FATAL - Something happened, if the command was being run in debug
3363 * mode, exit() as you really want to know something happened,
3364 * otherwise just keep running. This is ignored when running
3365 * under smf(5).
3366 *
3367 * The function will handle an optional variable args error message, this
3368 * will be written to the error stream, typically a log file or stderr.
3369 */
3370 void
ipsecutil_exit(exit_type_t type,char * fmri,FILE * fp,const char * fmt,...)3371 ipsecutil_exit(exit_type_t type, char *fmri, FILE *fp, const char *fmt, ...)
3372 {
3373 int exit_status;
3374 va_list args;
3375
3376 if (fp == NULL)
3377 fp = stderr;
3378 if (fmt != NULL) {
3379 va_start(args, fmt);
3380 vwarnxfp(fp, fmt, args);
3381 va_end(args);
3382 }
3383
3384 if (fmri == NULL) {
3385 /* Command being run directly from a shell. */
3386 switch (type) {
3387 case SERVICE_EXIT_OK:
3388 exit_status = 0;
3389 break;
3390 case SERVICE_DEGRADE:
3391 return;
3392 break;
3393 case SERVICE_BADPERM:
3394 case SERVICE_BADCONF:
3395 case SERVICE_MAINTAIN:
3396 case SERVICE_DISABLE:
3397 case SERVICE_FATAL:
3398 case SERVICE_RESTART:
3399 case DEBUG_FATAL:
3400 warnxfp(fp, "Fatal error - exiting.");
3401 exit_status = 1;
3402 break;
3403 }
3404 } else {
3405 /* Command being run as a smf(5) method. */
3406 switch (type) {
3407 case SERVICE_EXIT_OK:
3408 exit_status = SMF_EXIT_OK;
3409 break;
3410 case SERVICE_DEGRADE: /* Not implemented yet. */
3411 case DEBUG_FATAL:
3412 /* Keep running, don't exit(). */
3413 return;
3414 break;
3415 case SERVICE_BADPERM:
3416 warnxfp(fp, dgettext(TEXT_DOMAIN,
3417 "Permission error with %s."), fmri);
3418 exit_status = SMF_EXIT_ERR_PERM;
3419 break;
3420 case SERVICE_BADCONF:
3421 warnxfp(fp, dgettext(TEXT_DOMAIN,
3422 "Bad configuration of service %s."), fmri);
3423 exit_status = SMF_EXIT_ERR_FATAL;
3424 break;
3425 case SERVICE_MAINTAIN:
3426 warnxfp(fp, dgettext(TEXT_DOMAIN,
3427 "Service %s needs maintenance."), fmri);
3428 exit_status = SMF_EXIT_ERR_FATAL;
3429 break;
3430 case SERVICE_DISABLE:
3431 exit_status = SMF_EXIT_ERR_FATAL;
3432 break;
3433 case SERVICE_FATAL:
3434 warnxfp(fp, dgettext(TEXT_DOMAIN,
3435 "Service %s fatal error."), fmri);
3436 exit_status = SMF_EXIT_ERR_FATAL;
3437 break;
3438 case SERVICE_RESTART:
3439 exit_status = 1;
3440 break;
3441 }
3442 }
3443 (void) fflush(fp);
3444 (void) fclose(fp);
3445 exit(exit_status);
3446 }
3447