1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  *
  21  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  22  */
  23 
  24 #include <unistd.h>
  25 #include <stdio.h>
  26 #include <stdarg.h>
  27 #include <stdlib.h>
  28 #include <sys/sysconf.h>
  29 #include <string.h>
  30 #include <strings.h>
  31 #include <libintl.h>
  32 #include <locale.h>
  33 #include <ctype.h>
  34 #include <time.h>
  35 #include <sys/sysmacros.h>
  36 #include <sys/stat.h>
  37 #include <sys/mman.h>
  38 #include <fcntl.h>
  39 #include <sys/socket.h>
  40 #include <netdb.h>
  41 #include <errno.h>
  42 #include <assert.h>
  43 #include <netinet/in.h>
  44 #include <arpa/inet.h>
  45 #include <door.h>
  46 #include <setjmp.h>
  47 
  48 #include <ipsec_util.h>
  49 #include <ikedoor.h>
  50 
  51 static int      doorfd = -1;
  52 
  53 /*
  54  * These are additional return values for the command line parsing
  55  * function (parsecmd()).  They are specific to this utility, but
  56  * need to share the same space as the IKE_SVC_* defs, without conflicts.
  57  * So they're defined relative to the end of that range.
  58  */
  59 #define IKEADM_HELP_GENERAL     IKE_SVC_MAX + 1
  60 #define IKEADM_HELP_GET         IKE_SVC_MAX + 2
  61 #define IKEADM_HELP_SET         IKE_SVC_MAX + 3
  62 #define IKEADM_HELP_ADD         IKE_SVC_MAX + 4
  63 #define IKEADM_HELP_DEL         IKE_SVC_MAX + 5
  64 #define IKEADM_HELP_DUMP        IKE_SVC_MAX + 6
  65 #define IKEADM_HELP_FLUSH       IKE_SVC_MAX + 7
  66 #define IKEADM_HELP_READ        IKE_SVC_MAX + 8
  67 #define IKEADM_HELP_WRITE       IKE_SVC_MAX + 9
  68 #define IKEADM_HELP_TOKEN       IKE_SVC_MAX + 10
  69 #define IKEADM_HELP_HELP        IKE_SVC_MAX + 11
  70 #define IKEADM_EXIT             IKE_SVC_MAX + 12
  71 
  72 /*
  73  * Disable default TAB completion for now (until some brave soul tackles it).
  74  */
  75 /* ARGSUSED */
  76 static
  77 CPL_MATCH_FN(no_match)
  78 {
  79         return (0);
  80 }
  81 
  82 static void
  83 command_complete(int s)
  84 {
  85         if (interactive) {
  86                 longjmp(env, 1);
  87         } else {
  88                 exit(s);
  89         }
  90 }
  91 
  92 static void
  93 usage()
  94 {
  95         if (!interactive) {
  96                 (void) fprintf(stderr, gettext("Usage:\t"
  97                     "ikeadm [ -hnp ] cmd obj [cmd-specific options]\n"));
  98                 (void) fprintf(stderr, gettext("      \tikeadm help\n"));
  99         } else {
 100                 (void) fprintf(stderr,
 101                     gettext("\nType help for usage info\n"));
 102         }
 103 
 104         command_complete(1);
 105 }
 106 
 107 static void
 108 print_help()
 109 {
 110         (void) printf(gettext("Valid commands and objects:\n"));
 111         (void) printf(
 112             "\tget   debug|priv|stats|p1|rule|preshared|defaults [%s]\n",
 113             gettext("identifier"));
 114         (void) printf("\tset   priv %s\n", gettext("level"));
 115         (void) printf("\tset   debug %s [%s]\n",
 116             gettext("level"), gettext("filename"));
 117         (void) printf("\tadd   rule|preshared {%s}|%s\n",
 118             gettext("definition"), gettext("filename"));
 119         (void) printf("\tdel   p1|rule|preshared %s\n", gettext("identifier"));
 120         (void) printf("\tdump  p1|rule|preshared|certcache|groups|"
 121             "encralgs|authalgs\n");
 122         (void) printf("\tflush p1|certcache\n");
 123         (void) printf("\tread  rule|preshared [%s]\n", gettext("filename"));
 124         (void) printf("\twrite rule|preshared %s\n", gettext("filename"));
 125         (void) printf("\ttoken <login|logout> %s\n",
 126             gettext("<PKCS#11 Token Object>"));
 127         (void) printf(
 128             "\thelp  [get|set|add|del|dump|flush|read|write|token|help]\n");
 129         (void) printf("\texit  %s\n", gettext("exit the program"));
 130         (void) printf("\tquit  %s\n", gettext("exit the program"));
 131 
 132         command_complete(0);
 133 }
 134 
 135 static void
 136 print_get_help()
 137 {
 138         (void) printf(
 139             gettext("This command gets information from in.iked.\n\n"));
 140         (void) printf(gettext("Objects that may be retrieved include:\n"));
 141         (void) printf("\tdebug\t\t");
 142         (void) printf(gettext("the current debug level\n"));
 143         (void) printf("\tpriv\t\t");
 144         (void) printf(gettext("the current privilege level\n"));
 145         (void) printf("\tstats\t\t");
 146         (void) printf(gettext("current usage statistics\n"));
 147         (void) printf("\tp1\t\t");
 148         (void) printf(gettext("a phase 1 SA, identified by\n"));
 149         (void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
 150         (void) printf(gettext("\t\t\t  init_cookie resp_cookie\n"));
 151         (void) printf("\trule\t\t");
 152         (void) printf(gettext("a phase 1 rule, identified by its label\n"));
 153         (void) printf("\tpreshared\t");
 154         (void) printf(gettext("a preshared key, identified by\n"));
 155         (void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
 156         (void) printf(gettext("\t\t\t  local_id remote_id\n"));
 157         (void) printf("\n");
 158 
 159         command_complete(0);
 160 }
 161 
 162 static void
 163 print_set_help()
 164 {
 165         (void) printf(gettext("This command sets values in in.iked.\n\n"));
 166         (void) printf(gettext("Objects that may be set include:\n"));
 167         (void) printf("\tdebug\t\t");
 168         (void) printf(gettext("change the debug level\n"));
 169         (void) printf("\tpriv\t\t");
 170         (void) printf(
 171             gettext("change the privilege level (may only be lowered)\n"));
 172         (void) printf("\n");
 173 
 174         command_complete(0);
 175 }
 176 
 177 static void
 178 print_add_help()
 179 {
 180         (void) printf(
 181             gettext("This command adds items to in.iked's tables.\n\n"));
 182         (void) printf(gettext("Objects that may be set include:\n"));
 183         (void) printf("\trule\t\t");
 184         (void) printf(gettext("a phase 1 policy rule\n"));
 185         (void) printf("\tpreshared\t");
 186         (void) printf(gettext("a preshared key\n"));
 187         (void) printf(
 188             gettext("\nObjects may be entered on the command-line, as a\n"));
 189         (void) printf(
 190             gettext("series of keywords and tokens contained in curly\n"));
 191         (void) printf(
 192             gettext("braces ('{', '}'); or the name of a file containing\n"));
 193         (void) printf(gettext("the object definition may be provided.\n\n"));
 194         (void) printf(
 195             gettext("For security purposes, preshared keys may only be\n"));
 196         (void) printf(
 197             gettext("entered on the command-line if ikeadm is running in\n"));
 198         (void) printf(gettext("interactive mode.\n"));
 199         (void) printf("\n");
 200 
 201         command_complete(0);
 202 }
 203 
 204 static void
 205 print_del_help()
 206 {
 207         (void) printf(
 208             gettext("This command deletes an item from in.iked's tables.\n\n"));
 209         (void) printf(gettext("Objects that may be deleted include:\n"));
 210         (void) printf("\tp1\t\t");
 211         (void) printf(gettext("a phase 1 SA, identified by\n"));
 212         (void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
 213         (void) printf(gettext("\t\t\t  init_cookie resp_cookie\n"));
 214         (void) printf("\trule\t\t");
 215         (void) printf(gettext("a phase 1 rule, identified by its label\n"));
 216         (void) printf("\tpreshared\t");
 217         (void) printf(gettext("a preshared key, identified by\n"));
 218         (void) printf(gettext("\t\t\t  local_ip remote_ip OR\n"));
 219         (void) printf(gettext("\t\t\t  local_id remote_id\n"));
 220         (void) printf("\n");
 221 
 222         command_complete(0);
 223 }
 224 
 225 static void
 226 print_dump_help()
 227 {
 228         (void) printf(
 229             gettext("This command dumps one of in.iked's tables.\n\n"));
 230         (void) printf(gettext("Tables that may be dumped include:\n"));
 231         (void) printf("\tp1\t\t");
 232         (void) printf(gettext("all phase 1 SAs\n"));
 233         (void) printf("\trule\t\t");
 234         (void) printf(gettext("all phase 1 rules\n"));
 235         (void) printf("\tpreshared\t");
 236         (void) printf(gettext("all preshared keys\n"));
 237         (void) printf("\tcertcache\t");
 238         (void) printf(gettext("all cached certificates\n"));
 239         (void) printf("\tgroups\t\t");
 240         (void) printf(gettext("all implemented Diffie-Hellman groups\n"));
 241         (void) printf("\tencralgs\t");
 242         (void) printf(gettext("all encryption algorithms for IKE\n"));
 243         (void) printf("\tauthalgs\t");
 244         (void) printf(gettext("all authentication algorithms IKE\n"));
 245         (void) printf("\n");
 246 
 247         command_complete(0);
 248 }
 249 
 250 static void
 251 print_flush_help()
 252 {
 253         (void) printf(
 254             gettext("This command clears one of in.iked's tables.\n\n"));
 255         (void) printf(gettext("Tables that may be flushed include:\n"));
 256         (void) printf("\tp1\t\t");
 257         (void) printf(gettext("all phase 1 SAs\n"));
 258         (void) printf("\tcertcache\t");
 259         (void) printf(gettext("all cached certificates\n"));
 260         (void) printf("\n");
 261 
 262         command_complete(0);
 263 }
 264 
 265 static void
 266 print_read_help()
 267 {
 268         (void) printf(
 269             gettext("This command reads a new configuration file into\n"));
 270         (void) printf(
 271             gettext("in.iked, discarding the old configuration info.\n\n"));
 272         (void) printf(gettext("Sets of data that may be read include:\n"));
 273         (void) printf("\trule\t\t");
 274         (void) printf(gettext("all phase 1 rules\n"));
 275         (void) printf("\tpreshared\t");
 276         (void) printf(gettext("all preshared keys\n\n"));
 277         (void) printf(
 278             gettext("A filename may be provided to specify a source file\n"));
 279         (void) printf(gettext("other than the default.\n"));
 280         (void) printf("\n");
 281 
 282         command_complete(0);
 283 }
 284 
 285 static void
 286 print_write_help()
 287 {
 288         (void) printf(
 289             gettext("This command writes in.iked's current configuration\n"));
 290         (void) printf(gettext("out to a config file.\n\n"));
 291         (void) printf(gettext("Sets of data that may be written include:\n"));
 292         (void) printf("\trule\t\t");
 293         (void) printf(gettext("all phase 1 rules\n"));
 294         (void) printf("\tpreshared\t");
 295         (void) printf(gettext("all preshared keys\n\n"));
 296         (void) printf(
 297             gettext("A filename must be provided to specify the file to\n"));
 298         (void) printf(gettext("which the information should be written.\n"));
 299         (void) printf("\n");
 300 
 301         command_complete(0);
 302 }
 303 
 304 static void
 305 print_token_help()
 306 {
 307         (void) printf(gettext(
 308             "This command logs IKE into and out of PKCS#11 tokens.\n\n"));
 309         (void) printf(gettext("Commands include:\n"));
 310         (void) printf("\tlogin <PKCS#11 Token Object>\t");
 311         (void) printf(gettext("log into token\n"));
 312         (void) printf("\tlogout <PKCS#11 Token Object>\t");
 313         (void) printf(gettext("log out of token\n\n"));
 314         (void) printf(
 315             gettext("The PKCS#11 Token Object name must be "
 316             "enclosed in quotation marks.\n"));
 317         (void) printf("\n");
 318 
 319         command_complete(0);
 320 }
 321 
 322 static void
 323 print_help_help()
 324 {
 325         (void) printf(
 326             gettext("This command provides information about commands.\n\n"));
 327         (void) printf(
 328             gettext("The 'help' command alone provides a list of valid\n"));
 329         (void) printf(
 330             gettext("commands, along with the valid objects for each.\n"));
 331         (void) printf(
 332             gettext("'help' followed by a valid command name provides\n"));
 333         (void) printf(gettext("further information about that command.\n"));
 334         (void) printf("\n");
 335 
 336         command_complete(0);
 337 }
 338 
 339 /*PRINTFLIKE1*/
 340 static void
 341 message(char *fmt, ...)
 342 {
 343         va_list ap;
 344         char    msgbuf[BUFSIZ];
 345 
 346         va_start(ap, fmt);
 347         (void) vsnprintf(msgbuf, BUFSIZ, fmt, ap);
 348         (void) fprintf(stderr, gettext("ikeadm: %s\n"), msgbuf);
 349         va_end(ap);
 350 }
 351 
 352 static int
 353 open_door(void)
 354 {
 355         if (doorfd >= 0)
 356                 (void) close(doorfd);
 357         doorfd = open(DOORNM, O_RDONLY);
 358         return (doorfd);
 359 }
 360 
 361 static ike_service_t *
 362 ikedoor_call(char *reqp, int size, door_desc_t *descp, int ndesc)
 363 {
 364         door_arg_t      arg;
 365         int retries = 0;
 366 
 367         arg.data_ptr = reqp;
 368         arg.data_size = size;
 369         arg.desc_ptr = descp;
 370         arg.desc_num = ndesc;
 371         arg.rbuf = (char *)NULL;
 372         arg.rsize = 0;
 373 
 374 retry:
 375         if (door_call(doorfd, &arg) < 0) {
 376                 if ((errno == EBADF) && ((++retries < 2) &&
 377                     (open_door() >= 0)))
 378                         goto retry;
 379                 (void) fprintf(stderr,
 380                     gettext("Unable to communicate with in.iked\n"));
 381                 Bail("door_call failed");
 382         }
 383 
 384         if ((ndesc > 0) && (descp->d_attributes & DOOR_RELEASE) &&
 385             ((errno == EBADF) || (errno == EFAULT))) {
 386                 /* callers assume passed fds will be closed no matter what */
 387                 (void) close(descp->d_data.d_desc.d_descriptor);
 388         }
 389 
 390         /* LINTED E_BAD_PTR_CAST_ALIGN */
 391         return ((ike_service_t *)arg.rbuf);
 392 }
 393 
 394 /*
 395  * Parsing functions
 396  */
 397 
 398 /* stolen from ipseckey.c, with a second tier added */
 399 static int
 400 parsecmd(char *cmdstr, char *objstr)
 401 {
 402 #define MAXOBJS         11
 403         struct objtbl {
 404                 char    *obj;
 405                 int     token;
 406         };
 407         static struct cmdtbl {
 408                 char            *cmd;
 409                 int             null_obj_token;
 410                 struct objtbl   objt[MAXOBJS];
 411         } table[] = {
 412                 {"get", IKE_SVC_ERROR, {
 413                                 {"debug",       IKE_SVC_GET_DBG},
 414                                 {"priv",        IKE_SVC_GET_PRIV},
 415                                 {"stats",       IKE_SVC_GET_STATS},
 416                                 {"p1",          IKE_SVC_GET_P1},
 417                                 {"rule",        IKE_SVC_GET_RULE},
 418                                 {"preshared",   IKE_SVC_GET_PS},
 419                                 {"defaults",    IKE_SVC_GET_DEFS},
 420                                 {NULL,          IKE_SVC_ERROR}
 421                         }
 422                 },
 423                 {"set", IKE_SVC_ERROR, {
 424                                 {"debug",       IKE_SVC_SET_DBG},
 425                                 {"priv",        IKE_SVC_SET_PRIV},
 426                                 {NULL,          IKE_SVC_ERROR}
 427                         }
 428                 },
 429                 {"token", IKE_SVC_ERROR, {
 430                                 {"login",       IKE_SVC_SET_PIN},
 431                                 {"logout",      IKE_SVC_DEL_PIN},
 432                                 {NULL,          IKE_SVC_ERROR},
 433                         }
 434                 },
 435                 {"add", IKE_SVC_ERROR, {
 436                                 {"rule",        IKE_SVC_NEW_RULE},
 437                                 {"preshared",   IKE_SVC_NEW_PS},
 438                                 {NULL,          IKE_SVC_ERROR}
 439                         }
 440                 },
 441                 {"del", IKE_SVC_ERROR, {
 442                                 {"p1",          IKE_SVC_DEL_P1},
 443                                 {"rule",        IKE_SVC_DEL_RULE},
 444                                 {"preshared",   IKE_SVC_DEL_PS},
 445                                 {NULL,          IKE_SVC_ERROR}
 446                         }
 447                 },
 448                 {"dump", IKE_SVC_ERROR, {
 449                                 {"p1",          IKE_SVC_DUMP_P1S},
 450                                 {"rule",        IKE_SVC_DUMP_RULES},
 451                                 {"preshared",   IKE_SVC_DUMP_PS},
 452                                 {"certcache",   IKE_SVC_DUMP_CERTCACHE},
 453                                 {"groups",      IKE_SVC_DUMP_GROUPS},
 454                                 {"encralgs",    IKE_SVC_DUMP_ENCRALGS},
 455                                 {"authalgs",    IKE_SVC_DUMP_AUTHALGS},
 456                                 {NULL,          IKE_SVC_ERROR}
 457                         }
 458                 },
 459                 {"flush", IKE_SVC_ERROR, {
 460                                 {"p1",          IKE_SVC_FLUSH_P1S},
 461                                 {"certcache",   IKE_SVC_FLUSH_CERTCACHE},
 462                                 {NULL,          IKE_SVC_ERROR}
 463                         }
 464                 },
 465                 {"read", IKE_SVC_ERROR, {
 466                                 {"rule",        IKE_SVC_READ_RULES},
 467                                 {"preshared",   IKE_SVC_READ_PS},
 468                                 {NULL,          IKE_SVC_ERROR}
 469                         }
 470                 },
 471                 {"write", IKE_SVC_ERROR, {
 472                                 {"rule",        IKE_SVC_WRITE_RULES},
 473                                 {"preshared",   IKE_SVC_WRITE_PS},
 474                                 {NULL,          IKE_SVC_ERROR}
 475                         }
 476                 },
 477                 {"help", IKEADM_HELP_GENERAL, {
 478                                 {"get",         IKEADM_HELP_GET},
 479                                 {"set",         IKEADM_HELP_SET},
 480                                 {"add",         IKEADM_HELP_ADD},
 481                                 {"del",         IKEADM_HELP_DEL},
 482                                 {"dump",        IKEADM_HELP_DUMP},
 483                                 {"flush",       IKEADM_HELP_FLUSH},
 484                                 {"read",        IKEADM_HELP_READ},
 485                                 {"write",       IKEADM_HELP_WRITE},
 486                                 {"token",       IKEADM_HELP_TOKEN},
 487                                 {"help",        IKEADM_HELP_HELP},
 488                                 {NULL,          IKE_SVC_ERROR}
 489                         }
 490                 },
 491                 {"exit", IKEADM_EXIT, {
 492                                 {NULL,          IKE_SVC_ERROR}
 493                         }
 494                 },
 495                 {"quit", IKEADM_EXIT, {
 496                                 {NULL,          IKE_SVC_ERROR}
 497                         }
 498                 },
 499                 {"dbg", IKE_SVC_ERROR, {
 500                                 {"rbdump",      IKE_SVC_DBG_RBDUMP},
 501                                 {NULL,          IKE_SVC_ERROR}
 502                         }
 503                 },
 504                 {NULL,  IKE_SVC_ERROR, {
 505                                 {NULL,          IKE_SVC_ERROR}
 506                         }
 507                 }
 508         };
 509         struct cmdtbl   *ct = table;
 510         struct objtbl   *ot;
 511 
 512         if (cmdstr == NULL) {
 513                 return (IKE_SVC_ERROR);
 514         }
 515 
 516         while (ct->cmd != NULL && strcmp(ct->cmd, cmdstr) != 0)
 517                 ct++;
 518         ot = ct->objt;
 519 
 520         if (ct->cmd == NULL) {
 521                 message(gettext("Unrecognized command '%s'"), cmdstr);
 522                 return (ot->token);
 523         }
 524 
 525         if (objstr == NULL) {
 526                 return (ct->null_obj_token);
 527         }
 528 
 529         while (ot->obj != NULL && strcmp(ot->obj, objstr) != 0)
 530                 ot++;
 531 
 532         if (ot->obj == NULL)
 533                 message(gettext("Unrecognized object '%s'"), objstr);
 534 
 535         return (ot->token);
 536 }
 537 
 538 /*
 539  * Parsing functions:
 540  * Parse command-line identification info.  All return -1 on failure,
 541  * or the number of cmd-line args "consumed" on success (though argc
 542  * and argv params are not actually modified).
 543  */
 544 
 545 static int
 546 parse_label(int argc, char **argv, char *label)
 547 {
 548         if ((argc < 1) || (argv == NULL))
 549                 return (-1);
 550 
 551         if (strlcpy(label, argv[0], MAX_LABEL_LEN) >= MAX_LABEL_LEN)
 552                 return (-1);
 553 
 554         return (1);
 555 }
 556 
 557 /*
 558  * Parse a PKCS#11 token get the label.
 559  */
 560 static int
 561 parse_token(int argc, char **argv, char *token_label)
 562 {
 563         if ((argc < 1) || (argv == NULL))
 564                 return (-1);
 565 
 566         if (strlcpy(token_label, argv[0], PKCS11_TOKSIZE) >= PKCS11_TOKSIZE)
 567                 return (-1);
 568 
 569         return (0);
 570 }
 571 
 572 /*
 573  * Parse an address off the command line. In the hpp param, either
 574  * return a hostent pointer (caller frees) or a pointer to a dummy_he_t
 575  * (must also be freed by the caller; both cases are handled by the
 576  * macro FREE_HE).  The new getipnodebyname() call does the Right Thing
 577  * (TM), even with raw addresses (colon-separated IPv6 or dotted decimal
 578  * IPv4).
 579  * (mostly stolen from ipseckey.c, though some tweaks were made
 580  * to better serve our purposes here.)
 581  */
 582 
 583 typedef struct {
 584         struct hostent  he;
 585         char            *addtl[2];
 586 } dummy_he_t;
 587 
 588 static int
 589 parse_addr(int argc, char **argv, struct hostent **hpp)
 590 {
 591         int             hp_errno;
 592         struct hostent  *hp = NULL;
 593         dummy_he_t      *dhp;
 594         char            *addr1;
 595 
 596         if ((argc < 1) || (argv == NULL) || (argv[0] == NULL))
 597                 return (-1);
 598 
 599         if (!nflag) {
 600                 /*
 601                  * Try name->address first.  Assume AF_INET6, and
 602                  * get IPV4s, plus IPv6s iff IPv6 is configured.
 603                  */
 604                 hp = getipnodebyname(argv[0], AF_INET6, AI_DEFAULT | AI_ALL,
 605                     &hp_errno);
 606         } else {
 607                 /*
 608                  * Try a normal address conversion only.  malloc a
 609                  * dummy_he_t to construct a fake hostent.  Caller
 610                  * will know to free this one using free_he().
 611                  */
 612                 dhp = (dummy_he_t *)malloc(sizeof (dummy_he_t));
 613                 addr1 = (char *)malloc(sizeof (struct in6_addr));
 614                 if (inet_pton(AF_INET6, argv[0], addr1) == 1) {
 615                         dhp->he.h_addr_list = dhp->addtl;
 616                         dhp->addtl[0] = addr1;
 617                         dhp->addtl[1] = NULL;
 618                         hp = &dhp->he;
 619                         dhp->he.h_addrtype = AF_INET6;
 620                         dhp->he.h_length = sizeof (struct in6_addr);
 621                 } else if (inet_pton(AF_INET, argv[0], addr1) == 1) {
 622                         dhp->he.h_addr_list = dhp->addtl;
 623                         dhp->addtl[0] = addr1;
 624                         dhp->addtl[1] = NULL;
 625                         hp = &dhp->he;
 626                         dhp->he.h_addrtype = AF_INET;
 627                         dhp->he.h_length = sizeof (struct in_addr);
 628                 } else {
 629                         hp = NULL;
 630                 }
 631         }
 632 
 633         *hpp = hp;
 634 
 635         if (hp == NULL) {
 636                 message(gettext("Unknown address %s."), argv[0]);
 637                 return (-1);
 638         }
 639 
 640         return (1);
 641 }
 642 
 643 /*
 644  * Free a dummy_he_t structure that was malloc'd in parse_addr().
 645  * Unfortunately, callers of parse_addr don't want to know about
 646  * dummy_he_t structs, so all they have is a pointer to the struct
 647  * hostent; so that's what's passed in.  To manage this, we make
 648  * the assumption that the struct hostent is the first field in
 649  * the dummy_he_t, and therefore a pointer to it is a pointer to
 650  * the dummy_he_t.
 651  */
 652 static void
 653 free_he(struct hostent *hep)
 654 {
 655         dummy_he_t      *p = (dummy_he_t *)hep;
 656 
 657         assert(p != NULL);
 658 
 659         if (p->addtl[0])
 660                 free(p->addtl[0]);
 661         if (p->addtl[1])
 662                 free(p->addtl[1]);
 663 
 664         free(p);
 665 }
 666 
 667 #define FREE_HE(x) \
 668         if (nflag) \
 669                 free_he(x); \
 670         else \
 671                 freehostent(x)
 672 
 673 static void
 674 headdr2sa(char *hea, struct sockaddr_storage *sa, int len)
 675 {
 676         struct sockaddr_in      *sin;
 677         struct sockaddr_in6     *sin6;
 678 
 679         if (len == sizeof (struct in6_addr)) {
 680                 /* LINTED E_BAD_PTR_CAST_ALIGN */
 681                 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)hea)) {
 682                         sin = (struct sockaddr_in *)sa;
 683                         (void) memset(sin, 0, sizeof (*sin));
 684                         /* LINTED E_BAD_PTR_CAST_ALIGN */
 685                         IN6_V4MAPPED_TO_INADDR((struct in6_addr *)hea,
 686                             &sin->sin_addr);
 687                         sin->sin_family = AF_INET;
 688                 } else {
 689                         sin6 = (struct sockaddr_in6 *)sa;
 690                         (void) memset(sin6, 0, sizeof (*sin6));
 691                         (void) memcpy(&sin6->sin6_addr, hea,
 692                             sizeof (struct in6_addr));
 693                         sin6->sin6_family = AF_INET6;
 694                 }
 695         } else {
 696                 sin = (struct sockaddr_in *)sa;
 697                 (void) memset(sin, 0, sizeof (*sin));
 698                 (void) memcpy(&sin->sin_addr, hea, sizeof (struct in_addr));
 699                 sin->sin_family = AF_INET;
 700         }
 701 }
 702 
 703 /*
 704  * The possible ident-type keywords that might be used on the command
 705  * line.  This is a superset of the ones supported by ipseckey, those
 706  * in the ike config file, and those in ike.preshared.
 707  */
 708 static keywdtab_t       idtypes[] = {
 709         /* ip, ipv4, and ipv6 are valid for preshared keys... */
 710         {SADB_IDENTTYPE_RESERVED,       "ip"},
 711         {SADB_IDENTTYPE_RESERVED,       "ipv4"},
 712         {SADB_IDENTTYPE_RESERVED,       "ipv6"},
 713         {SADB_IDENTTYPE_PREFIX,         "prefix"},
 714         {SADB_IDENTTYPE_PREFIX,         "ipv4-prefix"},
 715         {SADB_IDENTTYPE_PREFIX,         "ipv6-prefix"},
 716         {SADB_IDENTTYPE_PREFIX,         "subnet"},
 717         {SADB_IDENTTYPE_PREFIX,         "subnetv4"},
 718         {SADB_IDENTTYPE_PREFIX,         "subnetv6"},
 719         {SADB_IDENTTYPE_FQDN,           "fqdn"},
 720         {SADB_IDENTTYPE_FQDN,           "dns"},
 721         {SADB_IDENTTYPE_FQDN,           "domain"},
 722         {SADB_IDENTTYPE_FQDN,           "domainname"},
 723         {SADB_IDENTTYPE_USER_FQDN,      "user_fqdn"},
 724         {SADB_IDENTTYPE_USER_FQDN,      "mbox"},
 725         {SADB_IDENTTYPE_USER_FQDN,      "mailbox"},
 726         {SADB_X_IDENTTYPE_DN,           "dn"},
 727         {SADB_X_IDENTTYPE_DN,           "asn1dn"},
 728         {SADB_X_IDENTTYPE_GN,           "gn"},
 729         {SADB_X_IDENTTYPE_GN,           "asn1gn"},
 730         {SADB_X_IDENTTYPE_ADDR_RANGE,   "ipv4-range"},
 731         {SADB_X_IDENTTYPE_ADDR_RANGE,   "ipv6-range"},
 732         {SADB_X_IDENTTYPE_ADDR_RANGE,   "rangev4"},
 733         {SADB_X_IDENTTYPE_ADDR_RANGE,   "rangev6"},
 734         {SADB_X_IDENTTYPE_KEY_ID,       "keyid"},
 735         {0, NULL}
 736 };
 737 
 738 static int
 739 parse_idtype(char *type, uint16_t *idnum)
 740 {
 741         keywdtab_t      *idp;
 742 
 743         if (type == NULL)
 744                 return (-1);
 745 
 746         for (idp = idtypes; idp->kw_str != NULL; idp++) {
 747                 if (strcasecmp(idp->kw_str, type) == 0) {
 748                         if (idnum != NULL)
 749                                 *idnum = idp->kw_tag;
 750                         return (1);
 751                 }
 752         }
 753 
 754         return (-1);
 755 }
 756 
 757 /*
 758  * The sadb_ident_t is malloc'd, since its length varies;
 759  * so the caller must free() it when done with the data.
 760  */
 761 static int
 762 parse_ident(int argc, char **argv, sadb_ident_t **idpp)
 763 {
 764         int             alloclen, consumed;
 765         sadb_ident_t    *idp;
 766         if ((argc < 2) || (argv == NULL) || (argv[0] == NULL) ||
 767             (argv[1] == NULL))
 768                 return (-1);
 769 
 770         alloclen = sizeof (sadb_ident_t) + IKEDOORROUNDUP(strlen(argv[1]) + 1);
 771         *idpp = idp = (sadb_ident_t *)malloc(alloclen);
 772         if (idp == NULL)
 773                 Bail("parsing identity");
 774 
 775         if ((consumed = parse_idtype(argv[0], &idp->sadb_ident_type)) < 0) {
 776                 message(gettext("unknown identity type %s."), argv[0]);
 777                 return (-1);
 778         }
 779 
 780         idp->sadb_ident_len = SADB_8TO64(alloclen);
 781         idp->sadb_ident_reserved = 0;
 782         idp->sadb_ident_id = 0;
 783 
 784         /* now copy in identity param */
 785         (void) strlcpy((char *)(idp + 1), argv[1],
 786             alloclen - (sizeof (sadb_ident_t)));
 787 
 788         return (++consumed);
 789 }
 790 
 791 static int
 792 parse_cky(int argc, char **argv, uint64_t *ckyp)
 793 {
 794         u_longlong_t    arg;
 795 
 796         if ((argc < 1) || (argv[0] == NULL))
 797                 return (-1);
 798 
 799         errno = 0;
 800         arg = strtoull(argv[0], NULL, 0);
 801         if (errno != 0) {
 802                 message(gettext("failed to parse cookie %s."), argv[0]);
 803                 return (-1);
 804         }
 805 
 806         *ckyp = (uint64_t)arg;
 807 
 808         return (1);
 809 }
 810 
 811 static int
 812 parse_addr_pr(int argc, char **argv, struct hostent **h1pp,
 813         struct hostent **h2pp)
 814 {
 815         int     rtn, consumed = 0;
 816 
 817         if ((rtn = parse_addr(argc, argv, h1pp)) < 0) {
 818                 return (-1);
 819         }
 820         consumed = rtn;
 821         argc -= rtn;
 822         argv += rtn;
 823 
 824         if ((rtn = parse_addr(argc, argv, h2pp)) < 0) {
 825                 FREE_HE(*h1pp);
 826                 return (-1);
 827         }
 828         consumed += rtn;
 829 
 830         return (consumed);
 831 }
 832 
 833 /*
 834  * The sadb_ident_ts are malloc'd, since their length varies;
 835  * so the caller must free() them when done with the data.
 836  */
 837 static int
 838 parse_ident_pr(int argc, char **argv, sadb_ident_t **id1pp,
 839     sadb_ident_t **id2pp)
 840 {
 841         int     rtn, consumed = 0;
 842 
 843         if ((rtn = parse_ident(argc, argv, id1pp)) < 0) {
 844                 return (-1);
 845         }
 846         consumed = rtn;
 847         argc -= rtn;
 848         argv += rtn;
 849 
 850         (*id1pp)->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
 851 
 852         if ((rtn = parse_ident(argc, argv, id2pp)) < 0) {
 853                 free(*id1pp);
 854                 return (-1);
 855         }
 856         consumed += rtn;
 857 
 858         (*id2pp)->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
 859 
 860         return (consumed);
 861 }
 862 
 863 static int
 864 parse_cky_pr(int argc, char **argv, ike_cky_pr_t *cpr)
 865 {
 866         int     rtn, consumed = 0;
 867 
 868         if ((rtn = parse_cky(argc, argv, &cpr->cky_i)) < 0) {
 869                 return (-1);
 870         }
 871         consumed = rtn;
 872         argc -= rtn;
 873         argv += rtn;
 874 
 875         if ((rtn = parse_cky(argc, argv, &cpr->cky_r)) < 0) {
 876                 return (-1);
 877         }
 878         consumed += rtn;
 879 
 880         return (consumed);
 881 }
 882 
 883 /*
 884  * Preshared key field types...used for parsing preshared keys that
 885  * have been entered on the command line.  The code to parse preshared
 886  * keys (parse_ps, parse_key, parse_psfldid, parse_ikmtype, ...) is
 887  * mostly duplicated from in.iked's readps.c.
 888  */
 889 #define PSFLD_LOCID     1
 890 #define PSFLD_LOCIDTYPE 2
 891 #define PSFLD_REMID     3
 892 #define PSFLD_REMIDTYPE 4
 893 #define PSFLD_MODE      5
 894 #define PSFLD_KEY       6
 895 
 896 static keywdtab_t       psfldtypes[] = {
 897         {PSFLD_LOCID,           "localid"},
 898         {PSFLD_LOCIDTYPE,       "localidtype"},
 899         {PSFLD_REMID,           "remoteid"},
 900         {PSFLD_REMIDTYPE,       "remoteidtype"},
 901         {PSFLD_MODE,            "ike_mode"},
 902         {PSFLD_KEY,             "key"},
 903         {0, NULL}
 904 };
 905 
 906 static int
 907 parse_psfldid(char *type, uint16_t *idnum)
 908 {
 909         keywdtab_t      *pfp;
 910 
 911         if (type == NULL)
 912                 return (-1);
 913 
 914         for (pfp = psfldtypes; pfp->kw_str != NULL; pfp++) {
 915                 if (strcasecmp(pfp->kw_str, type) == 0) {
 916                         if (idnum != NULL)
 917                                 *idnum = pfp->kw_tag;
 918                         return (1);
 919                 }
 920         }
 921 
 922         return (-1);
 923 }
 924 
 925 static keywdtab_t       ikemodes[] = {
 926         {IKE_XCHG_IDENTITY_PROTECT,     "main"},
 927         {IKE_XCHG_AGGRESSIVE,           "aggressive"},
 928         {IKE_XCHG_IP_AND_AGGR,          "both"},
 929         {0, NULL}
 930 };
 931 
 932 static int
 933 parse_ikmtype(char *mode, uint16_t *modenum)
 934 {
 935         keywdtab_t      *ikmp;
 936 
 937         if (mode == NULL)
 938                 return (-1);
 939 
 940         for (ikmp = ikemodes; ikmp->kw_str != NULL; ikmp++) {
 941                 if (strcasecmp(ikmp->kw_str, mode) == 0) {
 942                         if (modenum != NULL)
 943                                 *modenum = ikmp->kw_tag;
 944                         return (1);
 945                 }
 946         }
 947 
 948         return (-1);
 949 }
 950 
 951 #define hd2num(hd) (((hd) >= '0' && (hd) <= '9') ? ((hd) - '0') : \
 952         (((hd) >= 'a' && (hd) <= 'f') ? ((hd) - 'a' + 10) : ((hd) - 'A' + 10)))
 953 
 954 static uint8_t *
 955 parse_key(char *input, uint_t *keybuflen, uint_t *lbits)
 956 {
 957         uint8_t *keyp, *keybufp;
 958         uint_t  i, hexlen = 0, bits, alloclen;
 959 
 960         for (i = 0; input[i] != '\0' && input[i] != '/'; i++)
 961                 hexlen++;
 962 
 963         if (input[i] == '\0') {
 964                 bits = 0;
 965         } else {
 966                 /* Have /nn. */
 967                 input[i] = '\0';
 968                 if (sscanf((input + i + 1), "%u", &bits) != 1)
 969                         return (NULL);
 970 
 971                 /* hexlen is in nibbles */
 972                 if (((bits + 3) >> 2) > hexlen)
 973                         return (NULL);
 974 
 975                 /*
 976                  * Adjust hexlen down if user gave us too small of a bit
 977                  * count.
 978                  */
 979                 if ((hexlen << 2) > bits + 3) {
 980                         hexlen = (bits + 3) >> 2;
 981                         input[hexlen] = '\0';
 982                 }
 983         }
 984 
 985         /*
 986          * Allocate.  Remember, hexlen is in nibbles.
 987          */
 988 
 989         alloclen = (hexlen/2 + (hexlen & 0x1));
 990         keyp = malloc(alloclen);
 991 
 992         if (keyp == NULL)
 993                 return (NULL);
 994 
 995         keybufp = keyp;
 996         *keybuflen = alloclen;
 997         if (bits == 0)
 998                 *lbits = (hexlen + (hexlen & 0x1)) << 2;
 999         else
1000                 *lbits = bits;
1001 
1002         /*
1003          * Read in nibbles.  Read in odd-numbered as shifted high.
1004          * (e.g. 123 becomes 0x1230).
1005          */
1006         for (i = 0; input[i] != '\0'; i += 2) {
1007                 boolean_t second = (input[i + 1] != '\0');
1008 
1009                 if (!isxdigit(input[i]) ||
1010                     (!isxdigit(input[i + 1]) && second)) {
1011                         free(keyp);
1012                         return (NULL);
1013                 }
1014                 *keyp = (hd2num(input[i]) << 4);
1015                 if (second)
1016                         *keyp |= hd2num(input[i + 1]);
1017                 else
1018                         break; /* out of for loop. */
1019                 keyp++;
1020         }
1021 
1022         /* zero the remaining bits if we're a non-octet amount. */
1023         if (bits & 0x7)
1024                 *((input[i] == '\0') ? keyp - 1 : keyp) &=
1025                     0xff << (8 - (bits & 0x7));
1026         return (keybufp);
1027 }
1028 
1029 /*
1030  * the ike_ps_t struct (plus trailing data) will be allocated here,
1031  * so it will need to be freed by the caller.
1032  */
1033 static int
1034 parse_ps(int argc, char **argv, ike_ps_t **presharedpp, int *len)
1035 {
1036         uint_t          c = 0, locidlen, remidlen, keylen, keybits;
1037         uint_t          a_locidtotal = 0, a_remidtotal = 0;
1038         char            *locid, *remid, *locpfx = NULL, *rempfx = NULL;
1039         uint8_t         *keyp = NULL;
1040         uint16_t        fldid, locidtype, remidtype, mtype;
1041         struct hostent  *loche = NULL, *remhe = NULL;
1042         ike_ps_t        *psp = NULL;
1043         sadb_ident_t    *sidp;
1044         boolean_t       whacked = B_FALSE;
1045         int pfxlen = 0;
1046 
1047         if ((argv[c] == NULL) || (argv[c][0] != '{'))
1048                 return (-1);
1049         if (argv[c][1] != 0) {
1050                 /* no space between '{' and first token */
1051                 argv[c]++;
1052         } else {
1053                 c++;
1054         }
1055         if ((argv[argc - 1][strlen(argv[argc - 1]) - 1] == '}') &&
1056             (argv[argc - 1][0] != '}')) {
1057                 /*
1058                  * whack '}' without a space before it or parsers break.
1059                  * Remember this trailing character for later
1060                  */
1061                 argv[argc - 1][strlen(argv[argc - 1]) - 1] = '\0';
1062                 whacked = B_TRUE;
1063         }
1064 
1065         /* Default to type IP */
1066         locidtype = remidtype = SADB_IDENTTYPE_RESERVED;
1067         /* Default to base exchanges */
1068         mtype = IKE_XCHG_BASE;
1069 
1070         while ((c < argc) && (argv[c] != NULL) && (argv[c][0] != '}')) {
1071                 if ((argv[c + 1] == NULL) || (argv[c + 1][0] == '}'))
1072                         goto bail;
1073                 if (parse_psfldid(argv[c++], &fldid) < 0)
1074                         goto bail;
1075                 switch (fldid) {
1076                 case PSFLD_LOCID:
1077                         locid = argv[c++];
1078                         locidlen = strlen(locid) + 1;
1079                         break;
1080                 case PSFLD_LOCIDTYPE:
1081                         if (parse_idtype(argv[c++], &locidtype) < 0)
1082                                 goto bail;
1083                         break;
1084                 case PSFLD_REMID:
1085                         remid = argv[c++];
1086                         remidlen = strlen(remid) + 1;
1087                         break;
1088                 case PSFLD_REMIDTYPE:
1089                         if (parse_idtype(argv[c++], &remidtype) < 0)
1090                                 goto bail;
1091                         break;
1092                 case PSFLD_MODE:
1093                         if (parse_ikmtype(argv[c++], &mtype) < 0)
1094                                 goto bail;
1095                         break;
1096                 case PSFLD_KEY:
1097                         keyp  = parse_key(argv[c++], &keylen, &keybits);
1098                         if (keyp == NULL)
1099                                 goto bail;
1100                         break;
1101                 }
1102         }
1103 
1104         /* Make sure the line was terminated with '}' */
1105         if (argv[c] == NULL) {
1106                 if (!whacked)
1107                         goto bail;
1108         } else if (argv[c][0] != '}') {
1109                 goto bail;
1110         }
1111 
1112         /*
1113          * make sure we got all the required fields.  If no idtype, assume
1114          * ip addr; if that translation fails, we'll catch the error then.
1115          */
1116         if (locid == NULL || remid == NULL || keyp == NULL || mtype == 0)
1117                 goto bail;
1118 
1119         /* figure out the size buffer we need */
1120         *len = sizeof (ike_ps_t);
1121         if (locidtype != SADB_IDENTTYPE_RESERVED) {
1122                 a_locidtotal = IKEDOORROUNDUP(sizeof (sadb_ident_t) + locidlen);
1123                 *len += a_locidtotal;
1124         }
1125         if (remidtype != SADB_IDENTTYPE_RESERVED) {
1126                 a_remidtotal = IKEDOORROUNDUP(sizeof (sadb_ident_t) + remidlen);
1127                 *len += a_remidtotal;
1128         }
1129         *len += keylen;
1130 
1131         psp = malloc(*len);
1132         if (psp == NULL)
1133                 goto bail;
1134         (void) memset(psp, 0, *len);
1135 
1136         psp->ps_ike_mode = mtype;
1137 
1138         psp->ps_localid_off = sizeof (ike_ps_t);
1139         if (locidtype == SADB_IDENTTYPE_RESERVED) {
1140                 locpfx = strchr(locid, '/');
1141                 if (locpfx != NULL) {
1142                         *locpfx = '\0';
1143                         locpfx++;
1144                 }
1145 
1146                 /*
1147                  * this is an ip address, store in the sockaddr field;
1148                  * we won't use an sadb_ident_t.
1149                  */
1150                 psp->ps_localid_len = 0;
1151                 if (parse_addr(1, &locid, &loche) < 0)
1152                         goto bail;
1153                 if (loche->h_addr_list[1] != NULL) {
1154                         message(gettext("preshared key identifier cannot "
1155                             "match multiple IP addresses"));
1156                         goto bail;
1157                 }
1158                 headdr2sa(loche->h_addr_list[0], &psp->ps_ipaddrs.loc_addr,
1159                     loche->h_length);
1160                 FREE_HE(loche);
1161         } else {
1162                 psp->ps_localid_len = sizeof (sadb_ident_t) + locidlen;
1163                 sidp = (sadb_ident_t *)((int)psp + psp->ps_localid_off);
1164                 sidp->sadb_ident_len = psp->ps_localid_len;
1165                 sidp->sadb_ident_type = locidtype;
1166                 (void) strlcpy((char *)(sidp + 1), locid, a_locidtotal);
1167         }
1168 
1169         psp->ps_remoteid_off = psp->ps_localid_off + a_locidtotal;
1170         if (remidtype == SADB_IDENTTYPE_RESERVED) {
1171                 rempfx = strchr(remid, '/');
1172                 if (rempfx != NULL) {
1173                         *rempfx = '\0';
1174                         rempfx++;
1175                 }
1176 
1177                 /*
1178                  * this is an ip address, store in the sockaddr field;
1179                  * we won't use an sadb_ident_t.
1180                  */
1181                 psp->ps_remoteid_len = 0;
1182                 if (parse_addr(1, &remid, &remhe) < 0)
1183                         goto bail;
1184                 if (remhe->h_addr_list[1] != NULL) {
1185                         message(gettext("preshared key identifier cannot "
1186                             "match multiple IP addresses"));
1187                         goto bail;
1188                 }
1189                 headdr2sa(remhe->h_addr_list[0], &psp->ps_ipaddrs.rem_addr,
1190                     remhe->h_length);
1191                 FREE_HE(remhe);
1192         } else {
1193                 /* make sure we have at least 16-bit alignment */
1194                 if (remidlen & 0x1)
1195                         remidlen++;
1196                 psp->ps_remoteid_len = sizeof (sadb_ident_t) + remidlen;
1197                 sidp = (sadb_ident_t *)((int)psp + psp->ps_remoteid_off);
1198                 sidp->sadb_ident_len = psp->ps_remoteid_len;
1199                 sidp->sadb_ident_type = remidtype;
1200                 (void) strlcpy((char *)(sidp + 1), remid, a_remidtotal);
1201         }
1202 
1203         psp->ps_key_off = psp->ps_remoteid_off + a_remidtotal;
1204         psp->ps_key_len = keylen;
1205         psp->ps_key_bits = keybits;
1206         (void) memcpy((uint8_t *)((int)psp + psp->ps_key_off), keyp, keylen);
1207         if (locpfx != NULL && ((pfxlen = atoi(locpfx)) > 0))
1208                 psp->ps_localid_plen = pfxlen;
1209         if (rempfx != NULL && ((pfxlen = atoi(rempfx)) > 0))
1210                 psp->ps_remoteid_plen = pfxlen;
1211 
1212         *presharedpp = psp;
1213 
1214         return (c);
1215 
1216 bail:
1217         if (loche != NULL)
1218                 FREE_HE(loche);
1219         if (remhe != NULL)
1220                 FREE_HE(remhe);
1221         if (keyp != NULL)
1222                 free(keyp);
1223         if (psp != NULL)
1224                 free(psp);
1225 
1226         *presharedpp = NULL;
1227 
1228         return (-1);
1229 }
1230 
1231 /*
1232  * Printing functions
1233  *
1234  * A potential point of confusion here is that the ikeadm-specific string-
1235  * producing functions do not match the ipsec_util.c versions in style: the
1236  * ikeadm-specific functions return a string (and are named foostr), while
1237  * the ipsec_util.c functions actually print the string to the file named
1238  * in the second arg to the function (and are named dump_foo).
1239  *
1240  * Localization for ikeadm seems more straightforward when complete
1241  * phrases are translated rather than: a part of a phrase, a call to
1242  * dump_foo(), and more of the phrase.  It could also accommodate
1243  * non-English grammar more easily.
1244  */
1245 
1246 static char *
1247 errstr(int err)
1248 {
1249         static char     rtn[MAXLINESIZE];
1250 
1251         switch (err) {
1252         case IKE_ERR_NO_OBJ:
1253                 return (gettext("No data returned"));
1254         case IKE_ERR_NO_DESC:
1255                 return (gettext("No destination provided"));
1256         case IKE_ERR_ID_INVALID:
1257                 return (gettext("Id info invalid"));
1258         case IKE_ERR_LOC_INVALID:
1259                 return (gettext("Destination invalid"));
1260         case IKE_ERR_CMD_INVALID:
1261                 return (gettext("Command invalid"));
1262         case IKE_ERR_DATA_INVALID:
1263                 return (gettext("Supplied data invalid"));
1264         case IKE_ERR_CMD_NOTSUP:
1265                 return (gettext("Unknown command"));
1266         case IKE_ERR_REQ_INVALID:
1267                 return (gettext("Request invalid"));
1268         case IKE_ERR_NO_PRIV:
1269                 return (gettext("Not allowed at current privilege level"));
1270         case IKE_ERR_NO_AUTH:
1271                 return (gettext("User not authorized"));
1272         case IKE_ERR_SYS_ERR:
1273                 return (gettext("System error"));
1274         case IKE_ERR_DUP_IGNORED:
1275                 return (gettext("One or more duplicate entries ignored"));
1276         case IKE_ERR_NO_TOKEN:
1277                 return (gettext(
1278                     "token login failed or no objects on device"));
1279         case IKE_ERR_IN_PROGRESS:
1280                 return (gettext(
1281                     "Duplicate operation already in progress"));
1282         case IKE_ERR_NO_MEM:
1283                 return (gettext(
1284                     "Insufficient memory"));
1285         default:
1286                 (void) snprintf(rtn, MAXLINESIZE,
1287                     gettext("<unknown error %d>"), err);
1288                 return (rtn);
1289         }
1290 }
1291 
1292 static char *
1293 dbgstr(int bit)
1294 {
1295         static char     rtn[MAXLINESIZE];
1296 
1297         switch (bit) {
1298         case D_CERT:
1299                 return (gettext("Certificate management"));
1300         case D_KEY:
1301                 return (gettext("Key management"));
1302         case D_OP:
1303                 return (gettext("Operational"));
1304         case D_P1:
1305                 return (gettext("Phase 1 SA creation"));
1306         case D_P2:
1307                 return (gettext("Phase 2 SA creation"));
1308         case D_PFKEY:
1309                 return (gettext("PF_KEY interface"));
1310         case D_POL:
1311                 return (gettext("Policy management"));
1312         case D_PROP:
1313                 return (gettext("Proposal construction"));
1314         case D_DOOR:
1315                 return (gettext("Door interface"));
1316         case D_CONFIG:
1317                 return (gettext("Config file processing"));
1318         case D_LABEL:
1319                 return (gettext("MAC label processing"));
1320         default:
1321                 (void) snprintf(rtn, MAXLINESIZE,
1322                     gettext("<unknown flag 0x%x>"), bit);
1323                 return (rtn);
1324         }
1325 }
1326 
1327 static char *
1328 privstr(int priv)
1329 {
1330         static char     rtn[MAXLINESIZE];
1331 
1332         switch (priv) {
1333         case IKE_PRIV_MINIMUM:
1334                 return (gettext("base privileges"));
1335         case IKE_PRIV_MODKEYS:
1336                 return (gettext("access to preshared key information"));
1337         case IKE_PRIV_KEYMAT:
1338                 return (gettext("access to keying material"));
1339         default:
1340                 (void) snprintf(rtn, MAXLINESIZE,
1341                     gettext("<unknown level %d>"), priv);
1342                 return (rtn);
1343         }
1344 }
1345 
1346 static char *
1347 xchgstr(int xchg)
1348 {
1349         static char     rtn[MAXLINESIZE];
1350 
1351         switch (xchg) {
1352         case IKE_XCHG_NONE:
1353                 return (gettext("<unspecified>"));
1354         case IKE_XCHG_BASE:
1355                 return (gettext("base"));
1356         case IKE_XCHG_IDENTITY_PROTECT:
1357                 return (gettext("main mode (identity protect)"));
1358         case IKE_XCHG_AUTH_ONLY:
1359                 return (gettext("authentication only"));
1360         case IKE_XCHG_AGGRESSIVE:
1361                 return (gettext("aggressive mode"));
1362         case IKE_XCHG_IP_AND_AGGR:
1363                 return (gettext("main and aggressive mode"));
1364         case IKE_XCHG_ANY:
1365                 return (gettext("any mode"));
1366         default:
1367                 (void) snprintf(rtn, MAXLINESIZE,
1368                     gettext("<unknown %d>"), xchg);
1369                 return (rtn);
1370         }
1371 }
1372 
1373 static char *
1374 statestr(int state)
1375 {
1376         static char     rtn[MAXLINESIZE];
1377 
1378         switch (state) {
1379         case IKE_SA_STATE_INIT:
1380                 return (gettext("INITIALIZING"));
1381         case IKE_SA_STATE_SENT_SA:
1382                 return (gettext("SENT FIRST MSG (SA)"));
1383         case IKE_SA_STATE_SENT_KE:
1384                 return (gettext("SENT SECOND MSG (KE)"));
1385         case IKE_SA_STATE_SENT_LAST:
1386                 return (gettext("SENT FINAL MSG"));
1387         case IKE_SA_STATE_DONE:
1388                 return (gettext("ACTIVE"));
1389         case IKE_SA_STATE_DELETED:
1390                 return (gettext("DELETED"));
1391         case IKE_SA_STATE_INVALID:
1392                 return (gettext("<invalid>"));
1393         default:
1394                 (void) snprintf(rtn, MAXLINESIZE,
1395                     gettext("<unknown %d>"), state);
1396                 return (rtn);
1397         }
1398 }
1399 
1400 static char *
1401 authmethstr(int meth)
1402 {
1403         static char     rtn[MAXLINESIZE];
1404 
1405         switch (meth) {
1406         case IKE_AUTH_METH_PRE_SHARED_KEY:
1407                 return (gettext("pre-shared key"));
1408         case IKE_AUTH_METH_DSS_SIG:
1409                 return (gettext("DSS signatures"));
1410         case IKE_AUTH_METH_RSA_SIG:
1411                 return (gettext("RSA signatures"));
1412         case IKE_AUTH_METH_RSA_ENCR:
1413                 return (gettext("RSA Encryption"));
1414         case IKE_AUTH_METH_RSA_ENCR_REVISED:
1415                 return (gettext("Revised RSA Encryption"));
1416         default:
1417                 (void) snprintf(rtn, MAXLINESIZE,
1418                     gettext("<unknown %d>"), meth);
1419                 return (rtn);
1420         }
1421 }
1422 
1423 static char *
1424 prfstr(int prf)
1425 {
1426         static char     rtn[MAXLINESIZE];
1427 
1428         switch (prf) {
1429         case IKE_PRF_NONE:
1430                 return (gettext("<none/unavailable>"));
1431         case IKE_PRF_HMAC_MD5:
1432                 return ("HMAC MD5");
1433         case IKE_PRF_HMAC_SHA1:
1434                 return ("HMAC SHA1");
1435         case IKE_PRF_HMAC_SHA256:
1436                 return ("HMAC SHA256");
1437         case IKE_PRF_HMAC_SHA384:
1438                 return ("HMAC SHA384");
1439         case IKE_PRF_HMAC_SHA512:
1440                 return ("HMAC SHA512");
1441         default:
1442                 (void) snprintf(rtn, MAXLINESIZE,
1443                     gettext("<unknown %d>"), prf);
1444                 return (rtn);
1445         }
1446 }
1447 
1448 static char *
1449 dhstr(int grp)
1450 {
1451         static char     rtn[MAXLINESIZE];
1452 
1453         switch (grp) {
1454         case 0:
1455                 return (gettext("<unavailable>"));
1456         case IKE_GRP_DESC_MODP_768:
1457                 return (gettext("768-bit MODP (group 1)"));
1458         case IKE_GRP_DESC_MODP_1024:
1459                 return (gettext("1024-bit MODP (group 2)"));
1460         case IKE_GRP_DESC_EC2N_155:
1461                 return (gettext("EC2N group on GP[2^155]"));
1462         case IKE_GRP_DESC_EC2N_185:
1463                 return (gettext("EC2N group on GP[2^185]"));
1464         case IKE_GRP_DESC_MODP_1536:
1465                 return (gettext("1536-bit MODP (group 5)"));
1466         case IKE_GRP_DESC_MODP_2048:
1467                 return (gettext("2048-bit MODP (group 14)"));
1468         case IKE_GRP_DESC_MODP_3072:
1469                 return (gettext("3072-bit MODP (group 15)"));
1470         case IKE_GRP_DESC_MODP_4096:
1471                 return (gettext("4096-bit MODP (group 16)"));
1472         case IKE_GRP_DESC_MODP_6144:
1473                 return (gettext("6144-bit MODP (group 17)"));
1474         case IKE_GRP_DESC_MODP_8192:
1475                 return (gettext("8192-bit MODP (group 18)"));
1476         case IKE_GRP_DESC_ECP_256:
1477                 return (gettext("256-bit ECP (group 19)"));
1478         case IKE_GRP_DESC_ECP_384:
1479                 return (gettext("384-bit ECP (group 20)"));
1480         case IKE_GRP_DESC_ECP_521:
1481                 return (gettext("521-bit ECP (group 21)"));
1482         case IKE_GRP_DESC_MODP_1024_160:
1483                 return (
1484                     gettext("1024-bit MODP with 160-bit subprime (group 22)"));
1485         case IKE_GRP_DESC_MODP_2048_224:
1486                 return (
1487                     gettext("2048-bit MODP with 224-bit subprime (group 23)"));
1488         case IKE_GRP_DESC_MODP_2048_256:
1489                 return (
1490                     gettext("2048-bit MODP with 256-bit subprime (group 24)"));
1491         case IKE_GRP_DESC_ECP_192:
1492                 return (gettext("192-bit ECP (group 25)"));
1493         case IKE_GRP_DESC_ECP_224:
1494                 return (gettext("224-bit ECP (group 26)"));
1495         default:
1496                 (void) snprintf(rtn, MAXLINESIZE, gettext("<unknown %d>"), grp);
1497                 return (rtn);
1498         }
1499 }
1500 
1501 static void
1502 print_hdr(char *prefix, ike_p1_hdr_t *hdrp)
1503 {
1504         char sbuf[TBUF_SIZE];
1505         char tbuf[TBUF_SIZE];
1506         time_t ltime = (time_t)hdrp->p1hdr_dpd_time;
1507 
1508         (void) printf(
1509             gettext("%s Cookies: Initiator 0x%llx  Responder 0x%llx\n"),
1510             prefix, ntohll(hdrp->p1hdr_cookies.cky_i),
1511             ntohll(hdrp->p1hdr_cookies.cky_r));
1512         (void) printf(gettext("%s The local host is the %s.\n"), prefix,
1513             hdrp->p1hdr_isinit ? gettext("initiator") : gettext("responder"));
1514         (void) printf(gettext("%s ISAKMP version %d.%d; %s exchange\n"), prefix,
1515             hdrp->p1hdr_major, hdrp->p1hdr_minor, xchgstr(hdrp->p1hdr_xchg));
1516         (void) printf(gettext("%s Current state is %s\n"), prefix,
1517             statestr(hdrp->p1hdr_state));
1518         if (hdrp->p1hdr_support_dpd == B_FALSE) {
1519                 return;
1520         }
1521         (void) printf(gettext("%s Dead Peer Detection (RFC 3706)"
1522             " enabled"), prefix);
1523         if (hdrp->p1hdr_dpd_state < DPD_IN_PROGRESS) {
1524                 (void) printf("\n");
1525                 return;
1526         }
1527         if (strftime(tbuf, TBUF_SIZE, NULL,
1528             localtime(&ltime)) == 0) {
1529                 (void) strlcpy(tbuf, gettext("<time conversion failed>"),
1530                     TBUF_SIZE);
1531         }
1532         (void) printf(gettext("\n%s Dead Peer Detection handshake "), prefix);
1533         switch (hdrp->p1hdr_dpd_state) {
1534         case DPD_SUCCESSFUL:
1535                 (void) strlcpy(sbuf, gettext("was successful at "), TBUF_SIZE);
1536                 break;
1537         case DPD_FAILURE:
1538                 (void) strlcpy(sbuf, gettext("failed at "), TBUF_SIZE);
1539                 break;
1540         case DPD_IN_PROGRESS:
1541                 (void) strlcpy(sbuf, gettext("is in progress."), TBUF_SIZE);
1542                 break;
1543         }
1544         (void) printf("%s %s", sbuf,
1545             (hdrp->p1hdr_dpd_state == DPD_IN_PROGRESS) ? "" : tbuf);
1546         (void) printf("\n");
1547 }
1548 
1549 static void
1550 print_lt_limits(char *prefix, ike_p1_xform_t *xfp)
1551 {
1552         char byte_str[BYTE_STR_SIZE]; /* byte lifetime string representation */
1553         char secs_str[SECS_STR_SIZE]; /* lifetime string representation */
1554 
1555         (void) printf(gettext("%s Lifetime limits:\n"), prefix);
1556         (void) printf(gettext("%s %u seconds%s; %u kbytes %sprotected\n"),
1557             prefix, xfp->p1xf_max_secs, secs2out(xfp->p1xf_max_secs,
1558             secs_str, sizeof (secs_str), SPC_BEGIN), xfp->p1xf_max_kbytes,
1559             bytecnt2out((uint64_t)xfp->p1xf_max_kbytes << 10, byte_str,
1560             sizeof (byte_str), SPC_END));
1561         (void) printf(gettext("%s keying material for IPsec SAs can be "
1562             "provided %u times%s\n"), prefix, xfp->p1xf_max_keyuses,
1563             xfp->p1xf_max_keyuses == 0 ? " (no limit)" : "");
1564 }
1565 
1566 #define LT_USAGE_LEN    16      /* 1 uint64 + 2 uint32s */
1567 static void
1568 print_lt_usage(char *prefix, ike_p1_stats_t *sp)
1569 {
1570         time_t  scratch;
1571         char    tbuf[TBUF_SIZE];
1572         char    bytestr[BYTE_STR_SIZE]; /* byte lifetime representation */
1573 
1574         (void) printf(gettext("%s Current usage:\n"), prefix);
1575         scratch = (time_t)sp->p1stat_start;
1576         if (strftime(tbuf, TBUF_SIZE, NULL, localtime(&scratch)) == 0)
1577                 (void) strlcpy(tbuf, gettext("<time conversion failed>"),
1578                     TBUF_SIZE);
1579         (void) printf(gettext("%s SA was created at %s\n"), prefix, tbuf);
1580         (void) printf(gettext("%s %u kbytes %sprotected\n"),
1581             prefix, sp->p1stat_kbytes,
1582             bytecnt2out((uint64_t)sp->p1stat_kbytes << 10, bytestr,
1583             sizeof (bytestr), SPC_END));
1584         (void) printf(gettext("%s keying material for IPsec SAs provided "
1585             "%u times\n"), prefix, sp->p1stat_keyuses);
1586 }
1587 
1588 static void
1589 print_xform(char *prefix, ike_p1_xform_t *xfp, boolean_t print_lifetimes)
1590 {
1591         (void) printf(gettext("%s Authentication method: %s"), prefix,
1592             authmethstr(xfp->p1xf_auth_meth));
1593         (void) printf(gettext("\n%s Encryption alg: "), prefix);
1594         (void) dump_ealg(xfp->p1xf_encr_alg, stdout);
1595         if (xfp->p1xf_encr_low_bits != 0) {
1596                 (void) printf(gettext("(%d..%d)"), xfp->p1xf_encr_low_bits,
1597                     xfp->p1xf_encr_high_bits);
1598         } else if ((xfp->p1xf_encr_low_bits == 0) &&
1599             (xfp->p1xf_encr_high_bits != 0)) {
1600                 /*
1601                  * High bits is a placeholder for
1602                  * negotiated algorithm strength
1603                  */
1604                 (void) printf(gettext("(%d)"), xfp->p1xf_encr_high_bits);
1605         }
1606         (void) printf(gettext("; Authentication alg: "));
1607         (void) dump_aalg(xfp->p1xf_auth_alg, stdout);
1608         (void) printf("\n%s ", prefix);
1609         if (xfp->p1xf_prf != 0)
1610                 (void) printf(gettext("PRF: %s ; "), prfstr(xfp->p1xf_prf));
1611         (void) printf(gettext("Oakley Group: %s\n"),
1612             dhstr(xfp->p1xf_dh_group));
1613         if (xfp->p1xf_pfs == 0) {
1614                 (void) printf(gettext("%s Phase 2 PFS is not used\n"), prefix);
1615         } else {
1616                 (void) printf(gettext(
1617                     "%s Phase 2 PFS is required (Oakley Group: %s)\n"),
1618                     prefix, dhstr(xfp->p1xf_pfs));
1619         }
1620 
1621         if (print_lifetimes)
1622                 print_lt_limits(prefix, xfp);
1623 }
1624 
1625 static void
1626 print_lifetime(char *prefix, ike_p1_xform_t *xfp, ike_p1_stats_t *sp,
1627     int statlen)
1628 {
1629         time_t  current, remain, exp;
1630         char    tbuf[TBUF_SIZE];
1631         char    byte_str[BYTE_STR_SIZE]; /* byte lifetime representation */
1632         char    secs_str[SECS_STR_SIZE]; /* seconds lifetime representation */
1633 
1634         current = time(NULL);
1635 
1636         print_lt_limits(prefix, xfp);
1637 
1638         /*
1639          * make sure the stats struct we've been passed is as big
1640          * as we expect it to be.  The usage stats are at the end,
1641          * so anything less than the size we expect won't work.
1642          */
1643         if (statlen >= sizeof (ike_p1_stats_t)) {
1644                 print_lt_usage(prefix, sp);
1645         } else {
1646                 return;
1647         }
1648 
1649         (void) printf(gettext("%s Expiration info:\n"), prefix);
1650 
1651         if (xfp->p1xf_max_kbytes != 0)
1652                 (void) printf(gettext("%s %u more bytes %scan be "
1653                     "protected.\n"),
1654                     prefix, xfp->p1xf_max_kbytes - sp->p1stat_kbytes,
1655                     bytecnt2out((uint64_t)(xfp->p1xf_max_kbytes -
1656                     sp->p1stat_kbytes) << 10, byte_str, sizeof (byte_str),
1657                     SPC_END));
1658 
1659         if (xfp->p1xf_max_keyuses != 0)
1660                 (void) printf(gettext("%s Keying material can be provided "
1661                     "%u more times.\n"), prefix,
1662                     xfp->p1xf_max_keyuses - sp->p1stat_keyuses);
1663 
1664         if (xfp->p1xf_max_secs != 0) {
1665                 exp = (time_t)sp->p1stat_start + (time_t)xfp->p1xf_max_secs;
1666                 remain = exp - current;
1667                 if (strftime(tbuf, TBUF_SIZE, NULL, localtime(&exp)) == 0)
1668                         (void) strlcpy(tbuf,
1669                             gettext("<time conversion failed>"), TBUF_SIZE);
1670                 /*
1671                  * The SA may have expired but still exist because libike
1672                  * has not freed it yet.
1673                  */
1674                 if (remain > 0) {
1675                         (void) printf(gettext(
1676                             "%s SA expires in %lu seconds%s\n"),
1677                             prefix, remain, secs2out(remain, secs_str,
1678                             sizeof (secs_str), SPC_BEGIN));
1679                         (void) printf(gettext("%s Time of expiration: %s\n"),
1680                             prefix, tbuf);
1681                 } else {
1682                         (void) printf(gettext("%s SA Expired at %s\n"),
1683                             prefix, tbuf);
1684                 }
1685         }
1686 }
1687 
1688 /* used to verify structure lengths... */
1689 #define COUNTER_32BIT   4
1690 #define COUNTER_PAIR    8
1691 
1692 static void
1693 print_p1stats(char *prefix, ike_p1_stats_t *sp, int statlen,
1694     boolean_t print_lifetimes)
1695 {
1696         if (statlen < COUNTER_PAIR)
1697                 return;
1698         (void) printf(gettext("%s %u Quick Mode SAs created; "), prefix,
1699             sp->p1stat_new_qm_sas);
1700         (void) printf(gettext("%u Quick Mode SAs deleted\n"),
1701             sp->p1stat_del_qm_sas);
1702         statlen -= COUNTER_PAIR;
1703 
1704         if ((print_lifetimes) && (statlen >= LT_USAGE_LEN))
1705                 print_lt_usage(prefix, sp);
1706 }
1707 
1708 static void
1709 print_errs(char *prefix, ike_p1_errors_t *errp, int errlen)
1710 {
1711         /*
1712          * Don't try to break this one up; it's either all or nothing!
1713          */
1714         if (errlen < sizeof (ike_p1_errors_t))
1715                 return;
1716 
1717         (void) printf(gettext("%s %u RX errors: "), prefix,
1718             errp->p1err_decrypt + errp->p1err_hash + errp->p1err_otherrx);
1719         (void) printf(gettext("%u decryption, %u hash, %u other\n"),
1720             errp->p1err_decrypt, errp->p1err_hash, errp->p1err_otherrx);
1721         (void) printf(gettext("%s %u TX errors\n"), prefix, errp->p1err_tx);
1722 }
1723 
1724 static void
1725 print_addr_range(char *prefix, ike_addr_pr_t *pr)
1726 {
1727         boolean_t       range = B_TRUE;
1728         struct sockaddr_storage *beg, *end;
1729         struct sockaddr_in      *bsin, *esin;
1730         struct sockaddr_in6     *bsin6, *esin6;
1731 
1732         beg = &pr->beg_iprange;
1733         end = &pr->end_iprange;
1734 
1735         if (beg->ss_family != end->ss_family) {
1736                 (void) printf(gettext("%s invalid address range\n"), prefix);
1737                 return;
1738         }
1739 
1740         switch (beg->ss_family) {
1741         case AF_INET:
1742                 bsin = (struct sockaddr_in *)beg;
1743                 esin = (struct sockaddr_in *)end;
1744                 if ((uint32_t)bsin->sin_addr.s_addr ==
1745                     (uint32_t)esin->sin_addr.s_addr)
1746                         range = B_FALSE;
1747                 break;
1748         case AF_INET6:
1749                 bsin6 = (struct sockaddr_in6 *)beg;
1750                 esin6 = (struct sockaddr_in6 *)end;
1751                 if (IN6_ARE_ADDR_EQUAL(&bsin6->sin6_addr, &esin6->sin6_addr))
1752                         range = B_FALSE;
1753                 break;
1754         default:
1755                 (void) printf(gettext("%s invalid address range\n"), prefix);
1756                 return;
1757         }
1758 
1759         (void) printf("%s ", prefix);
1760         (void) dump_sockaddr((struct sockaddr *)beg, 0, B_TRUE, stdout, nflag);
1761         if (range) {
1762                 (void) printf(" - ");
1763                 (void) dump_sockaddr((struct sockaddr *)end, 0, B_TRUE, stdout,
1764                     nflag);
1765         }
1766         (void) printf("\n");
1767 
1768 }
1769 
1770 /*
1771  * used to tell printing function if info should be identified
1772  * as belonging to initiator, responder, or neither
1773  */
1774 #define IS_INITIATOR    1
1775 #define IS_RESPONDER    2
1776 #define DONT_PRINT_INIT 3
1777 
1778 static void
1779 print_addr(char *prefix, struct sockaddr_storage *sa, int init_instr,
1780     int mask)
1781 {
1782         (void) printf(gettext("%s Address"), prefix);
1783 
1784         if (init_instr != DONT_PRINT_INIT)
1785                 (void) printf(" (%s):\n", (init_instr == IS_INITIATOR) ?
1786                     gettext("Initiator") : gettext("Responder"));
1787         else
1788                 (void) printf(":\n");
1789 
1790         (void) printf("%s ", prefix);
1791         (void) dump_sockaddr((struct sockaddr *)sa, mask, B_FALSE, stdout,
1792             nflag);
1793 }
1794 
1795 static void
1796 print_id(char *prefix, sadb_ident_t *idp, int init_instr)
1797 {
1798         boolean_t       canprint;
1799 
1800         switch (init_instr) {
1801         case IS_INITIATOR:
1802                 (void) printf(gettext("%s Initiator identity, "), prefix);
1803                 break;
1804         case IS_RESPONDER:
1805                 (void) printf(gettext("%s Responder identity, "), prefix);
1806                 break;
1807         case DONT_PRINT_INIT:
1808                 (void) printf(gettext("%s Identity, "), prefix);
1809                 break;
1810         default:
1811                 (void) printf(gettext("<invalid identity>\n"));
1812                 return;
1813         }
1814         (void) printf(gettext("uid=%d, type "), idp->sadb_ident_id);
1815         canprint = dump_sadb_idtype(idp->sadb_ident_type, stdout, NULL);
1816         if (canprint) {
1817                 (void) printf("\n%s %s\n", prefix, (char *)(idp + 1));
1818         } else {
1819                 (void) printf(gettext("\n%s "), prefix);
1820                 print_asn1_name(stdout,
1821                     (const unsigned char *)(idp + 1),
1822                     SADB_64TO8(idp->sadb_ident_len) - sizeof (sadb_ident_t));
1823         }
1824 }
1825 
1826 static void
1827 print_idspec(char *prefix, char *idp, int icnt, int ecnt)
1828 {
1829         int     i;
1830 
1831         (void) printf(gettext("%s Identity descriptors:\n"), prefix);
1832 
1833         for (i = 0; i < icnt; i++) {
1834                 if (i == 0)
1835                         (void) printf(gettext("%s Includes:\n"), prefix);
1836                 (void) printf("%s    %s\n", prefix, idp);
1837                 idp += strlen(idp) + 1;
1838         }
1839 
1840         for (i = 0; i < ecnt; i++) {
1841                 if (i == 0)
1842                         (void) printf(gettext("%s Excludes:\n"), prefix);
1843                 (void) printf("%s    %s\n", prefix, idp);
1844                 idp += strlen(idp) + 1;
1845         }
1846 }
1847 
1848 static void
1849 print_keys(char *prefix, ike_p1_key_t *keyp, int size)
1850 {
1851         uint32_t        *curp;
1852         ike_p1_key_t    *p;
1853         int             ssize;
1854 
1855         curp = (uint32_t *)keyp;
1856 
1857         ssize = sizeof (ike_p1_key_t);
1858 
1859         while ((intptr_t)curp - (intptr_t)keyp < size) {
1860                 size_t p1klen, len;
1861 
1862                 p = (ike_p1_key_t *)curp;
1863                 p1klen = p->p1key_len;
1864                 len = p1klen - ssize;
1865 
1866                 p1klen = roundup(p1klen, sizeof (ike_p1_key_t));
1867                 if (p1klen < ssize) {
1868                         (void) printf(gettext("Short key\n"));
1869                         break;
1870                 }
1871 
1872                 switch (p->p1key_type) {
1873                 case IKE_KEY_PRESHARED:
1874                         (void) printf(gettext("%s Pre-shared key (%d bytes): "),
1875                             prefix, len);
1876                         break;
1877                 case IKE_KEY_SKEYID:
1878                         (void) printf(gettext("%s SKEYID (%d bytes): "),
1879                             prefix, len);
1880                         break;
1881                 case IKE_KEY_SKEYID_D:
1882                         (void) printf(gettext("%s SKEYID_d (%d bytes): "),
1883                             prefix, len);
1884                         break;
1885                 case IKE_KEY_SKEYID_A:
1886                         (void) printf(gettext("%s SKEYID_a (%d bytes): "),
1887                             prefix, len);
1888                         break;
1889                 case IKE_KEY_SKEYID_E:
1890                         (void) printf(gettext("%s SKEYID_e (%d bytes): "),
1891                             prefix, len);
1892                         break;
1893                 case IKE_KEY_ENCR:
1894                         (void) printf(gettext("%s Encryption key (%d bytes): "),
1895                             prefix, len);
1896                         break;
1897                 case IKE_KEY_IV:
1898                         (void) printf(
1899                             gettext("%s Initialization vector (%d bytes): "),
1900                             prefix, len);
1901                         break;
1902                 default:
1903                         (void) printf(gettext("%s Unidentified key info %p %d"),
1904                             prefix, p, p1klen);
1905                         goto badkey;
1906                 }
1907                 (void) dump_key((uint8_t *)(p + 1), SADB_8TO1(len), 0,
1908                     stdout, B_FALSE);
1909 badkey:
1910                 (void) printf("\n");
1911                 assert(IS_P2ALIGNED(p1klen, 8));
1912                 curp += (p1klen >> 2);
1913         }
1914 }
1915 
1916 static void
1917 print_group_header(void)
1918 {
1919         (void) printf(gettext("\nList of Diffie-Hellman groups for setting "
1920             "up IKE SAs"));
1921         (void) printf(gettext("\nThe values match the IPsec attribute "
1922             "assigned numbers published by IANA\n\n"));
1923         (void) printf("%-6s%-9s%-50s\n",
1924             gettext("Value"), gettext("Strength"), gettext("Description"));
1925 }
1926 
1927 static void
1928 print_group(ike_group_t *gp)
1929 {
1930         (void) printf("%-6u%-9u%-50s\n",
1931             gp->group_number, gp->group_bits, gp->group_label);
1932 }
1933 
1934 static void
1935 print_encralg_header(void)
1936 {
1937         (void) printf(gettext("\nList of encryption algorithms for IKE"));
1938         (void) printf(gettext("\nThe values match the IPsec attribute "
1939             "assigned numbers published by IANA\n\n"));
1940         (void) printf("%-6s%-20s%-15s\n", gettext("Value"),
1941             gettext("Name"), gettext("Keylen range"));
1942 }
1943 
1944 static void
1945 print_encralg(ike_encralg_t *ep)
1946 {
1947         char keylen_str[16];
1948 
1949         (void) strlcpy(keylen_str, "N/A", sizeof (keylen_str));
1950         if (ep->encr_keylen_min != 0 || ep->encr_keylen_max != 0)
1951                 (void) snprintf(keylen_str, sizeof (keylen_str), "%d-%d",
1952                     ep->encr_keylen_min, ep->encr_keylen_max);
1953         (void) printf("%-6u%-20s%-15s\n",
1954             ep->encr_value, ep->encr_name, keylen_str);
1955 }
1956 
1957 static void
1958 print_authalg_header(void)
1959 {
1960         (void) printf(gettext("\nList of authentication algorithms for IKE"));
1961         (void) printf(gettext("\nThe values match the IPsec attribute "
1962             "assigned numbers published by IANA\n\n"));
1963         (void) printf("%-6s%-20s\n", gettext("Value"), gettext("Name"));
1964 }
1965 
1966 static void
1967 print_authalg(ike_authalg_t *ap)
1968 {
1969         (void) printf("%-6u%-20s\n",
1970             ap->auth_value, ap->auth_name);
1971 }
1972 
1973 static void
1974 print_p1(ike_p1_sa_t *p1)
1975 {
1976         ike_p1_stats_t  *sp;
1977         ike_p1_errors_t *ep;
1978         ike_p1_key_t    *kp;
1979         sadb_ident_t    *lidp, *ridp;
1980         int             lstat, rstat;
1981 
1982         (void) printf("\n");
1983         print_hdr("IKESA:", &p1->p1sa_hdr);
1984         print_xform("XFORM:", &p1->p1sa_xform, B_FALSE);
1985 
1986         if (p1->p1sa_hdr.p1hdr_isinit) {
1987                 lstat = IS_INITIATOR;
1988                 rstat = IS_RESPONDER;
1989         } else {
1990                 lstat = IS_RESPONDER;
1991                 rstat = IS_INITIATOR;
1992         }
1993         print_addr("LOCIP:", &p1->p1sa_ipaddrs.loc_addr, lstat, 0);
1994         print_addr("REMIP:", &p1->p1sa_ipaddrs.rem_addr, rstat, 0);
1995 
1996         /*
1997          * the stat len might be 0; but still make the call
1998          * to print_lifetime() to pick up the xform info
1999          */
2000         sp = (ike_p1_stats_t *)((int)(p1) + p1->p1sa_stat_off);
2001         print_lifetime("LIFTM:", &p1->p1sa_xform, sp, p1->p1sa_stat_len);
2002 
2003         if (p1->p1sa_stat_len > 0) {
2004                 print_p1stats("STATS:", sp, p1->p1sa_stat_len, B_FALSE);
2005         }
2006 
2007         if (p1->p1sa_error_len > 0) {
2008                 ep = (ike_p1_errors_t *)((int)(p1) + p1->p1sa_error_off);
2009                 print_errs("ERRS: ", ep, p1->p1sa_error_len);
2010         }
2011 
2012         if (p1->p1sa_localid_len > 0) {
2013                 lidp = (sadb_ident_t *)((int)(p1) + p1->p1sa_localid_off);
2014                 print_id("LOCID:", lidp, lstat);
2015         }
2016 
2017         if (p1->p1sa_remoteid_len > 0) {
2018                 ridp = (sadb_ident_t *)((int)(p1) + p1->p1sa_remoteid_off);
2019                 print_id("REMID:", ridp, rstat);
2020         }
2021 
2022         if (p1->p1sa_key_len > 0) {
2023                 kp = (ike_p1_key_t *)((int)(p1) + p1->p1sa_key_off);
2024                 print_keys("KEY:  ", kp, p1->p1sa_key_len);
2025         }
2026 }
2027 
2028 static void
2029 print_certcache(ike_certcache_t *c)
2030 {
2031         (void) printf("\n");
2032 
2033         (void) printf(gettext("CERTIFICATE CACHE ID: %d\n"), c->cache_id);
2034         (void) printf(gettext("\tSubject Name: <%s>\n"),
2035             (c->subject != NULL) ? c->subject : gettext("Name unavailable"));
2036         (void) printf(gettext("\t Issuer Name: <%s>\n"),
2037             (c->issuer != NULL) ? c->issuer : gettext("Name unavailable"));
2038         if ((int)c->certclass == -1)
2039                 (void) printf(gettext("\t\t[trusted certificate]\n"));
2040         switch (c->linkage) {
2041         case CERT_OFF_WIRE:
2042                 (void) printf(gettext("\t\t[Public certificate only]\n"));
2043                 (void) printf(gettext(
2044                     "\t\t[Obtained via certificate payload]\n"));
2045                 break;
2046         case CERT_NO_PRIVKEY:
2047                 (void) printf(gettext("\t\t[Public certificate only]\n"));
2048                 break;
2049         case CERT_PRIVKEY_LOCKED:
2050                 (void) printf(gettext(
2051                     "\t\t[Private key linked but locked]\n"));
2052                 break;
2053         case CERT_PRIVKEY_AVAIL:
2054                 (void) printf(gettext("\t\t[Private key available]\n"));
2055                 break;
2056         }
2057 }
2058 
2059 static void
2060 print_ps(ike_ps_t *ps)
2061 {
2062         sadb_ident_t    *lidp, *ridp;
2063         uint8_t         *keyp;
2064 
2065         (void) printf("\n");
2066 
2067         (void) printf(gettext("PSKEY: For %s exchanges\n"),
2068             xchgstr(ps->ps_ike_mode));
2069 
2070         if (ps->ps_key_len > 0) {
2071                 keyp = (uint8_t *)((int)(ps) + ps->ps_key_off);
2072                 (void) printf(gettext("PSKEY: Pre-shared key (%d bytes): "),
2073                     ps->ps_key_len);
2074                 (void) dump_key(keyp, ps->ps_key_bits, 0, stdout, B_FALSE);
2075                 (void) printf("\n");
2076         }
2077 
2078         /*
2079          * We get *either* and address or an ident, never both.  So if
2080          * the ident is there, don't try printing an address.
2081          */
2082         if (ps->ps_localid_len > 0) {
2083                 lidp = (sadb_ident_t *)
2084                     ((int)(ps) + ps->ps_localid_off);
2085                 print_id("LOCID:", lidp, DONT_PRINT_INIT);
2086         } else {
2087                 print_addr("LOCIP:", &ps->ps_ipaddrs.loc_addr, DONT_PRINT_INIT,
2088                     ps->ps_localid_plen > 0 ? ps->ps_localid_plen : 0);
2089         }
2090 
2091         if (ps->ps_remoteid_len > 0) {
2092                 ridp = (sadb_ident_t *)
2093                     ((int)(ps) + ps->ps_remoteid_off);
2094                 print_id("REMID:", ridp, DONT_PRINT_INIT);
2095         } else {
2096                 print_addr("REMIP:", &ps->ps_ipaddrs.rem_addr, DONT_PRINT_INIT,
2097                     ps->ps_remoteid_plen > 0 ? ps->ps_remoteid_plen : 0);
2098         }
2099 }
2100 
2101 #define PREFIXLEN       16
2102 
2103 static void
2104 print_rule(ike_rule_t *rp)
2105 {
2106         char            prefix[PREFIXLEN];
2107         int             i;
2108         ike_p1_xform_t  *xfp;
2109         ike_addr_pr_t   *lipp, *ripp;
2110         char            *lidp, *ridp;
2111         char byte_str[BYTE_STR_SIZE]; /* kbyte string representation */
2112         char secs_str[SECS_STR_SIZE]; /* seconds string representation */
2113 
2114         (void) printf("\n");
2115         (void) printf(gettext("GLOBL: Label '%s', key manager cookie %u\n"),
2116             rp->rule_label, rp->rule_kmcookie);
2117         (void) printf(gettext("GLOBL: local_idtype="));
2118         (void) dump_sadb_idtype(rp->rule_local_idtype, stdout, NULL);
2119         (void) printf(gettext(", ike_mode=%s\n"), xchgstr(rp->rule_ike_mode));
2120         (void) printf(gettext(
2121             "GLOBL: p1_nonce_len=%u, p2_nonce_len=%u, p2_pfs=%s (group %u)\n"),
2122             rp->rule_p1_nonce_len, rp->rule_p2_nonce_len,
2123             (rp->rule_p2_pfs) ? gettext("true") : gettext("false"),
2124             rp->rule_p2_pfs);
2125         (void) printf(
2126             gettext("GLOBL: p2_lifetime=%u seconds%s\n"),
2127             rp->rule_p2_lifetime_secs, secs2out(rp->rule_p2_lifetime_secs,
2128             secs_str, sizeof (secs_str), SPC_BEGIN));
2129         (void) printf(
2130             gettext("GLOBL: p2_softlife=%u seconds%s\n"),
2131             rp->rule_p2_softlife_secs, secs2out(rp->rule_p2_softlife_secs,
2132             secs_str, sizeof (secs_str), SPC_BEGIN));
2133         (void) printf(
2134             gettext("GLOBL: p2_idletime=%u seconds%s\n"),
2135             rp->rule_p2_idletime_secs, secs2out(rp->rule_p2_idletime_secs,
2136             secs_str, sizeof (secs_str), SPC_BEGIN));
2137         /*
2138          * Perform explicit conversion before passing to bytecnt2out()
2139          * to avoid integer overflow.
2140          */
2141         (void) printf(
2142             gettext("GLOBL: p2_lifetime_kb=%u kilobytes%s\n"),
2143             rp->rule_p2_lifetime_kb,
2144             bytecnt2out((uint64_t)(rp->rule_p2_lifetime_kb) << 10,
2145             byte_str, sizeof (byte_str), SPC_BEGIN));
2146         (void) printf(
2147             gettext("GLOBL: p2_softlife_kb=%u kilobytes%s\n"),
2148             rp->rule_p2_softlife_kb,
2149             bytecnt2out(((uint64_t)(rp->rule_p2_softlife_kb)) << 10,
2150             byte_str, sizeof (byte_str), SPC_BEGIN));
2151 
2152         if (rp->rule_locip_cnt > 0) {
2153                 (void) printf(gettext("LOCIP: IP address range(s):\n"));
2154                 lipp = (ike_addr_pr_t *)((int)rp + rp->rule_locip_off);
2155                 for (i = 0; i < rp->rule_locip_cnt; i++, lipp++) {
2156                         print_addr_range("LOCIP:", lipp);
2157                 }
2158         }
2159 
2160         if (rp->rule_remip_cnt > 0) {
2161                 (void) printf(gettext("REMIP: IP address range(s):\n"));
2162                 ripp = (ike_addr_pr_t *)((int)rp + rp->rule_remip_off);
2163                 for (i = 0; i < rp->rule_remip_cnt; i++, ripp++) {
2164                         print_addr_range("REMIP:", ripp);
2165                 }
2166         }
2167 
2168         if (rp->rule_locid_inclcnt + rp->rule_locid_exclcnt > 0) {
2169                 lidp = (char *)((int)rp + rp->rule_locid_off);
2170                 print_idspec("LOCID:", lidp, rp->rule_locid_inclcnt,
2171                     rp->rule_locid_exclcnt);
2172         }
2173 
2174         if (rp->rule_remid_inclcnt + rp->rule_remid_exclcnt > 0) {
2175                 ridp = (char *)((int)rp + rp->rule_remid_off);
2176                 print_idspec("REMID:", ridp, rp->rule_remid_inclcnt,
2177                     rp->rule_remid_exclcnt);
2178         }
2179 
2180         if (rp->rule_xform_cnt > 0) {
2181                 (void) printf(gettext("XFRMS: Available Transforms:\n"));
2182                 xfp = (ike_p1_xform_t *)((int)rp +  rp->rule_xform_off);
2183                 for (i = 0; i < rp->rule_xform_cnt; i++, xfp++) {
2184                         (void) snprintf(prefix, PREFIXLEN, "XF %2u:", i);
2185                         print_xform(prefix, xfp, B_TRUE);
2186                 }
2187         }
2188 }
2189 
2190 #undef  PREFIXLEN
2191 
2192 #define PRSACNTS(init, resp) \
2193                 (void) printf(gettext("initiator: %10u   responder: %10u\n"), \
2194                     (init), (resp))
2195 
2196 static void
2197 print_stats(ike_stats_t *sp, int len)
2198 {
2199         /*
2200          * before printing each line, make sure the structure we were
2201          * given is big enough to include the fields needed.
2202          */
2203         if (len < COUNTER_PAIR)
2204                 return;
2205         (void) printf(gettext("Phase 1 SA counts:\n"));
2206         (void) printf(gettext("Current:   "));
2207         PRSACNTS(sp->st_init_p1_current, sp->st_resp_p1_current);
2208         len -= COUNTER_PAIR;
2209 
2210         if (len < COUNTER_PAIR)
2211                 return;
2212         (void) printf(gettext("Total:     "));
2213         PRSACNTS(sp->st_init_p1_total, sp->st_resp_p1_total);
2214         len -= COUNTER_PAIR;
2215 
2216         if (len < COUNTER_PAIR)
2217                 return;
2218         (void) printf(gettext("Attempted: "));
2219         PRSACNTS(sp->st_init_p1_attempts, sp->st_resp_p1_attempts);
2220         len -= COUNTER_PAIR;
2221 
2222         if (len < (COUNTER_PAIR + COUNTER_32BIT))
2223                 return;
2224         (void) printf(gettext("Failed:    "));
2225         PRSACNTS(sp->st_init_p1_noresp + sp->st_init_p1_respfail,
2226             sp->st_resp_p1_fail);
2227         (void) printf(
2228             gettext("           initiator fails include %u time-out(s)\n"),
2229             sp->st_init_p1_noresp);
2230 
2231         if (len < PATH_MAX)
2232                 return;
2233         if (*(sp->st_pkcs11_libname) != '\0')
2234                 (void) printf(gettext("PKCS#11 library linked in from %s\n"),
2235                     sp->st_pkcs11_libname);
2236 }
2237 
2238 /* Print one line of 'get defaults' output (i.e. single value). */
2239 static void
2240 print_defaults(char *label, char *description, char *unit,
2241     uint_t current, uint_t def)
2242 {
2243         (void) printf("%-18s%-10s%11u %-10s%-26s\n", label,
2244             (current != def) ? gettext("config") : gettext("default"),
2245             current, unit, description);
2246 }
2247 
2248 /*
2249  * Print out defaults used by in.iked, the argument is a buffer containing
2250  * two ike_defaults_t's, the first contains the hard coded defaults, the second
2251  * contains the actual values used. If these differ, then the defaults have been
2252  * changed via a config file entry. Note that "-" indicates this default
2253  * is not tunable via ike.config(4) or is system wide tunable.
2254  */
2255 static void
2256 do_print_defaults(ike_defaults_t *dp)
2257 {
2258         ike_defaults_t *ddp;
2259         ddp = (ike_defaults_t *)(dp + 1);
2260 
2261         (void) printf(gettext("\nGlobal defaults. Some values can be"
2262             " over-ridden on a per rule basis.\n"));
2263         (void) printf(gettext("\nSystem defaults are time delayed.\n\n"));
2264 
2265         (void) printf("%-18s%-10s%-12s%-10s%-26s\n\n",
2266             gettext("Token:"), gettext("Source:"), gettext("Value:"),
2267             gettext("Unit:"), gettext("Description:"));
2268 
2269         /* iked tunables */
2270         print_defaults("p1_lifetime_secs", gettext("phase 1 lifetime"),
2271             gettext("seconds"), ddp->rule_p1_lifetime_secs,
2272             dp->rule_p1_lifetime_secs);
2273 
2274         print_defaults("-", gettext("minimum phase 1 lifetime"),
2275             gettext("seconds"), ddp->rule_p1_minlife,
2276             dp->rule_p1_minlife);
2277 
2278         print_defaults("p1_nonce_len", gettext("phase 1 nonce length"),
2279             gettext("bytes"), ddp->rule_p1_nonce_len,
2280             dp->rule_p1_nonce_len);
2281 
2282         print_defaults("p2_lifetime_secs", gettext("phase 2 lifetime"),
2283             gettext("seconds"), ddp->rule_p2_lifetime_secs,
2284             dp->rule_p2_lifetime_secs);
2285 
2286         print_defaults("p2_softlife_secs", gettext("phase 2 soft lifetime"),
2287             gettext("seconds"), ddp->rule_p2_softlife_secs,
2288             dp->rule_p2_softlife_secs);
2289 
2290         print_defaults("p2_idletime_secs", gettext("phase 2 idle time"),
2291             gettext("seconds"), ddp->rule_p2_idletime_secs,
2292             dp->rule_p2_idletime_secs);
2293 
2294         print_defaults("p2_lifetime_kb", gettext("phase 2 lifetime"),
2295             gettext("kilobytes"), ddp->rule_p2_lifetime_kb,
2296             dp->rule_p2_lifetime_kb);
2297 
2298         print_defaults("p2_softlife_kb", gettext("phase 2 soft lifetime"),
2299             gettext("kilobytes"), ddp->rule_p2_softlife_kb,
2300             dp->rule_p2_softlife_kb);
2301 
2302         /* system wide tunables */
2303         print_defaults("-", gettext("system phase 2 lifetime"),
2304             gettext("seconds"), ddp->sys_p2_lifetime_secs,
2305             dp->sys_p2_lifetime_secs);
2306 
2307         print_defaults("-", gettext("system phase 2 soft lifetime"),
2308             gettext("seconds"), ddp->sys_p2_softlife_secs,
2309             dp->sys_p2_softlife_secs);
2310 
2311         print_defaults("-", gettext("system phase 2 idle time"),
2312             gettext("seconds"), ddp->sys_p2_idletime_secs,
2313             dp->sys_p2_idletime_secs);
2314 
2315         print_defaults("-", gettext("system phase 2 lifetime"),
2316             gettext("bytes"), ddp->sys_p2_lifetime_bytes,
2317             dp->sys_p2_lifetime_bytes);
2318 
2319         print_defaults("-", gettext("system phase 2 soft lifetime"),
2320             gettext("bytes"), ddp->sys_p2_softlife_bytes,
2321             dp->sys_p2_softlife_bytes);
2322 
2323         /* minimum and maximum values */
2324         print_defaults("-", gettext("minimum phase 2 hard lifetime"),
2325             gettext("seconds"), ddp->rule_p2_minlife_hard_secs,
2326             dp->rule_p2_minlife_hard_secs);
2327 
2328         print_defaults("-", gettext("minimum phase 2 soft lifetime"),
2329             gettext("seconds"), ddp->rule_p2_minlife_soft_secs,
2330             dp->rule_p2_minlife_soft_secs);
2331 
2332         print_defaults("-", gettext("minimum phase 2 idle lifetime"),
2333             gettext("seconds"), ddp->rule_p2_minlife_idle_secs,
2334             dp->rule_p2_minlife_idle_secs);
2335 
2336         print_defaults("-", gettext("minimum phase 2 hard lifetime"),
2337             gettext("kilobytes"), ddp->rule_p2_minlife_hard_kb,
2338             dp->rule_p2_minlife_hard_kb);
2339 
2340         print_defaults("-", gettext("minimum phase 2 soft lifetime"),
2341             gettext("kilobytes"), ddp->rule_p2_minlife_soft_kb,
2342             dp->rule_p2_minlife_soft_kb);
2343 
2344         print_defaults("-", gettext("minimum phase 2 delta"),
2345             gettext("seconds"), ddp->rule_p2_mindiff_secs,
2346             dp->rule_p2_mindiff_secs);
2347 
2348         print_defaults("-", gettext("minimum phase 2 delta"),
2349             gettext("kilobytes"), ddp->rule_p2_mindiff_kb,
2350             dp->rule_p2_mindiff_kb);
2351 
2352         print_defaults("-", gettext("maximum phase 2 lifetime"),
2353             gettext("seconds"), ddp->rule_p2_maxlife_secs,
2354             dp->rule_p2_maxlife_secs);
2355 
2356         print_defaults("-", gettext("conversion factor"),
2357             gettext("kbytes/s"), ddp->conversion_factor,
2358             dp->conversion_factor);
2359 
2360         print_defaults("-", gettext("maximum phase 2 lifetime"),
2361             gettext("kilobytes"), ddp->rule_p2_maxlife_kb,
2362             dp->rule_p2_maxlife_kb);
2363 
2364         /* other values */
2365         print_defaults("p2_nonce_len", gettext("phase 2 nonce length"),
2366             gettext("bytes"), ddp->rule_p2_nonce_len,
2367             dp->rule_p2_nonce_len);
2368 
2369         print_defaults("p2_pfs", gettext("phase 2 PFS"),
2370             " ", ddp->rule_p2_pfs, dp->rule_p2_pfs);
2371 
2372         print_defaults("max_certs", gettext("max certificates"),
2373             " ", ddp->rule_max_certs, dp->rule_max_certs);
2374 
2375         print_defaults("-", gettext("IKE port number"),
2376             " ", ddp->rule_ike_port, dp->rule_ike_port);
2377 
2378         print_defaults("-", gettext("NAT-T port number"),
2379             " ", ddp->rule_natt_port, dp->rule_natt_port);
2380 }
2381 
2382 static void
2383 print_categories(int level)
2384 {
2385         int     mask;
2386 
2387         if (level == 0) {
2388                 (void) printf(gettext("No debug categories enabled.\n"));
2389                 return;
2390         }
2391 
2392         (void) printf(gettext("Debug categories enabled:"));
2393         for (mask = 1; mask <= D_HIGHBIT; mask <<= 1) {
2394                 if (level & mask)
2395                         (void) printf("\n\t%s", dbgstr(mask));
2396         }
2397         (void) printf("\n");
2398 }
2399 
2400 /*PRINTFLIKE2*/
2401 static void
2402 ikeadm_err_exit(ike_err_t *err, char *fmt, ...)
2403 {
2404         va_list ap;
2405         char    bailbuf[BUFSIZ];
2406 
2407         va_start(ap, fmt);
2408         (void) vsnprintf(bailbuf, BUFSIZ, fmt, ap);
2409         va_end(ap);
2410         if ((err != NULL) && (err->ike_err == IKE_ERR_SYS_ERR)) {
2411                 bail_msg("%s: %s", bailbuf, (err->ike_err_unix == 0) ?
2412                     gettext("<unknown error>") : strerror(err->ike_err_unix));
2413         } else {
2414                 bail_msg("%s: %s", bailbuf, (err == NULL) ?
2415                     gettext("<unknown error>") : errstr(err->ike_err));
2416         }
2417 }
2418 
2419 /*PRINTFLIKE2*/
2420 static void
2421 ikeadm_err_msg(ike_err_t *err, char *fmt, ...)
2422 {
2423         va_list ap;
2424         char    mbuf[BUFSIZ];
2425 
2426         va_start(ap, fmt);
2427         (void) vsnprintf(mbuf, BUFSIZ, fmt, ap);
2428         va_end(ap);
2429         if ((err != NULL) && (err->ike_err == IKE_ERR_SYS_ERR)) {
2430                 message("%s: %s", mbuf, (err->ike_err_unix == 0) ?
2431                     gettext("<unknown error>") :
2432                     ((err->ike_err_unix == EEXIST) ?
2433                     gettext("Duplicate entry") :
2434                     strerror(err->ike_err_unix)));
2435         } else {
2436                 message("%s: %s", mbuf, (err == NULL) ?
2437                     gettext("<unknown error>") : errstr(err->ike_err));
2438         }
2439 }
2440 
2441 
2442 /*
2443  * Command functions
2444  */
2445 
2446 /*
2447  * Exploit the fact that ike_dbg_t and ike_priv_t have identical
2448  * formats in the following two functions.
2449  */
2450 static void
2451 do_getvar(int cmd)
2452 {
2453         ike_service_t   req, *rtn;
2454         ike_dbg_t       *dreq;
2455         char            *varname;
2456 
2457         switch (cmd) {
2458         case IKE_SVC_GET_DBG:
2459                 varname = gettext("debug");
2460                 break;
2461         case IKE_SVC_GET_PRIV:
2462                 varname = gettext("privilege");
2463                 break;
2464         default:
2465                 bail_msg(gettext("unrecognized get command (%d)"), cmd);
2466         }
2467 
2468         dreq = &req.svc_dbg;
2469         dreq->cmd = cmd;
2470         dreq->dbg_level = 0;
2471 
2472         rtn = ikedoor_call((char *)&req, sizeof (ike_dbg_t), NULL, 0);
2473 
2474         if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2475                 ikeadm_err_exit(&rtn->svc_err,
2476                     gettext("error getting %s level"), varname);
2477         }
2478         dreq = &rtn->svc_dbg;
2479         (void) printf(gettext("Current %s level is 0x%x"),
2480             varname, dreq->dbg_level);
2481 
2482         if (cmd == IKE_SVC_GET_DBG) {
2483                 (void) printf("\n");
2484                 print_categories(dreq->dbg_level);
2485         } else {
2486                 (void) printf(gettext(", %s enabled\n"),
2487                     privstr(dreq->dbg_level));
2488         }
2489 }
2490 
2491 /*
2492  * Log into a token and unlock all objects
2493  * referenced by PKCS#11 hint files.
2494  */
2495 static void
2496 do_setdel_pin(int cmd, int argc, char **argv)
2497 {
2498         ike_service_t   req, *rtn;
2499         ike_pin_t       *preq;
2500         char            token_label[PKCS11_TOKSIZE];
2501         char            *token_pin;
2502         char            prompt[80];
2503 
2504         if (argc < 1)
2505                 Bail(gettext("Must specify PKCS#11 token object."));
2506 
2507         preq = &req.svc_pin;
2508         preq->cmd = cmd;
2509 
2510         switch (cmd) {
2511         case IKE_SVC_SET_PIN:
2512                 if (parse_token(argc, argv, token_label) != 0)
2513                         Bail("Invalid syntax for \"token login\"");
2514                 (void) snprintf(prompt, sizeof (prompt),
2515                     "Enter PIN for PKCS#11 token \'%s\': ", token_label);
2516                 token_pin =
2517                     getpassphrase(prompt);
2518                 (void) strlcpy((char *)preq->token_pin, token_pin, MAX_PIN_LEN);
2519                 bzero(token_pin, strlen(token_pin));
2520                 break;
2521         case IKE_SVC_DEL_PIN:
2522                 if (parse_token(argc, argv, token_label) != 0)
2523                         Bail("Invalid syntax for \"token logout\"");
2524                 break;
2525         default:
2526                 bail_msg(gettext("unrecognized token command (%d)"), cmd);
2527         }
2528 
2529         (void) strlcpy(preq->pkcs11_token, token_label, PKCS11_TOKSIZE);
2530 
2531         rtn = ikedoor_call((char *)&req, sizeof (ike_pin_t), NULL, 0);
2532         if (cmd == IKE_SVC_SET_PIN)
2533                 bzero(preq->token_pin, sizeof (preq->token_pin));
2534 
2535         if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2536                 ikeadm_err_exit(&rtn->svc_err,
2537                     gettext("PKCS#11 operation"));
2538         }
2539         preq = &rtn->svc_pin;
2540         message(gettext("PKCS#11 operation successful"));
2541 }
2542 
2543 static void
2544 do_setvar(int cmd, int argc, char **argv)
2545 {
2546         ike_service_t   req, *rtn;
2547         ike_dbg_t       *dreq;
2548         door_desc_t     *descp = NULL, desc;
2549         int             fd, ndesc = 0;
2550         uint32_t        reqlevel;
2551         char            *varname;
2552 
2553         if (argc < 1)
2554                 Bail("unspecified level");
2555         reqlevel = strtoul(argv[0], NULL, 0);
2556 
2557         switch (cmd) {
2558         case IKE_SVC_SET_DBG:
2559                 if (argc > 2)
2560                         Bail("Too many arguments to \"set debug\"");
2561                 varname = gettext("debug");
2562                 if (reqlevel == 0) {
2563                         /* check for a string... */
2564                         reqlevel = parsedbgopts(argv[0]);
2565                 }
2566                 if (reqlevel == D_INVALID)
2567                         bail_msg(gettext("Bad debug flag: %s"), argv[0]);
2568                 break;
2569         case IKE_SVC_SET_PRIV:
2570                 if (argc > 1)
2571                         Bail("Too many arguments to \"set priv\"");
2572 
2573                 varname = gettext("privilege");
2574                 if (reqlevel == 0) {
2575                         /* check for a string... */
2576                         reqlevel = privstr2num(argv[0]);
2577                 }
2578                 if (reqlevel > IKE_PRIV_MAXIMUM)
2579                         bail_msg(gettext("Bad privilege flag: %s"), argv[0]);
2580                 break;
2581         default:
2582                 bail_msg(gettext("unrecognized set command (%d)"), cmd);
2583         }
2584 
2585         dreq = &req.svc_dbg;
2586         dreq->cmd = cmd;
2587         dreq->dbg_level = reqlevel;
2588 
2589         if ((argc == 2) && (cmd == IKE_SVC_SET_DBG)) {
2590                 fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND,
2591                     S_IRUSR | S_IWUSR);
2592                 if (fd < 0)
2593                         Bail("open debug file");
2594                 desc.d_data.d_desc.d_descriptor = fd;
2595                 desc.d_attributes = DOOR_DESCRIPTOR;
2596                 descp = &desc;
2597                 ndesc = 1;
2598         }
2599 
2600         rtn = ikedoor_call((char *)&req, sizeof (ike_dbg_t), descp, ndesc);
2601 
2602         if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2603                 ikeadm_err_exit(&rtn->svc_err,
2604                     gettext("error setting %s level"), varname);
2605         }
2606         dreq = &rtn->svc_dbg;
2607         (void) printf(
2608             gettext("Successfully changed %s level from 0x%x to 0x%x\n"),
2609             varname, dreq->dbg_level, reqlevel);
2610 
2611         if (cmd == IKE_SVC_SET_DBG) {
2612                 print_categories(reqlevel);
2613         } else {
2614                 (void) printf(gettext("New privilege level 0x%x enables %s\n"),
2615                     reqlevel, privstr(reqlevel));
2616         }
2617 }
2618 
2619 static void
2620 do_getstats(int cmd)
2621 {
2622         ike_service_t   *rtn;
2623         ike_statreq_t   sreq, *sreqp;
2624         ike_stats_t     *sp;
2625 
2626         sreq.cmd = cmd;
2627 
2628         rtn = ikedoor_call((char *)&sreq, sizeof (ike_statreq_t), NULL, 0);
2629         if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2630                 ikeadm_err_exit(&rtn->svc_err, gettext("error getting stats"));
2631         }
2632 
2633         sreqp = &rtn->svc_stats;
2634         sp = (ike_stats_t *)(sreqp + 1);
2635         print_stats(sp, sreqp->stat_len);
2636 }
2637 
2638 static void
2639 do_getdefs(int cmd)
2640 {
2641         ike_service_t   *rtn;
2642         ike_defreq_t    dreq, *dreqp;
2643         ike_defaults_t  *dp;
2644 
2645         dreq.cmd = cmd;
2646 
2647         rtn = ikedoor_call((char *)&dreq, sizeof (ike_defreq_t), NULL, 0);
2648         if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2649                 ikeadm_err_exit(&rtn->svc_err,
2650                     gettext("error getting defaults"));
2651         }
2652 
2653         dreqp = &rtn->svc_defaults;
2654         dp = (ike_defaults_t *)(dreqp + 1);
2655 
2656         /*
2657          * Before printing each line, make sure the structure we were
2658          * given is big enough to include the fields needed.
2659          * Silently bail out of there is a version mismatch.
2660          */
2661         if (dreqp->stat_len < ((2 * sizeof (ike_defaults_t))
2662             + sizeof (ike_defreq_t)) || dreqp->version != DOORVER) {
2663                 return;
2664         }
2665         do_print_defaults(dp);
2666 }
2667 
2668 static void
2669 do_dump(int cmd)
2670 {
2671         char            *name;
2672         ike_service_t   req, *rtn;
2673         ike_dump_t      *dreq, *dump;
2674 
2675         switch (cmd) {
2676         case IKE_SVC_DUMP_P1S:
2677                 name = gettext("phase 1 SA info");
2678                 break;
2679         case IKE_SVC_DUMP_RULES:
2680                 name = gettext("policy rules");
2681                 break;
2682         case IKE_SVC_DUMP_PS:
2683                 name = gettext("preshared keys");
2684                 break;
2685         case IKE_SVC_DUMP_CERTCACHE:
2686                 name = gettext("certcache");
2687                 break;
2688         case IKE_SVC_DUMP_GROUPS:
2689                 name = gettext("groups");
2690                 print_group_header();
2691                 break;
2692         case IKE_SVC_DUMP_ENCRALGS:
2693                 name = gettext("encralgs");
2694                 print_encralg_header();
2695                 break;
2696         case IKE_SVC_DUMP_AUTHALGS:
2697                 name = gettext("authalgs");
2698                 print_authalg_header();
2699                 break;
2700         default:
2701                 bail_msg(gettext("unrecognized dump command (%d)"), cmd);
2702         }
2703 
2704         dreq = &req.svc_dump;
2705         dreq->cmd = cmd;
2706         dreq->dump_len = 0;
2707         dreq->dump_next = 0;
2708         do {
2709                 rtn = ikedoor_call((char *)&req, sizeof (ike_dump_t),
2710                     NULL, 0);
2711                 if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
2712                         if (rtn && (rtn->svc_err.ike_err == IKE_ERR_NO_OBJ)) {
2713                                 /* no entries to print */
2714                                 break;
2715                         }
2716                         ikeadm_err_exit(&rtn->svc_err,
2717                             gettext("error getting %s"), name);
2718                 }
2719                 dump = &rtn->svc_dump;
2720 
2721                 switch (cmd) {
2722                 case IKE_SVC_DUMP_P1S:
2723                         print_p1((ike_p1_sa_t *)(dump + 1));
2724                         break;
2725                 case IKE_SVC_DUMP_RULES:
2726                         print_rule((ike_rule_t *)(dump + 1));
2727                         break;
2728                 case IKE_SVC_DUMP_PS:
2729                         print_ps((ike_ps_t *)(dump + 1));
2730                         break;
2731                 case IKE_SVC_DUMP_CERTCACHE:
2732                         print_certcache((ike_certcache_t *)(dump + 1));
2733                         break;
2734                 case IKE_SVC_DUMP_GROUPS:
2735                         print_group((ike_group_t *)(dump + 1));
2736                         break;
2737                 case IKE_SVC_DUMP_ENCRALGS:
2738                         print_encralg((ike_encralg_t *)(dump + 1));
2739                         break;
2740                 case IKE_SVC_DUMP_AUTHALGS:
2741                         print_authalg((ike_authalg_t *)(dump + 1));
2742                         break;
2743                 }
2744 
2745                 dreq->dump_next = dump->dump_next;
2746 
2747                 (void) munmap((char *)rtn, dump->dump_len);
2748 
2749         } while (dreq->dump_next);
2750 
2751         (void) printf(gettext("\nCompleted dump of %s\n"), name);
2752 }
2753 
2754 static void
2755 do_getdel_doorcall(int cmd, int idlen, int idtype, char *idp, char *name)
2756 {
2757         int             totallen;
2758         char            *p;
2759         ike_service_t   *reqp, *rtnp;
2760         ike_get_t       *getp;
2761         boolean_t       getcmd;
2762 
2763         getcmd = ((cmd == IKE_SVC_GET_P1) || (cmd == IKE_SVC_GET_RULE) ||
2764             (cmd == IKE_SVC_GET_PS));
2765 
2766         /*
2767          * WARNING: to avoid being redundant, this code takes advantage
2768          * of the fact that the ike_get_t and ike_del_t structures are
2769          * identical (only the field names differ, their function and
2770          * size are the same).  If for some reason those structures
2771          * change, this code will need to be re-written to accomodate
2772          * that difference.
2773          */
2774         totallen = sizeof (ike_get_t) + idlen;
2775         if ((reqp = (ike_service_t *)malloc(totallen)) == NULL)
2776                 Bail("malloc(id)");
2777 
2778         getp = &reqp->svc_get;
2779         getp->cmd = cmd;
2780         getp->get_len = totallen;
2781         getp->get_idtype = idtype;
2782         p = (char *)(getp + 1);
2783 
2784         (void) memcpy(p, idp, idlen);
2785 
2786         rtnp = ikedoor_call((char *)reqp, totallen, NULL, 0);
2787         if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
2788                 if (rtnp && (rtnp->svc_err.ike_err == IKE_ERR_NO_OBJ)) {
2789                         message(gettext("Could not find requested %s."), name);
2790                 } else {
2791                         ikeadm_err_msg(&rtnp->svc_err, gettext("error %s %s"),
2792                             (getcmd) ? gettext("getting") : gettext("deleting"),
2793                             name);
2794                 }
2795                 free(reqp);
2796                 return;
2797         }
2798         getp = &rtnp->svc_get;
2799 
2800         if (getcmd) {
2801                 switch (cmd) {
2802                 case IKE_SVC_GET_P1:
2803                         print_p1((ike_p1_sa_t *)(getp + 1));
2804                         break;
2805                 case IKE_SVC_GET_PS:
2806                         print_ps((ike_ps_t *)(getp + 1));
2807                         break;
2808                 case IKE_SVC_GET_RULE:
2809                         print_rule((ike_rule_t *)(getp + 1));
2810                         break;
2811                 }
2812         } else {
2813                 message(gettext("Successfully deleted selected %s."), name);
2814         }
2815 
2816         (void) munmap((char *)rtnp, getp->get_len);
2817         free(reqp);
2818 }
2819 
2820 static void
2821 do_getdel(int cmd, int argc, char **argv)
2822 {
2823         int             idlen, idtype = 0, i, j;
2824         int             bytelen1, bytelen2;
2825         char            *name, *idp, *p, *p1, *p2;
2826         ike_addr_pr_t   apr;
2827         ike_cky_pr_t    cpr;
2828         sadb_ident_t    *sid1p, *sid2p;
2829         struct hostent  *he1p, *he2p;
2830         char            label[MAX_LABEL_LEN];
2831 
2832         if ((argc < 1) || (argv[0] == NULL)) {
2833                 Bail("not enough identification info");
2834         }
2835 
2836         switch (cmd) {
2837         case IKE_SVC_GET_P1:
2838         case IKE_SVC_DEL_P1:
2839                 name = gettext("phase 1 SA");
2840                 /*
2841                  * The first token must either be an address (or hostname)
2842                  * or a cookie.  We require cookies to be entered as hex
2843                  * numbers, beginning with 0x; so if our token starts with
2844                  * that, it's a cookie.
2845                  */
2846                 if (strncmp(argv[0], "0x", 2) == 0) {
2847                         if (parse_cky_pr(argc, argv, &cpr) >= 0) {
2848                                 idtype = IKE_ID_CKY_PAIR;
2849                                 idlen = sizeof (ike_cky_pr_t);
2850                                 idp = (char *)&cpr;
2851                         }
2852                 } else {
2853                         if (parse_addr_pr(argc, argv, &he1p, &he2p) >= 0) {
2854                                 idtype = IKE_ID_ADDR_PAIR;
2855                                 idlen = sizeof (ike_addr_pr_t);
2856                         }
2857                 }
2858                 break;
2859 
2860         case IKE_SVC_GET_RULE:
2861         case IKE_SVC_DEL_RULE:
2862                 name = gettext("policy rule");
2863                 if (parse_label(argc, argv, label) >= 0) {
2864                         idtype = IKE_ID_LABEL;
2865                         idlen = MAX_LABEL_LEN;
2866                         idp = label;
2867                 }
2868                 break;
2869 
2870         case IKE_SVC_GET_PS:
2871         case IKE_SVC_DEL_PS:
2872                 name = gettext("preshared key");
2873                 /*
2874                  * The first token must either be an address or an ident
2875                  * type.  Check for an ident type to determine which it is.
2876                  */
2877                 if (parse_idtype(argv[0], NULL) >= 0) {
2878                         if (parse_ident_pr(argc, argv, &sid1p, &sid2p) >= 0) {
2879                                 idtype = IKE_ID_IDENT_PAIR;
2880                                 idlen = SADB_64TO8(sid1p->sadb_ident_len) +
2881                                     SADB_64TO8(sid2p->sadb_ident_len);
2882                         }
2883                 } else {
2884                         if (parse_addr_pr(argc, argv, &he1p, &he2p) >= 0) {
2885                                 idtype = IKE_ID_ADDR_PAIR;
2886                                 idlen = sizeof (ike_addr_pr_t);
2887                         }
2888                 }
2889                 break;
2890 
2891         default:
2892                 bail_msg(gettext("unrecognized get/del command (%d)"), cmd);
2893         }
2894 
2895         switch (idtype) {
2896         case IKE_ID_ADDR_PAIR:
2897                 /*
2898                  * we might have exploding addrs here; do every possible
2899                  * combination.
2900                  */
2901                 i = 0;
2902                 j = 0;
2903                 while ((p1 = he1p->h_addr_list[i++]) != NULL) {
2904                         headdr2sa(p1, &apr.loc_addr, he1p->h_length);
2905 
2906                         while ((p2 = he2p->h_addr_list[j++]) != NULL) {
2907                                 headdr2sa(p2, &apr.rem_addr, he2p->h_length);
2908                                 do_getdel_doorcall(cmd, idlen, idtype,
2909                                     (char *)&apr, name);
2910                         }
2911                 }
2912                 FREE_HE(he1p);
2913                 FREE_HE(he2p);
2914                 break;
2915 
2916         case IKE_ID_IDENT_PAIR:
2917                 bytelen1 = SADB_64TO8(sid1p->sadb_ident_len);
2918                 bytelen2 = SADB_64TO8(sid2p->sadb_ident_len);
2919                 if (idlen != bytelen1 + bytelen2)
2920                         Bail("ident syntax error");
2921                 idp = p = (char *)malloc(idlen);
2922                 if (p == NULL)
2923                         Bail("malloc(id)");
2924                 (void) memcpy(p, (char *)sid1p, bytelen1);
2925                 p += bytelen1;
2926                 (void) memcpy(p, (char *)sid2p, bytelen2);
2927                 do_getdel_doorcall(cmd, idlen, idtype, idp, name);
2928                 free(idp);
2929                 free(sid1p);
2930                 free(sid2p);
2931                 break;
2932 
2933         case IKE_ID_CKY_PAIR:
2934         case IKE_ID_LABEL:
2935                 do_getdel_doorcall(cmd, idlen, idtype, idp, name);
2936                 break;
2937 
2938         case 0:
2939         default:
2940                 bail_msg(gettext("invalid %s identification\n"), name);
2941         }
2942 }
2943 
2944 /*
2945  * Copy source into target, inserting an escape character ('\') before
2946  * any quotes that appear.  Return true on success, false on failure.
2947  */
2948 static boolean_t
2949 escapequotes(char *target, char *source, int tlen)
2950 {
2951         int     s, t, len = strlen(source) + 1;
2952 
2953         if (tlen < len)
2954                 return (B_FALSE);
2955 
2956         for (s = 0, t = 0; s < len && t < tlen; s++) {
2957                 if (source[s] == '\"')
2958                         target[t++] = '\\';
2959                 target[t++] = source[s];
2960         }
2961 
2962         if ((t == tlen) && (s < len))
2963                 return (B_FALSE);
2964 
2965         return (B_TRUE);
2966 }
2967 
2968 /*
2969  * Return true if the arg following the given keyword should
2970  * be in quotes (i.e. is a string), false if not.
2971  */
2972 static boolean_t
2973 quotedfield(char *keywd)
2974 {
2975         if ((strncmp(keywd, "label", strlen("label") + 1) == 0) ||
2976             (strncmp(keywd, "local_id", strlen("local_id") + 1) == 0) ||
2977             (strncmp(keywd, "remote_id", strlen("remote_id") + 1) == 0))
2978                 return (B_TRUE);
2979 
2980         return (B_FALSE);
2981 }
2982 
2983 static void
2984 do_new(int cmd, int argc, char **argv)
2985 {
2986         ike_service_t   *rtn;
2987         ike_new_t       new, *newp = NULL;
2988         door_desc_t     desc, *descp = NULL;
2989         int             i, fd, ndesc = 0, buflen;
2990         char            *name, tmpfilepath[32];
2991         FILE            *tmpfile;
2992 
2993         switch (cmd) {
2994         case IKE_SVC_NEW_PS:
2995                 name = gettext("preshared key");
2996                 break;
2997         case IKE_SVC_NEW_RULE:
2998                 name = gettext("policy rule");
2999                 break;
3000         default:
3001                 bail_msg(gettext("unrecognized new command (%d)"), cmd);
3002         }
3003 
3004         if (argc == 1) {
3005                 /* We've been given a file to read from */
3006                 fd = open(argv[0], O_RDONLY);
3007                 if (fd < 0)
3008                         Bail("open source file");
3009 
3010                 desc.d_data.d_desc.d_descriptor = fd;
3011                 desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
3012                 descp = &desc;
3013                 ndesc = 1;
3014 
3015                 new.cmd = cmd;
3016                 new.new_len = 0;
3017                 newp = &new;
3018                 buflen = sizeof (ike_new_t);
3019 
3020         } else if ((argc > 1) && (cmd == IKE_SVC_NEW_PS)) {
3021                 /*
3022                  * This is an alternative to using the tmpfile method
3023                  * for preshared keys.  It means we're duplicating the
3024                  * parsing effort that happens in readps.c; but it
3025                  * does avoid having the key sitting in a file.
3026                  */
3027                 ike_ps_t        *psp;
3028                 int             pslen;
3029 
3030                 /*
3031                  * must be in interactive mode; don't want keys in
3032                  * the process args.
3033                  */
3034                 if (!interactive)
3035                         Bail("Must be in interactive mode to add key info.");
3036                 if (parse_ps(argc, argv, &psp, &pslen) < 0) {
3037                         errno = 0;
3038                         Bail("invalid preshared key definition");
3039                 }
3040                 newp = malloc(sizeof (ike_new_t) + pslen);
3041                 if (newp == NULL)
3042                         Bail("alloc pskey");
3043                 newp->cmd = cmd;
3044                 newp->new_len = sizeof (ike_new_t) + pslen;
3045                 (void) memcpy((char *)(newp + 1), psp, pslen);
3046                 buflen = newp->new_len;
3047                 /* parse_ps allocated the ike_ps_t buffer; free it now */
3048                 free(psp);
3049 
3050         } else if ((argc > 1) && (cmd == IKE_SVC_NEW_RULE)) {
3051                 /*
3052                  * We've been given the item in argv.  However, parsing
3053                  * rules can get more than a little messy, and in.iked
3054                  * already has a great parser for this stuff!  So don't
3055                  * fool around with trying to do the parsing here. Just
3056                  * write it out to a tempfile, and send the fd to in.iked.
3057                  *
3058                  * We could conceivably do this for preshared keys,
3059                  * rather than duplicating the parsing effort; but that
3060                  * would mean the key would be written out to a file,
3061                  * which isn't such a good idea.
3062                  */
3063                 boolean_t       doquotes = B_FALSE;
3064                 int             rtn;
3065 
3066                 if ((argv[0][0] != '{') ||
3067                     (argv[argc - 1][strlen(argv[argc - 1]) - 1] != '}'))
3068                         bail_msg(gettext("improperly formatted %s"), name);
3069 
3070                 /* attempt to use a fairly unpredictable file name... */
3071                 (void) sprintf(tmpfilepath, "/var/run/%x", (int)gethrtime());
3072                 fd = open(tmpfilepath, O_RDWR | O_CREAT | O_EXCL,
3073                     S_IRUSR | S_IWUSR);
3074                 if (fd < 0)
3075                         Bail("cannot open tmpfile");
3076 
3077                 /* and make it inaccessible asap */
3078                 if (unlink(tmpfilepath) < 0) {
3079                         (void) close(fd);
3080                         Bail("tmpfile error");
3081                 }
3082 
3083                 tmpfile = fdopen(fd, "w");
3084                 if (tmpfile == NULL) {
3085                         (void) close(fd);
3086                         Bail("cannot write to tmpfile");
3087                 }
3088 
3089                 for (i = 0; i < argc; i++) {
3090                         /*
3091                          * We have to do some gyrations with our string here,
3092                          * to properly handle quotes.  There are two issues:
3093                          * - some of the fields of a rule may have embedded
3094                          *   whitespace, and thus must be quoted on the cmd
3095                          *   line.  The shell removes the quotes, and gives
3096                          *   us a single argv string; but we need to put the
3097                          *   quotes back in when we write the string out to
3098                          *   file.  The doquotes boolean is set when we
3099                          *   process a keyword which will be followed by a
3100                          *   string value (so the NEXT argv element will be
3101                          *   quoted).
3102                          * - there might be a quote character in a field,
3103                          *   that was escaped on the cmdline.  The shell
3104                          *   removes the escape char, and leaves the quote
3105                          *   in the string it gives us.  We need to put the
3106                          *   escape char back in before writing to file.
3107                          */
3108                         char    field[MAXLINESIZE];
3109                         if (!escapequotes(field, argv[i], MAXLINESIZE))
3110                                 Bail("write to tmpfile failed (arg too big)");
3111                         if (doquotes) {
3112                                 rtn = fprintf(tmpfile, "\"%s\"\n", field);
3113                                 doquotes = B_FALSE;
3114                         } else {
3115                                 rtn = fprintf(tmpfile, "%s\n", field);
3116                         }
3117                         if (rtn < 0)
3118                                 Bail("write to tmpfile failed");
3119                         /*
3120                          * check if this is a keyword identifying
3121                          * a field that needs to be quoted.
3122                          */
3123                         doquotes = quotedfield(argv[i]);
3124                 }
3125                 if (fflush(tmpfile) == EOF)
3126                         Bail("write to tmpfile failed");
3127                 /* rewind so that the daemon will get the beginning */
3128                 rewind(tmpfile);
3129 
3130                 desc.d_data.d_desc.d_descriptor = fd;
3131                 desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
3132                 descp = &desc;
3133                 ndesc = 1;
3134 
3135                 new.cmd = cmd;
3136                 new.new_len = 0;
3137                 newp = &new;
3138                 buflen = sizeof (ike_new_t);
3139 
3140         } else {
3141                 /* not enough information! */
3142                 bail_msg(gettext("missing %s description or file name"), name);
3143         }
3144 
3145         rtn = ikedoor_call((char *)newp, buflen, descp, ndesc);
3146 
3147         if ((rtn == NULL) || (rtn->svc_err.cmd == IKE_SVC_ERROR)) {
3148                 ikeadm_err_msg(&rtn->svc_err,
3149                     gettext("error creating new %s"), name);
3150         } else {
3151                 message(gettext("Successfully created new %s."), name);
3152         }
3153 }
3154 
3155 static void
3156 do_flush(int cmd)
3157 {
3158         ike_service_t   *rtnp;
3159         ike_flush_t     flush;
3160 
3161         if (cmd != IKE_SVC_FLUSH_P1S && cmd != IKE_SVC_FLUSH_CERTCACHE) {
3162                 bail_msg(gettext("unrecognized flush command (%d)."), cmd);
3163         }
3164 
3165         flush.cmd = cmd;
3166 
3167         rtnp = ikedoor_call((char *)&flush, sizeof (ike_flush_t), NULL, 0);
3168         if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
3169                 ikeadm_err_exit(&rtnp->svc_err, gettext("error doing flush"));
3170         }
3171         if (cmd == IKE_SVC_FLUSH_P1S)
3172                 message(gettext("Successfully flushed P1 SAs."));
3173         else
3174                 message(gettext("Successfully flushed cert cache."));
3175 }
3176 
3177 static void
3178 do_rw(int cmd, int argc, char **argv)
3179 {
3180         ike_service_t   *rtnp;
3181         ike_rw_t        rw;
3182         door_desc_t     desc, *descp = NULL;
3183         int             oflag, omode, fd, ndesc = 0;
3184         char            *op, *obj = NULL;
3185         boolean_t       writing = B_FALSE;
3186 
3187         switch (cmd) {
3188         case IKE_SVC_READ_PS:
3189                 obj = gettext("preshared key");
3190                 /* FALLTHRU */
3191         case IKE_SVC_READ_RULES:
3192                 if (obj == NULL)
3193                         obj = gettext("policy rule");
3194                 op = gettext("read");
3195                 oflag = O_RDONLY;
3196                 omode = 0;
3197                 break;
3198 
3199         case IKE_SVC_WRITE_PS:
3200                 obj = gettext("preshared key");
3201                 /* FALLTHRU */
3202         case IKE_SVC_WRITE_RULES:
3203                 if (obj == NULL)
3204                         obj = gettext("policy rule");
3205                 op = gettext("write");
3206                 oflag = O_RDWR | O_CREAT | O_EXCL;
3207                 omode = S_IRUSR | S_IWUSR;
3208 
3209                 /* for write commands, dest location must be specified */
3210                 if (argc < 1) {
3211                         bail_msg(gettext("destination location required "
3212                             "to write %ss"), obj);
3213                 }
3214                 writing = B_TRUE;
3215                 break;
3216 
3217         default:
3218                 bail_msg(gettext("unrecognized read/write command (%d)."), cmd);
3219         }
3220 
3221         rw.cmd = cmd;
3222 
3223         if (argc >= 1) {
3224                 rw.rw_loc = IKE_RW_LOC_USER_SPEC;
3225                 fd = open(argv[0], oflag, omode);
3226                 if (fd < 0)
3227                         Bail("open user-specified file");
3228 
3229                 desc.d_data.d_desc.d_descriptor = fd;
3230                 desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
3231                 descp = &desc;
3232                 ndesc = 1;
3233         } else {
3234                 rw.rw_loc = IKE_RW_LOC_DEFAULT;
3235         }
3236 
3237         rtnp = ikedoor_call((char *)&rw, sizeof (ike_rw_t), descp, ndesc);
3238         if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
3239                 /*
3240                  * Need to remove the target file in the
3241                  * case of a failed write command.
3242                  */
3243                 if (writing) {
3244                         /*
3245                          * argv[0] must be valid if we're writing; we
3246                          * exit before setting this boolean if not.
3247                          */
3248                         (void) unlink(argv[0]);
3249                         (void) close(fd);
3250 
3251                         if ((rtnp != NULL) &&
3252                             (rtnp->svc_err.ike_err == IKE_ERR_NO_OBJ)) {
3253                                 message(gettext("No %s information to write."),
3254                                     obj);
3255                                 return;
3256                         }
3257                 }
3258                 ikeadm_err_exit(&rtnp->svc_err, gettext("error doing %s"), op);
3259         }
3260         message(gettext("Completed %s of %s configuration information."),
3261             op, obj);
3262 }
3263 
3264 static void
3265 do_rbdump()
3266 {
3267         ike_cmd_t       req;
3268         ike_service_t   *rtnp;
3269 
3270         req.cmd = IKE_SVC_DBG_RBDUMP;
3271 
3272         rtnp = ikedoor_call((char *)&req, sizeof (ike_cmd_t), NULL, 0);
3273         if ((rtnp == NULL) || (rtnp->svc_err.cmd == IKE_SVC_ERROR)) {
3274                 ikeadm_err_exit(&rtnp->svc_err, gettext("error doing flush"));
3275         }
3276         message(gettext("Successfully dumped rulebase; check iked dbg"));
3277 }
3278 
3279 #define REQ_ARG_CNT     1
3280 
3281 /*ARGSUSED*/
3282 static void
3283 parseit(int argc, char **argv, char *notused, boolean_t notused_either)
3284 {
3285         int     cmd, cmd_obj_args = 1;
3286         char    *cmdstr, *objstr;
3287 
3288         if (interactive) {
3289                 if (argc == 0)
3290                         return;
3291         }
3292 
3293         if (argc < REQ_ARG_CNT) {
3294                 usage();
3295         }
3296 
3297         cmdstr = argv[0];
3298         if (argc > REQ_ARG_CNT) {
3299                 cmd_obj_args++;
3300                 objstr = argv[1];
3301         } else {
3302                 objstr = NULL;
3303         }
3304         cmd = parsecmd(cmdstr, objstr);
3305 
3306         /* skip over args specifying command/object */
3307         argc -= cmd_obj_args;
3308         argv += cmd_obj_args;
3309 
3310         switch (cmd) {
3311         case IKE_SVC_GET_DEFS:
3312                 if (argc != 0) {
3313                         print_get_help();
3314                         break;
3315                 }
3316                 do_getdefs(cmd);
3317                 break;
3318         case IKE_SVC_GET_DBG:
3319         case IKE_SVC_GET_PRIV:
3320                 if (argc != 0) {
3321                         print_get_help();
3322                         break;
3323                 }
3324                 do_getvar(cmd);
3325                 break;
3326         case IKE_SVC_GET_STATS:
3327                 if (argc != 0) {
3328                         print_get_help();
3329                         break;
3330                 }
3331                 do_getstats(cmd);
3332                 break;
3333         case IKE_SVC_SET_DBG:
3334         case IKE_SVC_SET_PRIV:
3335                 do_setvar(cmd, argc, argv);
3336                 break;
3337         case IKE_SVC_SET_PIN:
3338         case IKE_SVC_DEL_PIN:
3339                 do_setdel_pin(cmd, argc, argv);
3340                 break;
3341         case IKE_SVC_DUMP_P1S:
3342         case IKE_SVC_DUMP_RULES:
3343         case IKE_SVC_DUMP_GROUPS:
3344         case IKE_SVC_DUMP_ENCRALGS:
3345         case IKE_SVC_DUMP_AUTHALGS:
3346         case IKE_SVC_DUMP_PS:
3347         case IKE_SVC_DUMP_CERTCACHE:
3348                 if (argc != 0) {
3349                         print_dump_help();
3350                         break;
3351                 }
3352                 do_dump(cmd);
3353                 break;
3354         case IKE_SVC_GET_P1:
3355         case IKE_SVC_GET_RULE:
3356         case IKE_SVC_GET_PS:
3357         case IKE_SVC_DEL_P1:
3358         case IKE_SVC_DEL_RULE:
3359         case IKE_SVC_DEL_PS:
3360                 do_getdel(cmd, argc, argv);
3361                 break;
3362         case IKE_SVC_NEW_RULE:
3363         case IKE_SVC_NEW_PS:
3364                 do_new(cmd, argc, argv);
3365                 break;
3366         case IKE_SVC_FLUSH_P1S:
3367         case IKE_SVC_FLUSH_CERTCACHE:
3368                 if (argc != 0) {
3369                         print_flush_help();
3370                         break;
3371                 }
3372                 do_flush(cmd);
3373                 break;
3374         case IKE_SVC_READ_RULES:
3375         case IKE_SVC_READ_PS:
3376         case IKE_SVC_WRITE_RULES:
3377         case IKE_SVC_WRITE_PS:
3378                 do_rw(cmd, argc, argv);
3379                 break;
3380         case IKEADM_HELP_GENERAL:
3381                 print_help();
3382                 break;
3383         case IKEADM_HELP_GET:
3384                 print_get_help();
3385                 break;
3386         case IKEADM_HELP_SET:
3387                 print_set_help();
3388                 break;
3389         case IKEADM_HELP_ADD:
3390                 print_add_help();
3391                 break;
3392         case IKEADM_HELP_DEL:
3393                 print_del_help();
3394                 break;
3395         case IKEADM_HELP_DUMP:
3396                 print_dump_help();
3397                 break;
3398         case IKEADM_HELP_FLUSH:
3399                 print_flush_help();
3400                 break;
3401         case IKEADM_HELP_READ:
3402                 print_read_help();
3403                 break;
3404         case IKEADM_HELP_WRITE:
3405                 print_write_help();
3406                 break;
3407         case IKEADM_HELP_TOKEN:
3408                 print_token_help();
3409                 break;
3410         case IKEADM_HELP_HELP:
3411                 print_help_help();
3412                 break;
3413         case IKEADM_EXIT:
3414                 if (interactive)
3415                         exit(0);
3416                 break;
3417         case IKE_SVC_DBG_RBDUMP:
3418                 do_rbdump();
3419                 break;
3420         case IKE_SVC_ERROR:
3421                 usage();
3422         default:
3423                 exit(0);
3424         }
3425 }
3426 
3427 int
3428 main(int argc, char **argv)
3429 {
3430         char    ch;
3431 
3432         (void) setlocale(LC_ALL, "");
3433 #if !defined(TEXT_DOMAIN)
3434 #define TEXT_DOMAIN "SYS_TEST"
3435 #endif
3436         (void) textdomain(TEXT_DOMAIN);
3437 
3438         while ((ch = getopt(argc, argv, "hpn")) != EOF) {
3439                 switch (ch) {
3440                 case 'h':
3441                         print_help();
3442                         return (0);
3443                 case 'p':
3444                         pflag = B_TRUE;
3445                         break;
3446                 case 'n':
3447                         nflag = B_TRUE;
3448                         break;
3449                 default:
3450                         usage();
3451                 }
3452         }
3453         argc -= optind;
3454         argv += optind;
3455 
3456         if (open_door() < 0) {
3457                 (void) fprintf(stderr,
3458                     gettext("Unable to communicate with in.iked\n"));
3459                 Bail("open_door failed");
3460         }
3461 
3462         if (*argv == NULL) {
3463                 /* no cmd-line args, do interactive mode */
3464                 do_interactive(stdin, NULL, "ikeadm> ", NULL, parseit,
3465                     no_match);
3466         }
3467 
3468         parseit(argc, argv, NULL, B_FALSE);
3469 
3470         return (0);
3471 }