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