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