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 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright (c) 2017, Joyent, Inc.
  26  */
  27 
  28 #include <sys/types.h>
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <strings.h>
  32 #include <errno.h>
  33 #include <ctype.h>
  34 #include <libintl.h>
  35 #include <arpa/inet.h>
  36 #include <sys/socket.h>
  37 #include <netdb.h>
  38 #include <net/pfkeyv2.h>
  39 #include <pthread.h>
  40 #include <synch.h>
  41 #include <assert.h>
  42 #include <bunyan.h>
  43 #include <err.h>
  44 
  45 #include "preshared.h"
  46 #include "defs.h"
  47 #include <ipsec_util.h>
  48 
  49 static FILE *fp;
  50 
  51 /* Preshared key lock */
  52 static pthread_rwlock_t ps_rwlock = PTHREAD_RWLOCK_INITIALIZER;
  53 
  54 #define hd2num(hd) (((hd) >= '0' && (hd) <= '9') ? ((hd) - '0') : \
  55         (((hd) >= 'a' && (hd) <= 'f') ? ((hd) - 'a' + 10) : ((hd) - 'A' + 10)))
  56 
  57 #define ADDRBITS_V4     32      /* number of bits in IPv4 address */
  58 #define ADDRBITS_V6     128     /* number of bits in IPv6 address */
  59 
  60 
  61 #define CHR_CURLY_BRACE_OPEN            '{'
  62 #define CHR_CURLY_BRACE_CLOSE           '}'
  63 #define CHR_COMMENT_BEGIN               '#'
  64 #define CHR_COLON                       ':'
  65 #define CHR_SLASH                       '/'
  66 #define CHR_BACKSLASH                   '\\'
  67 #define CHR_DOUBLEQUOTE                 '"'
  68 #define CHR_SPACE                       ' '
  69 #define CHR_NEWLINE                     '\n'
  70 #define CHR_TAB                         '\t'
  71 #define CHR_NULL                        '\0'
  72 
  73 /*
  74  * Error message strings
  75  */
  76 
  77 static const char *err_arr [] = {
  78 #define ERR_LOCID_MISMATCH              0
  79         "Local Id value does not match the specified Localid type",
  80 #define ERR_REMID_MISMATCH              1
  81         "Remote Id does not match the remoteid type",
  82 #define ERR_MAINMODE_LOCID_NOTIP        2
  83         "Local Id can only be an IP address",
  84 #define ERR_MAINMODE_REMID_NOTIP        3
  85         "Remote Id can only be an IP address",
  86 #define ERR_ENTRY_NOBEGINBRACE          4
  87         "Syntax error - Entry does not start with an open brace",
  88 #define ERR_INVALID_FIELDNAME           5
  89         "Invalid attribute field name",
  90 #define ERR_REPEATED_FIELD              6
  91         "Field in an entry is repeated",
  92 #define ERR_INVALID_LOCALID_TYPE        7
  93         "Invalid Local Id type",
  94 #define ERR_MISSING_LOCALID             8
  95         "localid not defined",
  96 #define ERR_MISSING_REMID               9
  97         "remotedid not defined",
  98 #define ERR_INVALID_REMID_TYPE          10
  99         "Invalid Remote Id type",
 100 #define ERR_INVALID_IKE_MODE            11
 101         "Invalid Ike Mode",
 102 #define ERR_INVALID_BIT_SPECIFIER       12
 103         "Invalid Bit Specifier",
 104 #define ERR_BITLEN2BIG                  13
 105         "Bit length too large",
 106 #define ERR_WARN_LOWBITS_TRUNC          14
 107         "Lower bits will be truncated",
 108 #define ERR_STRING_NOT_HEX              15
 109         "Invalid string format - hex string expected",
 110 #define ERR_BADADDR_PREFIXLEN_PART      16
 111         "Invalid prefix length format in address",
 112 #define ERR_BADADDR_SLASH_UNEXPECTED    17
 113         "Unxpected '/' in address string",
 114 #define ERR_BADADDR_TRY_AGAIN           18
 115         "Bad address string - try again later",
 116 #define ERR_BADADDR_ADDRESS             19
 117         "Bad address string",
 118 #define ERR_BADADDR_MISMATCH            20
 119         "Address versions do not match",
 120 #define ERR_BADADDR_MCAST    21
 121         "Multicast address not allowed",
 122 #define ERR_BADADDR_4MAPPED    22
 123         "V4 mapped in v6 address not allowed",
 124 #define ERR_BADADDR_4COMPAT    23
 125         "V4 compatible in v6 address not allowed",
 126 #define ERR_INVALID_ASCII_STRING        24
 127         "Syntax error in ASCII string or quotes",
 128 };
 129 
 130 
 131 /*
 132  * Buffer to hold input line
 133  */
 134 static char     linebuf[1024];
 135 
 136 
 137 /*
 138  * Types of tokens
 139  */
 140 #define PS_TOK_BEGIN_CURLY_BRACE        1
 141 #define PS_TOK_END_CURLY_BRACE          2
 142 #define PS_TOK_FLD_TYPE                 3
 143 #define PS_TOK_FLD_VALUE                4
 144 
 145 
 146 /*
 147  * The prototype syntax of this file used, e.g. "localid" and "localidtype".
 148  * The aliases support transitioning to using same keywords as the ike/config
 149  * parser, e.g. "local_id" and "local_id_type".
 150  *
 151  * Also, {local,remote}_addr are aliases for {local,remote}_id for now,
 152  * eventually they should be handled differently.
 153  */
 154 static const keywdtab_t fldstab[] = {
 155         { PS_FLD_LOCID,         "localid" },
 156         { PS_FLD_LOCID,         "local_id" },
 157         { PS_FLD_LOCID,         "local_addr" },
 158         { PS_FLD_LOCID_TYPE,    "localidtype" },
 159         { PS_FLD_LOCID_TYPE,    "local_id_type" },
 160         { PS_FLD_REMID,         "remoteid" },
 161         { PS_FLD_REMID,         "remote_id" },
 162         { PS_FLD_REMID,         "remote_addr" },
 163         { PS_FLD_REMID_TYPE,    "remoteidtype" },
 164         { PS_FLD_REMID_TYPE,    "remote_id_type" },
 165         { PS_FLD_IKE_MODE,      "ike_mode" },
 166         { PS_FLD_IKE_MODE,      "mode" },
 167         { PS_FLD_KEY,           "key" },
 168 };
 169 
 170 static const keywdtab_t idstab[] = {
 171         { PS_ID_IP,                     "IP" },
 172         { PS_ID_IP4,                    "IPv4" },
 173         { PS_ID_IP6,                    "IPv6" },
 174         { PS_ID_IP,                     "IP_SUBNET" },
 175         { PS_ID_IP4,                    "IPv4_SUBNET" },
 176         { PS_ID_IP6,                    "IPv6_SUBNET" },
 177 };
 178 
 179 static const keywdtab_t ikmstab[] = {
 180         { PS_IKM_MAIN,                  "main" },
 181 };
 182 
 183 /*
 184  * Head and tail of linked list of entry data structures
 185  */
 186 static preshared_entry_t *ps_head, *ps_tail;
 187 
 188 /*
 189  * Global counters for use in reporting approximate error location
 190  * in config file
 191  */
 192 static int err_line_number;
 193 static int err_entry_number;
 194 
 195 /*
 196  * Function prototypes
 197  */
 198 static int getidtype(char *);
 199 static int getfldtype(char *);
 200 static int getikmtype(char *);
 201 static int postprocess_entry(preshared_entry_t *, char **);
 202 static char *get_next_token(char **);
 203 static char *readnextline(FILE *);
 204 static preshared_entry_t *getnextentry(FILE *, char **);
 205 static uint8_t *parsekey(char *, uint_t *, uint_t *, char **);
 206 /* Note: in_get{prefilen,addr}, in6_getaddr stolen from ifconfig.c */
 207 static int in_getprefixlen(char *, boolean_t, int);
 208 static int in_getaddr(char *, struct sockaddr_storage *, int *, char **);
 209 static int in6_getaddr(char *, struct sockaddr_storage *, int *, char **);
 210 static boolean_t check_if_v6(char *);
 211 
 212 
 213 /*
 214  * Functions
 215  */
 216 
 217 /*
 218  * Check for same preshared entry.
 219  * Caller holds ps_rwlock as reader
 220  */
 221 static boolean_t
 222 same_psent(preshared_entry_t *ptr, preshared_entry_t *ps)
 223 {
 224         struct sockaddr_in      *ptr_v4, *ps_v4;
 225         struct sockaddr_in6     *ptr_v6, *ps_v6;
 226 
 227         assert(RW_LOCK_HELD(&ps_rwlock));
 228 
 229         /*
 230          * Check for duplicate entries.  Preshared type
 231          * of IPv4/IPv6 has a NULL locid/remid string and
 232          * has the sockaddr_storages structures populated.
 233          * All others store themselves in the aforementioned
 234          * strings.
 235          */
 236 
 237         /* Local and Remote ID types must match */
 238         if ((ptr->pe_locidtype != ps->pe_locidtype) ||
 239             (ptr->pe_remidtype != ps->pe_remidtype))
 240                 return (B_FALSE);
 241 
 242         /* Check local ids */
 243         switch (ptr->pe_locidtype) {
 244         case PS_ID_IP:
 245         case PS_ID_IP4:
 246         case PS_ID_SUBNET4:
 247                 ptr_v4 = (struct sockaddr_in *)&ptr->pe_locid_sa;
 248                 ps_v4 = (struct sockaddr_in *)&ps->pe_locid_sa;
 249                 if ((uint32_t)ptr_v4->sin_addr.s_addr !=
 250                     (uint32_t)ps_v4->sin_addr.s_addr)
 251                         return (B_FALSE);
 252                 /*
 253                  * Prefix length either same number or same error
 254                  * PS_PLEN_NO_PREFIX for non subnet
 255                  */
 256                 if (&ptr->pe_locid_plen != &ps->pe_locid_plen)
 257                         return (B_FALSE);
 258                 break;
 259         case PS_ID_IP6:
 260         case PS_ID_SUBNET6:
 261                 ptr_v6 = (struct sockaddr_in6 *)&ptr->pe_locid_sa;
 262                 ps_v6 = (struct sockaddr_in6 *)&ps->pe_locid_sa;
 263                 if (!(IN6_ARE_ADDR_EQUAL(&ptr_v6->sin6_addr,
 264                     &ps_v6->sin6_addr)))
 265                         return (B_FALSE);
 266                 /*
 267                  * Prefix length either same number or same error
 268                  * PS_PLEN_NO_PREFIX for non subnet
 269                  */
 270                 if (&ptr->pe_locid_plen != &ps->pe_locid_plen)
 271                         return (B_FALSE);
 272                 break;
 273         default:
 274                 if (strcmp(ptr->pe_locid, ps->pe_locid) != 0)
 275                                 return (B_FALSE);
 276         }
 277 
 278         /* Check remote ids */
 279         switch (ptr->pe_remidtype) {
 280         case PS_ID_IP:
 281         case PS_ID_IP4:
 282                 ptr_v4 = (struct sockaddr_in *)&ptr->pe_remid_sa;
 283                 ps_v4 = (struct sockaddr_in *)&ps->pe_remid_sa;
 284                 if ((uint32_t)ptr_v4->sin_addr.s_addr !=
 285                     (uint32_t)ps_v4->sin_addr.s_addr)
 286                         return (B_FALSE);
 287                 /*
 288                  * Prefix length either same number or same error
 289                  * PS_PLEN_NO_PREFIX for non subnet
 290                  */
 291                 if (&ptr->pe_remid_plen != &ps->pe_remid_plen)
 292                         return (B_FALSE);
 293                 break;
 294         case PS_ID_IP6:
 295                 ptr_v6 = (struct sockaddr_in6 *)&ptr->pe_remid_sa;
 296                 ps_v6 = (struct sockaddr_in6 *)&ps->pe_remid_sa;
 297                 if (!(IN6_ARE_ADDR_EQUAL(&ptr_v6->sin6_addr,
 298                     &ps_v6->sin6_addr)))
 299                         return (B_FALSE);
 300                 /*
 301                  * Prefix length either same number or same error
 302                  * PS_PLEN_NO_PREFIX for non subnet
 303                  */
 304                 if (&ptr->pe_remid_plen != &ps->pe_remid_plen)
 305                         return (B_FALSE);
 306                 break;
 307         default:
 308                 if (strcmp(ptr->pe_remid, ps->pe_remid) != 0)
 309                                 return (B_FALSE);
 310         }
 311         return (B_TRUE);
 312 }
 313 
 314 /*
 315  * Check for duplicate preshared entry.
 316  * Caller holds ps_rwlock as reader
 317  */
 318 static boolean_t
 319 has_dup(preshared_entry_t *ps, preshared_entry_t **head)
 320 {
 321         preshared_entry_t *ptr;
 322 
 323         assert(RW_LOCK_HELD(&ps_rwlock));
 324 
 325         if (ps == NULL) /* no op */
 326                 return (B_FALSE);
 327 
 328         ptr = *head;
 329 
 330         while (ptr != NULL) {
 331                 if (same_psent(ptr, ps))
 332                         return (B_TRUE);
 333                 ptr = ptr->pe_next;
 334         }
 335         return (B_FALSE);
 336 }
 337 
 338 /*
 339  * Append entries to list.
 340  * Caller holds ps_rwlock as writer
 341  */
 342 static boolean_t
 343 append_to_list(preshared_entry_t *ps, preshared_entry_t **head,
 344     preshared_entry_t **tail)
 345 {
 346         assert(RW_WRITE_HELD(&ps_rwlock));
 347 
 348         if (ps == NULL)         /* no op */
 349                 return (B_TRUE);
 350         assert(ps->pe_refcnt > 0);
 351         if (has_dup(ps, head)) {
 352                 (void) fprintf(stderr,
 353                     gettext("Ignoring duplicate preshared entry.\n"));
 354                 PE_REFRELE(ps);
 355                 return (B_FALSE);
 356         }
 357         ps->pe_next = NULL;  /* will be last entry */
 358         if (*head == NULL) {
 359                 /* list initialization  */
 360                 *head = *tail = ps;
 361         } else {
 362                 (*tail)->pe_next = ps;
 363                 *tail = (*tail)->pe_next;
 364         }
 365         return (B_TRUE);
 366 }
 367 
 368 /*
 369  * Appends preshared entry to list
 370  * Holds ps_rwlock as writer
 371  */
 372 boolean_t
 373 append_preshared_entry(preshared_entry_t *ps)
 374 {
 375         boolean_t rc;
 376 
 377         (void) pthread_rwlock_wrlock(&ps_rwlock);
 378         rc = append_to_list(ps, &ps_head, &ps_tail);
 379         (void) pthread_rwlock_unlock(&ps_rwlock);
 380         return (rc);
 381 }
 382 
 383 /*
 384  * Frees preshared list
 385  * Caller holds ps_rwlock as writer
 386  */
 387 static void
 388 free_preshared_list(preshared_entry_t **head, preshared_entry_t **tail)
 389 {
 390         preshared_entry_t       *ps;
 391 
 392         assert(RW_WRITE_HELD(&ps_rwlock));
 393 
 394         while (*head != NULL) {
 395                 /* Zero the old list in case of reloading. */
 396                 ps = *head;
 397                 if (ps == *tail)
 398                         *tail = NULL;
 399                 *head = ps->pe_next;
 400                 PE_REFRELE(ps);
 401         }
 402 }
 403 
 404 static char *
 405 getidstr(int val)
 406 {
 407         const keywdtab_t *idt;
 408 
 409         for (idt = idstab; idt < A_END(idstab); idt++) {
 410                 if (val == idt->kw_tag)
 411                         return (idt->kw_str);
 412         }
 413         return (NULL);          /* not found */
 414 }
 415 
 416 static int
 417 getidtype(char *valp)
 418 {
 419         const keywdtab_t *idt;
 420 
 421         for (idt = idstab; idt < A_END(idstab); idt++) {
 422                 if (strcasecmp(valp, idt->kw_str) == 0)
 423                         return (idt->kw_tag);
 424         }
 425         return (-1);            /* not found */
 426 }
 427 
 428 static int
 429 getfldtype(char *valp)
 430 {
 431         const keywdtab_t *fldt;
 432 
 433         for (fldt = fldstab; fldt < A_END(fldstab); fldt++) {
 434                 if (strcasecmp(valp, fldt->kw_str) == 0)
 435                         return (fldt->kw_tag);
 436         }
 437         return (-1);            /* not found */
 438 }
 439 
 440 static char *
 441 getikmstr(int val)
 442 {
 443         const keywdtab_t *idt;
 444 
 445         for (idt = ikmstab; idt < A_END(ikmstab); idt++) {
 446                 if (val == idt->kw_tag)
 447                         return (idt->kw_str);
 448         }
 449         return (NULL);          /* not found */
 450 }
 451 
 452 static int
 453 getikmtype(char *valp)
 454 {
 455         const keywdtab_t *ikmt;
 456 
 457         for (ikmt = ikmstab; ikmt < A_END(ikmstab); ikmt++) {
 458                 if (strcasecmp(valp, ikmt->kw_str) == 0)
 459                         return (ikmt->kw_tag);
 460         }
 461         return (-1);            /* not found */
 462 
 463 }
 464 
 465 /*
 466  * unlike the other get*str functions, this one mallocs the returned
 467  * string, so the caller will need to free it.
 468  */
 469 char *
 470 getkeystr(uint8_t *key, uint_t bytes, uint_t bits)
 471 {
 472         uint8_t *sp;
 473         char    *dp, *buf;
 474         uint_t  len;
 475 
 476         /* assume two digits per byte, and no more than 4 digits of bitlen */
 477         len = (bytes < 1) + 6;
 478         if ((buf = malloc(len)) == NULL)
 479                 return (NULL);
 480 
 481         sp = key;
 482         dp = buf;
 483         while (bytes-- != 0) {
 484                 (void) sprintf(dp, "%02x", *sp++);
 485                 dp += 2;
 486         }
 487         (void) sprintf(dp, "/%d", bits);
 488 
 489         return (buf);
 490 }
 491 
 492 /*
 493  * Parsing for hex key values.
 494  * Return value:
 495  *      Pointer to allocated buffer containing the key
 496  *      Parameter, "len" contains length of key buffer on successful return
 497  *      Parameter, "lbits" contains length of key in bits in the key buffer.
 498  * Note:Stolen from ipseckey.c and then adapted for use here.
 499  */
 500 static uint8_t *
 501 parsehexkey(char *input, uint_t *keybuflen, uint_t *lbits, char **errp)
 502 {
 503         uint8_t *keyp, *keybufp;
 504         uint_t i, hexlen = 0, bits, alloclen;
 505 
 506         for (i = 0; input[i] != CHR_NULL && input[i] != CHR_SLASH; i++)
 507                 hexlen++;
 508 
 509         if (input[i] == CHR_NULL) {
 510                 bits = 0;
 511         } else {
 512                 /* Have /nn. */
 513                 input[i] = CHR_NULL;
 514                 if (sscanf((input + i + 1), "%u", &bits) != 1) {
 515                         *errp = (char *)err_arr[ERR_INVALID_BIT_SPECIFIER];
 516                         return (NULL);
 517                 }
 518 
 519                 /* hexlen in nibbles */
 520                 if (((bits + 3) >> 2) > hexlen) {
 521                         *errp = (char *)err_arr[ERR_BITLEN2BIG];
 522                         return (NULL);
 523                 }
 524 
 525                 /*
 526                  * Adjust hexlen down if user gave us too small of a bit
 527                  * count.
 528                  */
 529                 if ((hexlen << 2) > bits + 3) {
 530                         /*
 531                          * NOTE: Callers don't necessarily handle warnings
 532                          * a successful return.
 533                          */
 534                         *errp = (char *)err_arr[ERR_WARN_LOWBITS_TRUNC];
 535                         hexlen = (bits + 3) >> 2;
 536                         input[hexlen] = CHR_NULL;
 537                 }
 538         }
 539 
 540         /*
 541          * Allocate.  Remember, hexlen is in nibbles.
 542          */
 543 
 544         alloclen = (hexlen/2 + (hexlen & 0x1));
 545         keyp = malloc(alloclen);
 546 
 547         if (keyp == NULL) {
 548                 *errp = strerror(errno);
 549                 return (NULL);
 550         }
 551 
 552         keybufp = keyp;
 553         *keybuflen = alloclen;
 554         if (bits == 0)
 555                 *lbits = (hexlen + (hexlen & 0x1)) << 2;
 556         else
 557                 *lbits = bits;
 558 
 559         /*
 560          * Read in nibbles.  Read in odd-numbered as shifted high.
 561          * (e.g. 123 becomes 0x1230).
 562          */
 563 
 564         for (i = 0; input[i] != CHR_NULL; i += 2) {
 565                 boolean_t second = (input[i + 1] != CHR_NULL);
 566 
 567                 if (!isxdigit(input[i]) ||
 568                     (!isxdigit(input[i + 1]) && second)) {
 569                         free(keybufp); /* free allocated memory on error */
 570                         *errp = (char *)err_arr[ERR_STRING_NOT_HEX];
 571                         return (NULL);
 572                 }
 573                 *keyp = (hd2num(input[i]) << 4);
 574                 if (second)
 575                         *keyp |= hd2num(input[i + 1]);
 576                 else
 577                         break;  /* out of for loop. */
 578                 keyp++;
 579         }
 580 
 581         /* bzero the remaining bits if we're a non-octet amount. */
 582         if (bits & 0x7)
 583                 *((input[i] == CHR_NULL) ? keyp - 1 : keyp) &=
 584                     0xff << (8 - (bits & 0x7));
 585         return (keybufp);
 586 }
 587 /*
 588  * Parsing for ASCII key values.
 589  * Return value:
 590  *      Pointer to allocated buffer containing the key
 591  *      Parameter, "len" contains length of key buffer on successful return
 592  *      Parameter, "lbits" contains length of key in bits in the key buffer.
 593  * Note:Stolen from ipseckey.c and then adapted for use here.
 594  */
 595 static uint8_t *
 596 parseasciikey(char *input, uint_t *keybuflen, uint_t *lbits, char **errp)
 597 {
 598         uint8_t *keyp, *keybufp;
 599         uint_t i, asciilen = 0;
 600 
 601         /* Make sure the first and last characters are '"', unescaped */
 602 
 603         if (input[0] != CHR_DOUBLEQUOTE)
 604                 goto invalid_ascii_string;
 605 
 606         /* Set pointer past first quote, then find the end */
 607         input++;
 608 
 609         for (i = 0; input[i] != CHR_NULL; i++)
 610                 asciilen++;
 611         /*
 612          * Length without trailing \0 and leading quote lopped off
 613          * from before must be at least 3 for a well formed key
 614          */
 615         if (--asciilen < 3)
 616                 goto invalid_ascii_string;
 617         /*
 618          * Make sure the last quote exists and is not escaped,
 619          * but also watch for valid "this string\\" syntax.
 620          */
 621         if (input[asciilen] != CHR_DOUBLEQUOTE)
 622                 goto invalid_ascii_string;
 623 
 624         /* We know we can dereference these because of length check above */
 625         if ((input[asciilen - 1] == CHR_BACKSLASH) &&
 626             (input[asciilen - 2] != CHR_BACKSLASH))
 627                 goto invalid_ascii_string;
 628 
 629         input[asciilen] = CHR_NULL;
 630 
 631         /* Now we have something well-formed in quotes and length set */
 632 
 633         /*
 634          * Allocate.  If we have backslashes, we can shrink later
 635          */
 636 
 637         keyp = malloc(asciilen);
 638         if (keyp == NULL) {
 639                 *errp = strerror(errno);
 640                 return (NULL);
 641         }
 642 
 643         keybufp = keyp;
 644         /*
 645          * Read in bytes, but be aware of next byte for escape purposes
 646          */
 647 
 648         for (i = 0; input[i] != CHR_NULL; i++) {
 649                 boolean_t second = (input[i + 1] != CHR_NULL);
 650 
 651                 if (!isascii(input[i]) ||
 652                     (second && !isascii(input[i + 1]))) {
 653                         goto free_key_buffer;
 654                 }
 655                 /*
 656                  * Consider backslash an escape character for
 657                  * itself, single and double quotes, but not
 658                  * for anything else
 659                  */
 660                 if (second && (input[i] == CHR_BACKSLASH)) {
 661                         if (input[i + 1] == CHR_DOUBLEQUOTE ||
 662                             input[i + 1] == CHR_BACKSLASH) {
 663                                 *keyp = input[i + 1];
 664                                 i++;
 665                                 keyp++;
 666                                 asciilen--;
 667                                 continue; /* for loop */
 668                         }
 669                 }
 670                 *keyp = input[i];
 671                 keyp++;
 672         }
 673         /* Shrink to fit */
 674         *keybuflen = asciilen;
 675         *lbits = asciilen << 3;
 676         keybufp = realloc(keybufp, asciilen);
 677 
 678         return (keybufp);
 679 
 680 free_key_buffer:
 681         free(keybufp);
 682 invalid_ascii_string:
 683         *errp = (char *)err_arr[ERR_INVALID_ASCII_STRING];
 684         return (NULL);
 685 }
 686 
 687 static uint8_t *
 688 parsekey(char *input, uint_t *keybuflen, uint_t *lbits, char **errp)
 689 {
 690         /* Determine if this is an ASCII key or hex key */
 691         if (input[0] == CHR_DOUBLEQUOTE) {
 692                 return (parseasciikey(input, keybuflen, lbits, errp));
 693         } else {
 694                 return (parsehexkey(input, keybuflen, lbits, errp));
 695         }
 696 }
 697 
 698 static boolean_t
 699 check_if_v6(char *abuf)
 700 {
 701         char *cp;
 702         for (cp = abuf; *cp != CHR_NULL; cp++) {
 703                 if (*cp == CHR_COLON)
 704                         return (B_TRUE);
 705         }
 706         return (B_FALSE);
 707 }
 708 
 709 static boolean_t
 710 valid_ip6_address(struct sockaddr_in6 *addr, char **errmsgp)
 711 {
 712 
 713                 /* is it mcast */
 714                 if (IN6_IS_ADDR_MULTICAST(&addr->sin6_addr)) {
 715                         *errmsgp = (char *)err_arr[ERR_BADADDR_MCAST];
 716                         return (B_FALSE);
 717                 }
 718                 /* is it v4 mapped */
 719                 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
 720                         *errmsgp = (char *)err_arr[ERR_BADADDR_4MAPPED];
 721                         return (B_FALSE);
 722                 }
 723                 /* is it v4 compat */
 724                 if (IN6_IS_ADDR_V4COMPAT(&addr->sin6_addr)) {
 725                         *errmsgp = (char *)err_arr[ERR_BADADDR_4COMPAT];
 726                         return (B_FALSE);
 727                 }
 728 
 729                 return (B_TRUE);
 730 }
 731 
 732 /*
 733  * Post process preshared key entry.
 734  * Caller holds ps_rwlock as reader
 735  */
 736 static int
 737 postprocess_entry(preshared_entry_t *ps, char **errmsgp)
 738 {
 739         assert(RW_LOCK_HELD(&ps_rwlock));
 740 
 741         /* ID types default to IP. */
 742         if ((ps->pe_flds_mask & PS_FLD_LOCID_TYPE) == 0) {
 743                 ps->pe_flds_mask |= PS_FLD_LOCID_TYPE;
 744                 ps->pe_locidtype = PS_ID_IP;
 745         }
 746         if ((ps->pe_flds_mask & PS_FLD_REMID_TYPE) == 0) {
 747                 ps->pe_flds_mask |= PS_FLD_REMID_TYPE;
 748                 ps->pe_remidtype = PS_ID_IP;
 749         }
 750 
 751         /*
 752          * Verify that all mandatory fields are there.
 753          * mandatory:  local_id and remote_id (or local_addr and remote_addr),
 754          * mode, and key.
 755          */
 756 
 757         /*
 758          * Note: verify that semantic relationships among fields is fine
 759          * Since we only support main mode, we force the mode to be main.
 760          */
 761 
 762         ps->pe_ike_mode = PS_IKM_MAIN;
 763         if ((ps->pe_locidtype != PS_ID_IP) &&
 764             (ps->pe_locidtype != PS_ID_IP4) &&
 765             (ps->pe_locidtype != PS_ID_IP6)) {
 766                 *errmsgp = (char *)err_arr[ERR_MAINMODE_LOCID_NOTIP];
 767                 return (-1);
 768         }
 769         if ((ps->pe_remidtype != PS_ID_IP) &&
 770             (ps->pe_remidtype != PS_ID_IP4) &&
 771             (ps->pe_remidtype != PS_ID_IP6)) {
 772                 *errmsgp = (char *)err_arr[ERR_MAINMODE_REMID_NOTIP];
 773                 return (-1);
 774         }
 775 
 776         /*
 777          * Parse "id" values now and verify that they match the
 778          * "idtype" associated with them.
 779          * NOTE: Real work is TBD
 780          */
 781         if (ps->pe_flds_mask & PS_FLD_LOCID_TYPE) {
 782                 int retval;
 783 
 784                 if (ps->pe_locid == NULL) {
 785                         *errmsgp = (char *)err_arr[ERR_MISSING_LOCALID];
 786                         return (-1);
 787                 }
 788 
 789                 switch (ps->pe_locidtype) {
 790                 case PS_ID_IP:
 791                 {
 792                         boolean_t isv6 = check_if_v6(ps->pe_locid);
 793                         if (isv6) {
 794                                 ps->pe_locidtype = PS_ID_IP6;
 795                                 retval = in6_getaddr(ps->pe_locid,
 796                                     &ps->pe_locid_sa, &ps->pe_locid_plen,
 797                                     errmsgp);
 798                         } else {
 799                                 ps->pe_locidtype = PS_ID_IP4;
 800                                 retval = in_getaddr(ps->pe_locid,
 801                                     &ps->pe_locid_sa, &ps->pe_locid_plen,
 802                                     errmsgp);
 803                         }
 804                         if (retval < 0)
 805                                 return (-1);
 806                 }
 807                 break;
 808                 case PS_ID_IP4:
 809                 case PS_ID_SUBNET4:
 810                         retval = in_getaddr(ps->pe_locid, &ps->pe_locid_sa,
 811                             &ps->pe_locid_plen, errmsgp);
 812                         if (retval < 0)
 813                                 return (-1);
 814                         break;
 815                 case PS_ID_IP6:
 816                 case PS_ID_SUBNET6:
 817                         retval = in6_getaddr(ps->pe_locid, &ps->pe_locid_sa,
 818                             &ps->pe_locid_plen, errmsgp);
 819                         if (retval < 0)
 820                                 return (-1);
 821                         break;
 822                 case PS_ID_SUBNET:
 823                 {
 824                         boolean_t isv6 = check_if_v6(ps->pe_locid);
 825                         if (isv6) {
 826                                 ps->pe_locidtype = PS_ID_SUBNET6;
 827                                 retval = in6_getaddr(ps->pe_locid,
 828                                     &ps->pe_locid_sa, &ps->pe_locid_plen,
 829                                     errmsgp);
 830                         } else {
 831                                 ps->pe_locidtype = PS_ID_SUBNET4;
 832                                 retval = in_getaddr(ps->pe_locid,
 833                                     &ps->pe_locid_sa, &ps->pe_locid_plen,
 834                                     errmsgp);
 835                         }
 836                         if (retval < 0)
 837                                 return (-1);
 838                 }
 839                 break;
 840                 case PS_ID_RANGE:
 841                         break;
 842                 case PS_ID_RANGE4:
 843                         break;
 844                 case PS_ID_RANGE6:
 845                         break;
 846                 case PS_ID_ASN1DN:
 847                         break;
 848                 case PS_ID_ASN1GN:
 849                         break;
 850                 case PS_ID_KEYID:
 851                         break;
 852                 case PS_ID_FQDN:
 853                         break;
 854                 case PS_ID_USER_FQDN:
 855                         break;
 856                 }
 857         }
 858         if (ps->pe_flds_mask & PS_FLD_REMID_TYPE) {
 859                 int retval;
 860 
 861                 if (ps->pe_remid == NULL) {
 862                         *errmsgp = (char *)err_arr[ERR_MISSING_REMID];
 863                         return (-1);
 864                 }
 865                 switch (ps->pe_remidtype) {
 866                 case PS_ID_IP:
 867                 {
 868                         boolean_t isv6 = check_if_v6(ps->pe_remid);
 869                         if (isv6) {
 870                                 ps->pe_remidtype = PS_ID_IP6;
 871                                 retval = in6_getaddr(ps->pe_remid,
 872                                     &ps->pe_remid_sa, &ps->pe_remid_plen,
 873                                     errmsgp);
 874                         } else {
 875                                 ps->pe_remidtype = PS_ID_IP4;
 876                                 retval = in_getaddr(ps->pe_remid,
 877                                     &ps->pe_remid_sa, &ps->pe_remid_plen,
 878                                     errmsgp);
 879                         }
 880                         if (retval < 0)
 881                                 return (-1);
 882                 }
 883                 break;
 884                 case PS_ID_IP4:
 885                 case PS_ID_SUBNET4:
 886                         retval = in_getaddr(ps->pe_remid, &ps->pe_remid_sa,
 887                             &ps->pe_remid_plen, errmsgp);
 888                         if (retval < 0)
 889                                 return (-1);
 890                         break;
 891                 case PS_ID_IP6:
 892                 case PS_ID_SUBNET6:
 893                         retval = in6_getaddr(ps->pe_remid, &ps->pe_remid_sa,
 894                             &ps->pe_remid_plen, errmsgp);
 895                         if (retval < 0)
 896                                 return (-1);
 897                         break;
 898                 case PS_ID_SUBNET:
 899                 {
 900                         boolean_t isv6 = check_if_v6(ps->pe_remid);
 901                         if (isv6) {
 902                                 ps->pe_remidtype = PS_ID_SUBNET6;
 903                                 retval = in6_getaddr(ps->pe_remid,
 904                                     &ps->pe_remid_sa, &ps->pe_remid_plen,
 905                                     errmsgp);
 906                         } else {
 907                                 ps->pe_remidtype = PS_ID_SUBNET4;
 908                                 retval = in_getaddr(ps->pe_remid,
 909                                     &ps->pe_remid_sa, &ps->pe_remid_plen,
 910                                     errmsgp);
 911                         }
 912                         if (retval < 0)
 913                                 return (-1);
 914                 }
 915                 break;
 916                 case PS_ID_RANGE:
 917                         break;
 918                 case PS_ID_RANGE4:
 919                         break;
 920                 case PS_ID_RANGE6:
 921                         break;
 922                 case PS_ID_ASN1DN:
 923                         break;
 924                 case PS_ID_ASN1GN:
 925                         break;
 926                 case PS_ID_KEYID:
 927                         break;
 928                 case PS_ID_FQDN:
 929                         break;
 930                 case PS_ID_USER_FQDN:
 931                         break;
 932                 }
 933         }
 934 
 935         /*
 936          * Reality check address families
 937          * Remote and local address families must match
 938          */
 939         if (check_if_v6(ps->pe_locid) != check_if_v6(ps->pe_remid)) {
 940                 *errmsgp = (char *)err_arr[ERR_BADADDR_MISMATCH];
 941                 return (-1);
 942         }
 943 
 944         /* v6 */
 945         if (ps->pe_remidtype == PS_ID_IP6 ||
 946             ps->pe_remidtype == PS_ID_SUBNET6) {
 947                 struct sockaddr_in6 *local =
 948                     (struct sockaddr_in6 *)(&ps->pe_locid_sa);
 949                 struct sockaddr_in6 *remote =
 950                     (struct sockaddr_in6 *)(&ps->pe_remid_sa);
 951 
 952                 if (!valid_ip6_address(local, errmsgp) ||
 953                     !valid_ip6_address(remote, errmsgp)) {
 954                         return (-1);
 955                 }
 956         } else {
 957                 /* v4 */
 958                 struct sockaddr_in *local =
 959                     (struct sockaddr_in *)(&ps->pe_locid_sa);
 960                 struct sockaddr_in *remote =
 961                     (struct sockaddr_in *)(&ps->pe_remid_sa);
 962 
 963                 /* are either mcast */
 964                 if (IN_MULTICAST(ntohl(local->sin_addr.s_addr)) ||
 965                     IN_MULTICAST(ntohl(remote->sin_addr.s_addr))) {
 966                         *errmsgp = (char *)err_arr[ERR_BADADDR_MCAST];
 967                         return (-1);
 968                 }
 969         }
 970 
 971         return (0);             /* OK return */
 972 }
 973 
 974 /*
 975  * Note: Code stolen from ifconfig.c and adapted.
 976  *
 977  * If "slash" is zero this parses the whole string as
 978  * an integer. With "slash" non zero it parses the tail part as an integer.
 979  *
 980  * If it is not a valid integer this returns BAD_ADDR.
 981  * If there is /<n> present this returns PS_PLEN_NO_PREFIX.
 982  */
 983 static int
 984 in_getprefixlen(char *addr, boolean_t slash, int max_plen)
 985 {
 986         int prefixlen;
 987         char *str, *end;
 988 
 989         if (slash) {
 990                 str = strchr(addr, CHR_SLASH);
 991                 if (str == NULL)
 992                         return (PS_PLEN_NO_PREFIX);
 993                 str++;
 994         } else
 995                 str = addr;
 996 
 997         prefixlen = strtol(str, &end, 10);
 998         if (prefixlen < 0)
 999                 return (PS_PLEN_BAD_ADDR);
1000         if (str == end)
1001                 return (PS_PLEN_BAD_ADDR);
1002         if (max_plen != 0 && max_plen < prefixlen)
1003                 return (PS_PLEN_BAD_ADDR);
1004         return (prefixlen);
1005 }
1006 
1007 
1008 /*
1009  * Note: code stolen from ifconfig.c and adapted
1010  *
1011  * If the last argument is non-NULL allow a <addr>/<n> syntax and
1012  * pass out <n> in *plenp.
1013  * If <n> doesn't parse return PS_PLEN_BAD_ADDR as *plenp.
1014  * If no /<n> is present return PS_PLEN_NO_PREFIX as *plenp.
1015  */
1016 static int
1017 in_getaddr(char *s, struct sockaddr_storage *saddr, int *plenp, char **errp)
1018 {
1019         struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
1020         struct hostent *hp;
1021         struct netent *np;
1022         char str[BUFSIZ];
1023         int error_num;
1024 
1025         (void) strncpy(str, s, sizeof (str));
1026 
1027         /*
1028          * Look for '/'<n> (CHR_SLASH)is plenp
1029          */
1030         if (plenp != NULL) {
1031                 char *cp;
1032 
1033                 *plenp = in_getprefixlen(str, B_TRUE, ADDRBITS_V4);
1034                 if (*plenp == PS_PLEN_BAD_ADDR) {
1035                         *errp = (char *)err_arr[ERR_BADADDR_PREFIXLEN_PART];
1036                         return (-1);
1037                 }
1038                 cp = strchr(str, CHR_SLASH);
1039                 if (cp != NULL)
1040                         *cp = CHR_NULL;
1041         } else if (strchr(str, CHR_SLASH) != NULL) {
1042                 *errp = (char *)err_arr[ERR_BADADDR_SLASH_UNEXPECTED];
1043                 return (-1);
1044         }
1045 
1046         (void) memset(sin, 0, sizeof (*sin));
1047 
1048         /*
1049          *      Try to catch attempts to set the broadcast address to all 1's.
1050          */
1051         if (strcmp(str, "255.255.255.255") == 0 ||
1052             (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) {
1053                 sin->sin_family = AF_INET;
1054                 sin->sin_addr.s_addr = 0xffffffff;
1055                 return (0);
1056         }
1057 
1058         hp = getipnodebyname(str, AF_INET, 0, &error_num);
1059         if (hp) {
1060                 sin->sin_family = hp->h_addrtype;
1061                 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1062                 freehostent(hp);
1063                 return (0);
1064         }
1065         np = getnetbyname(str);
1066         if (np) {
1067                 sin->sin_family = np->n_addrtype;
1068                 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1069                 return (0);
1070         }
1071         if (error_num == TRY_AGAIN) {
1072                 *errp = (char *)err_arr[ERR_BADADDR_TRY_AGAIN];
1073         } else {
1074                 *errp = (char *)err_arr[ERR_BADADDR_ADDRESS];
1075         }
1076         return (-1);
1077 }
1078 
1079 /*
1080  * Note: Code stolen from ifconfig.c and adapted.
1081  *
1082  * If the third argument is non-NULL allow a <addr>/<n> syntax and
1083  * pass out <n> in *plenp.
1084  * If <n> doesn't parse return PS_PLEN_BAD_ADDR as *plenp.
1085  * If no /<n> is present return PS_PLEN_NO_PREFIX as *plenp.
1086  */
1087 static int
1088 in6_getaddr(char *s, struct sockaddr_storage *saddr, int *plenp, char **errp)
1089 {
1090         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
1091         struct hostent *hp;
1092         char str[BUFSIZ];
1093         int error_num;
1094 
1095         (void) strncpy(str, s, sizeof (str));
1096 
1097         /*
1098          * Look for '/'<n> (CHR_SLASH) is plenp
1099          */
1100         if (plenp != NULL) {
1101                 char *cp;
1102 
1103                 *plenp = in_getprefixlen(str, B_TRUE, ADDRBITS_V6);
1104                 if (*plenp == PS_PLEN_BAD_ADDR) {
1105                         *errp = (char *)err_arr[ERR_BADADDR_PREFIXLEN_PART];
1106                         return (-1);
1107                 }
1108                 cp = strchr(str, CHR_SLASH);
1109                 if (cp != NULL)
1110                         *cp = CHR_NULL;
1111         } else if (strchr(str, CHR_SLASH) != NULL) {
1112                 *errp = (char *)err_arr[ERR_BADADDR_SLASH_UNEXPECTED];
1113                 return (-1);
1114         }
1115 
1116         (void) memset(sin6, 0, sizeof (*sin6));
1117 
1118         hp = getipnodebyname(str, AF_INET6, 0, &error_num);
1119         if (hp) {
1120                 sin6->sin6_family = hp->h_addrtype;
1121                 (void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length);
1122                 freehostent(hp);
1123                 return (0);
1124         }
1125         if (error_num == TRY_AGAIN) {
1126                 *errp = (char *)err_arr[ERR_BADADDR_TRY_AGAIN];
1127         } else {
1128                 *errp = (char *)err_arr[ERR_BADADDR_ADDRESS];
1129         }
1130         return (-1);
1131 }
1132 
1133 /*
1134  * char *get_next_token(cpp)
1135  *      cpp - on input should point within a null terminated buffer.
1136  *      return value - on output will point to past spaces to first
1137  *              non-space character that starts a token
1138  *      cpp - on output will point past non-space token string pointed
1139  *              by return value.
1140  *      Side-effects: modifies a potential space character after token
1141  *              to null to form  a null terminated token unless a
1142  *              double-quote has been seen in the token
1143  */
1144 static char *
1145 get_next_token(char **cpp)
1146 {
1147         char *cp = *cpp;
1148         char *startcp, *endcp;
1149         boolean_t quote_seen = B_FALSE;
1150 
1151         /* skip leading whitespaces */
1152         while (*cp == CHR_SPACE || *cp == CHR_TAB || *cp == CHR_NEWLINE)
1153                 cp++;
1154 
1155         if (*cp == CHR_NULL) {  /* end of string */
1156                 *cpp = NULL;
1157                 return (NULL);
1158         }
1159 
1160         startcp = endcp = cp;
1161         while (*endcp != CHR_NULL &&
1162             ((*endcp != CHR_SPACE && *endcp != CHR_TAB) || quote_seen) &&
1163             *endcp != CHR_NEWLINE) {
1164                 /*
1165                  * Within quotes, ignore spaces and tabs as delimiters
1166                  * and take note of start and end quotes, ignoring
1167                  * backslash escaped characters.
1168                  */
1169                 if (*endcp == CHR_DOUBLEQUOTE &&
1170                     ((endcp == startcp) ||
1171                     ((endcp > startcp) && *(endcp - 1) != CHR_BACKSLASH)))
1172                         quote_seen = !quote_seen;
1173                 endcp++;
1174         }
1175         if (*endcp != CHR_NULL)
1176                 *endcp++ = CHR_NULL;
1177         *cpp = endcp;
1178         return (startcp);
1179 }
1180 
1181 static char *
1182 readnextline(FILE *fp)
1183 {
1184         char *cp;
1185 
1186         while ((cp = fgets(linebuf, sizeof (linebuf), fp)) != NULL) {
1187                 err_line_number++; /* NOTE approx - if long lines */
1188                 if (*cp == CHR_NEWLINE || *cp == CHR_COMMENT_BEGIN)
1189                         continue;
1190                 break;
1191         }
1192         if (cp == NULL)
1193                 return (NULL);
1194         return (linebuf);
1195 }
1196 
1197 
1198 /*
1199  * static preshared_entry_t *getnextentry(fp, errmpp)
1200  *      fp
1201  *              file pointer to open config file.
1202  *      errmpp
1203  *              pointer to pointer to buffer containing error message
1204  *      return value
1205  *              NULL when EOF is reached
1206  *              pointer to valid entry otherwise
1207  *
1208  *      Function scans open input file to get the next entry read from
1209  *      the file and instantiated in the preshared_entry_t data structure.
1210  *      In case of invalid syntax entries the function exits and does
1211  *      not return and process exits.
1212  *
1213  *      Caller holds ps_rwlock as reader.
1214  */
1215 static preshared_entry_t *
1216 getnextentry(FILE *fp, char **errmpp)
1217 {
1218         preshared_entry_t *ps;
1219         char *cp;               /* pointer to scan input */
1220         char *tp;
1221         char *errmsg = NULL;
1222         int cur_fld_type = -1;  /* "uninitialized" */
1223         int entry_done = FALSE;
1224         int next_token_expected = PS_TOK_BEGIN_CURLY_BRACE;
1225 
1226         assert(RW_LOCK_HELD(&ps_rwlock));
1227 
1228         *errmpp = NULL;
1229 
1230         ps = calloc(1, sizeof (preshared_entry_t));     /* Auto-zeroes... */
1231         if (ps == NULL) {
1232                 errmsg = strerror(errno);
1233                 goto fatal_error;
1234         }
1235         ps->pe_refcnt = 1;
1236 nextline:
1237         /* get next line  */
1238 
1239         /* skip comment and null lines */
1240         while (((cp = readnextline(fp)) != NULL) &&
1241             (*cp == CHR_COMMENT_BEGIN || *cp == CHR_NULL))
1242                 ;
1243 
1244         if (cp == NULL) {
1245                 /* EOF  */
1246                 PE_REFRELE(ps);
1247                 return (NULL);
1248         }
1249 
1250         for (;;) {
1251                 if (entry_done == TRUE)
1252                         break;
1253                 tp = get_next_token(&cp);
1254                 if (tp == NULL)
1255                         goto nextline;
1256 process_newtoken:
1257                 /* skip rest of line if comment token */
1258                 if (*tp == CHR_COMMENT_BEGIN)
1259                         goto nextline;
1260 
1261                 switch (next_token_expected) {
1262 
1263                 case PS_TOK_BEGIN_CURLY_BRACE:
1264                         if (*tp != CHR_CURLY_BRACE_OPEN) {
1265                                 errmsg = (char *)err_arr[
1266                                     ERR_ENTRY_NOBEGINBRACE];
1267                                 goto bad_syntax;
1268                         }
1269                         err_entry_number++;
1270                         next_token_expected = PS_TOK_FLD_TYPE;
1271 
1272                         /*
1273                          * Note: We skip tokens assuming whitespace
1274                          * termination but relax that for this token.
1275                          *
1276                          * Reset scan pointer past this token (one character)
1277                          * so pointer does not miss any tokens that may
1278                          * be glued to this one with no whitespaces.
1279                          */
1280                         tp++;   /* past brace */
1281                         if (*tp == CHR_NULL) {
1282                                 /* past whitespace terminated brace */
1283                                 tp++;
1284                         }
1285                         cp = tp;
1286                         break;
1287 
1288                 case PS_TOK_END_CURLY_BRACE:
1289                         /*
1290                          * Do sanity checks on entry and other
1291                          * post-processing
1292                          */
1293                         if (postprocess_entry(ps, &errmsg) < 0)
1294                                 goto bad_semantics;
1295                         entry_done = TRUE;
1296                         break;
1297 
1298                 case PS_TOK_FLD_TYPE:
1299                         /*
1300                          * Note: could be end-of-entry too...
1301                          * here we assume the closing brace is
1302                          * preceded by a whitespace. We gave some latitude to
1303                          * opening brace, but not to the closing brace
1304                          */
1305                         if (*tp == CHR_CURLY_BRACE_CLOSE) {
1306                                 /*
1307                                  * End of fields, reset expected token,
1308                                  * Also reset scan token so this
1309                                  */
1310                                 next_token_expected = PS_TOK_END_CURLY_BRACE;
1311                                 goto process_newtoken;
1312                         }
1313 
1314                         /* initialize cur_fld_type */
1315                         if ((cur_fld_type = getfldtype(tp)) < 0) {
1316                                 errmsg = (char *)err_arr[ERR_INVALID_FIELDNAME];
1317                                 goto bad_syntax;
1318                         }
1319 
1320                         if ((ps->pe_flds_mask & cur_fld_type) != 0) {
1321                                 errmsg = (char *)err_arr[ERR_REPEATED_FIELD];
1322                                 goto bad_syntax;
1323                         }
1324 
1325                         ps->pe_flds_mask |= cur_fld_type;
1326 
1327                         next_token_expected = PS_TOK_FLD_VALUE;
1328                         break;
1329 
1330                 case PS_TOK_FLD_VALUE:
1331 
1332                         /*
1333                          * Note: we assume all value fields do
1334                          * not embed any whitespace even for complicated
1335                          * value syntax such as for "range". Is that a
1336                          * "reasonable" assumption ?
1337                          *
1338                          * Note++: All things being strdup()'d below need
1339                          * to be parsed and put into context dependent data
1340                          * structures at some point (after entry is read or
1341                          * right here).
1342                          */
1343                         switch (cur_fld_type) {
1344                         case PS_FLD_LOCID_TYPE:
1345                                 if ((ps->pe_locidtype = getidtype(tp)) < 0) {
1346                                         errmsg = (char *)err_arr[
1347                                             ERR_INVALID_LOCALID_TYPE];
1348                                         goto bad_syntax;
1349                                 }
1350                                 break;
1351                         case PS_FLD_LOCID:
1352                                 ps->pe_locid = strdup(tp);
1353                                 if (ps->pe_locid == NULL) {
1354                                         errmsg = strerror(errno);
1355                                         goto fatal_error;
1356                                 }
1357                                 break;
1358                         case PS_FLD_REMID_TYPE:
1359                                 if ((ps->pe_remidtype = getidtype(tp)) < 0) {
1360                                         errmsg = (char *)err_arr[
1361                                             ERR_INVALID_REMID_TYPE];
1362                                         goto bad_syntax;
1363                                 }
1364                                 break;
1365                         case PS_FLD_REMID:
1366                                 ps->pe_remid = strdup(tp);
1367                                 if (ps->pe_remid == NULL) {
1368                                         errmsg = strerror(errno);
1369                                         goto fatal_error;
1370                                 }
1371                                 break;
1372                         case PS_FLD_IKE_MODE:
1373                                 if ((ps->pe_ike_mode = getikmtype(tp)) < 0) {
1374                                         errmsg = (char *)err_arr[
1375                                             ERR_INVALID_IKE_MODE];
1376                                         goto bad_syntax;
1377                                 }
1378                                 break;
1379                         case PS_FLD_KEY:
1380                                 ps->pe_keybuf = parsekey(tp,
1381                                     &ps->pe_keybuf_bytes,
1382                                     &ps->pe_keybuf_lbits, &errmsg);
1383                                 if (ps->pe_keybuf == NULL)
1384                                         goto fatal_error;
1385                                 else if (errmsg != NULL) {
1386                                         /*
1387                                          * Utter warning on otherwise okay
1388                                          * input.
1389                                          */
1390                                         (void) fprintf(stderr,
1391                                             gettext("read_preshared: %s\n"),
1392                                             errmsg);
1393                                 }
1394                                 break;
1395                         default:
1396                                 /* Should never happen - assert ? */
1397                                 errmsg = (char *)err_arr[
1398                                     ERR_INVALID_FIELDNAME];
1399                                 goto fatal_error;
1400                         }
1401 
1402                         next_token_expected = PS_TOK_FLD_TYPE;
1403                         break;
1404                 }
1405         }
1406         return (ps);
1407         /*
1408          * TBD any differentiation in these errors ?
1409          */
1410 bad_semantics:
1411 bad_syntax:
1412 fatal_error:
1413         if (ps != NULL)
1414                 PE_REFRELE(ps);
1415         *errmpp = errmsg;
1416         return (NULL);
1417 }
1418 
1419 
1420 /*
1421  * Load any preshared keys.
1422  * Boolean parameter 'replace' determines whether the newly-read entries
1423  * will replace the existing list, or be appended to it.
1424  * On success, returns a linked list of preshared entries, and sets the
1425  * error message pointer *errmp to NULL.
1426  * On failure, returns NULL and sets *errmp to an error message string.
1427  *
1428  * Holds ps_rwlock as writer.
1429  */
1430 char *
1431 preshared_load(const char *ps_filename, int ps_fd, boolean_t replace)
1432 {
1433         preshared_entry_t *ps, *tmp_head = NULL, *tmp_tail = NULL;
1434         char *errmp;
1435         boolean_t dupfound = B_FALSE;
1436 
1437         (void) pthread_rwlock_wrlock(&ps_rwlock);
1438 
1439         /* TODO more paranoia/permissions checks on file needed */
1440 
1441         if (ps_filename == NULL)
1442                 fp = fdopen(ps_fd, "r");
1443         else
1444                 fp = fopen(ps_filename, "r");
1445         if (fp == NULL) {
1446                 (void) pthread_rwlock_unlock(&ps_rwlock);
1447                 if (errno == ENOENT)
1448                         return (NULL);  /* no file == empty file */
1449                 return (strerror(errno));
1450         }
1451 
1452         while ((ps = getnextentry(fp, &errmp)) != NULL) {
1453                 /* process the new entry */
1454 
1455                 /*
1456                  * For now, create a list of just the new entries
1457                  */
1458                 if (!replace) {
1459                         if (has_dup(ps, &ps_head)) {
1460                                 /* Skip duplicates in master list */
1461                                 PE_REFRELE(ps);
1462                                 dupfound = B_TRUE;
1463                                 continue;
1464                         }
1465                 }
1466                 assert(ps->pe_refcnt >= 1);
1467                 if (!append_to_list(ps, &tmp_head, &tmp_tail)) {
1468                         /* Duplicate found within new list */
1469                         dupfound = B_TRUE;
1470                 }
1471         }
1472 
1473         (void) fclose(fp);
1474 
1475         if (errmp == NULL) {
1476                 /*
1477                  * we read the list in successfully; either
1478                  * replace or append to global list now.
1479                  */
1480                 if (replace || ps_tail == NULL) {
1481                         free_preshared_list(&ps_head, &ps_tail);
1482                         ps_head = tmp_head;
1483                         ps_tail = tmp_tail;
1484                 } else {
1485                         ps_tail->pe_next = tmp_head;
1486                         ps_tail = tmp_tail;
1487                 }
1488         } else {
1489                 /*
1490                  * had problems reading new list; free it
1491                  */
1492                 free_preshared_list(&tmp_head, &tmp_tail);
1493         }
1494 
1495         if (dupfound && (errmp == NULL)) {
1496                 /* Hack to key off of later, not user visible */
1497                 (void) pthread_rwlock_unlock(&ps_rwlock);
1498                 return ("DUP");
1499         }
1500 
1501         (void) pthread_rwlock_unlock(&ps_rwlock);
1502         return (errmp);
1503 }
1504 
1505 /*
1506  * Returns 0 if requested entry not found; 1 if deleted successfully.
1507  * Holds ps_rwlock as writer.
1508  */
1509 int
1510 delete_ps(preshared_entry_t *delp)
1511 {
1512         preshared_entry_t       *curp, *prevp;
1513 
1514         (void) pthread_rwlock_wrlock(&ps_rwlock);
1515         if (ps_head == NULL) {
1516                 (void) pthread_rwlock_unlock(&ps_rwlock);
1517                 return (0);
1518         }
1519 
1520         if (delp == ps_head) {
1521                 /* CORNER CASE: Deletion of last entry */
1522                 if (ps_head == ps_tail)
1523                         ps_tail = NULL;
1524                 ps_head = delp->pe_next;
1525                 (void) pthread_rwlock_unlock(&ps_rwlock);
1526                 PE_REFRELE(delp);
1527                 return (1);
1528         }
1529 
1530         for (prevp = ps_head, curp = ps_head->pe_next; curp != NULL;
1531             prevp = curp, curp = curp->pe_next) {
1532                 if (curp == delp)
1533                         break;
1534         }
1535         if (curp == NULL) {
1536                 (void) pthread_rwlock_unlock(&ps_rwlock);
1537                 return (0);
1538         }
1539 
1540         prevp->pe_next = curp->pe_next;
1541         if (curp == ps_tail)
1542                 ps_tail = prevp;
1543         (void) pthread_rwlock_unlock(&ps_rwlock);
1544         PE_REFRELE(curp);
1545         return (1);
1546 }
1547 
1548 /*
1549  * return -1 on error, number of preshared entries written on success
1550  * Holds ps_rwlock as reader
1551  */
1552 int
1553 write_preshared(int fd, char **errmp)
1554 {
1555         preshared_entry_t       *pep;
1556         FILE    *ofile;
1557         char    *keyp;
1558         int     written = 0;
1559 
1560         (void) pthread_rwlock_rdlock(&ps_rwlock);
1561         if ((ofile = fdopen(fd, "w+")) == NULL) {
1562                 *errmp = strerror(errno);
1563                 (void) pthread_rwlock_unlock(&ps_rwlock);
1564                 return (-1);
1565         }
1566 
1567         for (pep = ps_head; pep != NULL; pep = pep->pe_next) {
1568                 const char *mdstr;
1569 
1570                 if ((keyp = getkeystr(pep->pe_keybuf, pep->pe_keybuf_bytes,
1571                     pep->pe_keybuf_lbits)) == NULL) {
1572                         *errmp = strerror(errno);
1573                         (void) pthread_rwlock_unlock(&ps_rwlock);
1574                         return (-1);
1575                 }
1576 
1577                 if (pep->pe_locid != NULL) {
1578                         (void) fprintf(ofile, "{\n"
1579                             "\tlocalidtype    %s\n\tlocalid        %s\n",
1580                             getidstr(pep->pe_locidtype), pep->pe_locid);
1581                 } else {
1582                         (void) fprintf(ofile,
1583                             "{\n\tlocalidtype    %s\n\tlocalid        ",
1584                             getidstr(pep->pe_locidtype));
1585                         (void) dump_sockaddr(
1586                             (struct sockaddr *)&pep->pe_locid_sa,
1587                             (pep->pe_locid_plen > 0) ? pep->pe_locid_plen : 0,
1588                             B_TRUE, ofile, B_FALSE);
1589                         (void) fprintf(ofile, "\n");
1590                 }
1591 
1592                 if (pep->pe_remid != NULL) {
1593                         (void) fprintf(ofile,
1594                             "\tremoteidtype   %s\n\tremoteid       %s\n",
1595                             getidstr(pep->pe_remidtype), pep->pe_remid);
1596                 } else {
1597                         (void) fprintf(ofile,
1598                             "\tremoteidtype   %s\n\tremoteid       ",
1599                             getidstr(pep->pe_remidtype));
1600                         (void) dump_sockaddr(
1601                             (struct sockaddr *)&pep->pe_remid_sa,
1602                             (pep->pe_remid_plen > 0) ? pep->pe_remid_plen : 0,
1603                             B_TRUE, ofile, B_FALSE);
1604                         (void) fprintf(ofile, "\n");
1605                 }
1606 
1607                 mdstr = getikmstr(pep->pe_ike_mode);
1608                 if (mdstr != NULL)
1609                         (void) fprintf(ofile, "\tike_mode       %s\n", mdstr);
1610 
1611                 (void) fprintf(ofile, "\tkey            %s\n}\n", keyp);
1612                 free(memset(keyp, 0, strlen(keyp)));
1613                 written++;
1614         }
1615         (void) fclose(ofile);
1616 
1617         (void) pthread_rwlock_unlock(&ps_rwlock);
1618         return (written);
1619 }
1620 
1621 /*
1622  * Convert a PS_ID_* to an SADB_IDENTTYPE_* constant.
1623  * Returns SADB_IDENTTYPE_RESERVED on failure.
1624  */
1625 int
1626 psid2sadb(int psid)
1627 {
1628         switch (psid) {
1629         case PS_ID_IP:
1630         case PS_ID_IP4:
1631         case PS_ID_IP6:
1632                 return (SADB_IDENTTYPE_RESERVED);
1633         case PS_ID_SUBNET:
1634         case PS_ID_SUBNET4:
1635         case PS_ID_SUBNET6:
1636                 return (SADB_IDENTTYPE_PREFIX);
1637         case PS_ID_RANGE:
1638         case PS_ID_RANGE4:
1639         case PS_ID_RANGE6:
1640                 return (SADB_X_IDENTTYPE_ADDR_RANGE);
1641         case PS_ID_ASN1DN:
1642                 return (SADB_X_IDENTTYPE_DN);
1643         case PS_ID_ASN1GN:
1644                 return (SADB_X_IDENTTYPE_GN);
1645         case PS_ID_KEYID:
1646                 return (SADB_X_IDENTTYPE_KEY_ID);
1647         case PS_ID_FQDN:
1648                 return (SADB_IDENTTYPE_FQDN);
1649         case PS_ID_USER_FQDN:
1650                 return (SADB_IDENTTYPE_USER_FQDN);
1651         }
1652         return (SADB_IDENTTYPE_RESERVED);
1653 }
1654 
1655 int
1656 sadb2psid(int sadb)
1657 {
1658         switch (sadb) {
1659         case SADB_IDENTTYPE_PREFIX:
1660                 return (PS_ID_SUBNET);
1661         case SADB_X_IDENTTYPE_ADDR_RANGE:
1662                 return (PS_ID_RANGE);
1663         case SADB_X_IDENTTYPE_DN:
1664                 return (PS_ID_ASN1DN);
1665         case SADB_X_IDENTTYPE_GN:
1666                 return (PS_ID_ASN1GN);
1667         case SADB_X_IDENTTYPE_KEY_ID:
1668                 return (PS_ID_KEYID);
1669         case SADB_IDENTTYPE_FQDN:
1670                 return (PS_ID_FQDN);
1671         case SADB_IDENTTYPE_USER_FQDN:
1672                 return (PS_ID_USER_FQDN);
1673         }
1674         return (0);
1675 }
1676 
1677 /*
1678  * Lookup preshared entry by ident
1679  * Holds ps_rwlock as reader
1680  */
1681 preshared_entry_t *
1682 lookup_ps_by_ident(sadb_ident_t *local, sadb_ident_t *remote)
1683 {
1684         int     ltype, rtype;
1685         char    *lid, *rid;
1686         preshared_entry_t       *ps;
1687 
1688         if (local == NULL || remote == NULL)
1689                 return (NULL);
1690 
1691         lid = (char *)(local + 1);
1692         rid = (char *)(remote + 1);
1693 
1694         (void) pthread_rwlock_rdlock(&ps_rwlock);
1695         for (ps = ps_head; ps != NULL; ps = ps->pe_next) {
1696 
1697                 /*
1698                  * Have to convert for each preshared (rather than converting
1699                  * the passed-in sadb ids just once to preshared-style)
1700                  * because there are multiple PS_ID_* for each SADB_IDENT_*.
1701                  */
1702                 ltype = psid2sadb(ps->pe_locidtype);
1703                 rtype = psid2sadb(ps->pe_remidtype);
1704 
1705                 if ((local->sadb_ident_type != ltype) ||
1706                     (remote->sadb_ident_type != rtype))
1707                         continue;
1708 
1709                 if (ps->pe_locidtype == PS_ID_FQDN ||
1710                     ps->pe_locidtype == PS_ID_USER_FQDN) {
1711                         /*
1712                          * Check for case insensitive match.
1713                          */
1714                         if ((strcasecmp(ps->pe_locid, lid) == 0) &&
1715                             (strcasecmp(ps->pe_remid, rid) == 0))
1716                                 break;
1717                 } else {
1718                         /*
1719                          * Otherwise just go for an exact match.
1720                          */
1721                         if ((strcmp(ps->pe_locid, lid) == 0) &&
1722                             (strcmp(ps->pe_remid, rid) == 0))
1723                                 break;
1724                 }
1725         }
1726         if (ps != NULL)
1727                 PE_REFHOLD(ps);
1728         (void) pthread_rwlock_unlock(&ps_rwlock);
1729         return (ps);
1730 }
1731 
1732 /*
1733  * Stolen from kernel spd.c - maybe this should go in libipsecutil
1734  *
1735  * sleazy prefix-length-based compare.
1736  */
1737 boolean_t
1738 ip_addr_match(uint8_t *addr1, int pfxlen, in6_addr_t *addr2p)
1739 {
1740         int offset = pfxlen>>3;
1741         int bitsleft = pfxlen & 7;
1742         uint8_t *addr2 = (uint8_t *)addr2p;
1743 
1744         /*
1745          * and there was much evil..
1746          * XXX should inline-expand the bcmp here and do this 32 bits
1747          * or 64 bits at a time..
1748          */
1749         return ((bcmp(addr1, addr2, offset) == 0) &&
1750             ((bitsleft == 0) ||
1751             (((addr1[offset] ^ addr2[offset]) & (0xff<<(8-bitsleft))) == 0)));
1752 }
1753 
1754 /*
1755  * Lookup preshared entry by v4 or v4 mapped v6 address
1756  * Holds ps_rwlock as reader
1757  */
1758 preshared_entry_t *
1759 lookup_ps_by_in_addr(struct in_addr *local, struct in_addr *remote)
1760 {
1761         struct in_addr *inp;
1762         struct in_addr in;
1763         struct sockaddr_in      *loc_sin, *rem_sin;
1764         struct sockaddr_in6     *loc_sin6, *rem_sin6;
1765         preshared_entry_t *ps;
1766         boolean_t loc_is_v6, rem_is_v6;
1767         int pfxlen;
1768 
1769         if (local == NULL || remote == NULL)
1770                 return (NULL);
1771 
1772         bzero(&in, sizeof (struct in_addr));
1773 
1774         (void) pthread_rwlock_rdlock(&ps_rwlock);
1775         /*
1776          * Also looks up IPv6 id type entries for mapped addresses
1777          */
1778 
1779         for (ps = ps_head; ps != NULL; ps = ps->pe_next) {
1780 
1781                 /* filter on relevant id type first */
1782                 if ((ps->pe_locidtype != PS_ID_IP4 &&
1783                     ps->pe_locidtype != PS_ID_IP6 &&
1784                     ps->pe_locidtype != PS_ID_IP &&
1785                     ps->pe_locidtype != PS_ID_SUBNET4 &&
1786                     ps->pe_locidtype != PS_ID_SUBNET6 &&
1787                     ps->pe_locidtype != PS_ID_SUBNET) ||
1788                     (ps->pe_remidtype != PS_ID_IP4 &&
1789                     ps->pe_remidtype != PS_ID_IP6 &&
1790                     ps->pe_remidtype != PS_ID_IP &&
1791                     ps->pe_remidtype != PS_ID_SUBNET4 &&
1792                     ps->pe_remidtype != PS_ID_SUBNET6 &&
1793                     ps->pe_remidtype != PS_ID_SUBNET))
1794                         continue; /* local and/or remote id types invalid */
1795 
1796                 /* establish format of address */
1797                 if ((ps->pe_locidtype == PS_ID_IP6 ||
1798                     ps->pe_locidtype == PS_ID_SUBNET6) ||
1799                     ((ps->pe_locidtype == PS_ID_IP ||
1800                     ps->pe_locidtype == PS_ID_SUBNET) &&
1801                     check_if_v6(ps->pe_locid)))
1802                         loc_is_v6 = B_TRUE;
1803                 else
1804                         loc_is_v6 = B_FALSE;
1805                 if ((ps->pe_remidtype == PS_ID_IP6 ||
1806                     ps->pe_remidtype == PS_ID_SUBNET6) ||
1807                     ((ps->pe_locidtype == PS_ID_IP ||
1808                     ps->pe_locidtype == PS_ID_SUBNET) &&
1809                     check_if_v6(ps->pe_remid)))
1810                         rem_is_v6 = B_TRUE;
1811                 else
1812                         rem_is_v6 = B_FALSE;
1813 
1814                 loc_sin = (struct sockaddr_in *)&ps->pe_locid_sa;
1815                 rem_sin = (struct sockaddr_in *)&ps->pe_remid_sa;
1816                 loc_sin6 = (struct sockaddr_in6 *)&ps->pe_locid_sa;
1817                 rem_sin6 = (struct sockaddr_in6 *)&ps->pe_remid_sa;
1818 
1819                 /* if v6 format, it is only interesting if v4mapped */
1820                 if (loc_is_v6 && !IN6_IS_ADDR_V4MAPPED(&loc_sin6->sin6_addr))
1821                         continue;       /* not v4 mapped v6 address */
1822                 if (rem_is_v6 && !IN6_IS_ADDR_V4MAPPED(&rem_sin6->sin6_addr))
1823                         continue;       /* not v4 mapped v6 address */
1824 
1825 
1826                 /* match localid */
1827                 if (loc_is_v6) {
1828                         IN6_V4MAPPED_TO_INADDR(&loc_sin6->sin6_addr, &in);
1829                         inp = &in;
1830                 } else {
1831                         inp = &loc_sin->sin_addr;
1832                 }
1833 
1834                 if (ps->pe_locid_plen < 0)
1835                         pfxlen = ADDRBITS_V4;
1836                 else
1837                         pfxlen = ps->pe_locid_plen;
1838                 if (!ip_addr_match((uint8_t *)&inp->s_addr, pfxlen,
1839                     (in6_addr_t *)&local->s_addr))
1840                         continue; /* local id mismatched */
1841 
1842                 /* match remote id */
1843                 if (rem_is_v6) {
1844                         IN6_V4MAPPED_TO_INADDR(&rem_sin6->sin6_addr, &in);
1845                         inp = &in;
1846                 } else {
1847                         inp = &rem_sin->sin_addr;
1848                 }
1849 
1850                 if (ps->pe_remid_plen < 0)
1851                         pfxlen = ADDRBITS_V4;
1852                 else
1853                         pfxlen = ps->pe_remid_plen;
1854                 if (!ip_addr_match((uint8_t *)&inp->s_addr, pfxlen,
1855                     (in6_addr_t *)&remote->s_addr))
1856                         continue; /* remote id mismatched */
1857 
1858                 /* match found for both local and remote id */
1859                 break; /* out of loop */
1860         }
1861         if (ps != NULL)
1862                 PE_REFHOLD(ps);
1863         (void) pthread_rwlock_unlock(&ps_rwlock);
1864         return (ps); /* NULL if loop expires on its own */
1865 }
1866 
1867 /*
1868  * Lookup preshared entry by v6 address
1869  * Holds ps_rwlock as reader
1870  */
1871 preshared_entry_t *
1872 lookup_ps_by_in6_addr(struct in6_addr *local, struct in6_addr *remote)
1873 {
1874         preshared_entry_t *ps;
1875         struct sockaddr_in6     *loc_sin6, *rem_sin6;
1876         int pfxlen;
1877 
1878         if (local == NULL || remote == NULL)
1879                 return (NULL);
1880 
1881         (void) pthread_rwlock_rdlock(&ps_rwlock);
1882         for (ps = ps_head; ps != NULL; ps = ps->pe_next) {
1883 
1884                 /* filter on relevant id type first */
1885                 if ((ps->pe_locidtype != PS_ID_IP6 &&
1886                     ps->pe_locidtype != PS_ID_IP &&
1887                     ps->pe_locidtype != PS_ID_SUBNET &&
1888                     ps->pe_locidtype != PS_ID_SUBNET6) ||
1889                     (ps->pe_remidtype != PS_ID_IP6 &&
1890                     ps->pe_remidtype != PS_ID_IP &&
1891                     ps->pe_remidtype != PS_ID_SUBNET &&
1892                     ps->pe_remidtype != PS_ID_SUBNET6))
1893                         continue; /* local and/or remote id types invalid */
1894 
1895                 /*
1896                  * if PS_ID_IP or PS_ID_SUBNET, it is
1897                  * only interesting if v6 format
1898                  */
1899                 if ((ps->pe_locidtype == PS_ID_IP ||
1900                     ps->pe_locidtype == PS_ID_SUBNET) &&
1901                     !check_if_v6(ps->pe_locid))
1902                         continue; /* not v6 address */
1903                 if ((ps->pe_remidtype == PS_ID_IP ||
1904                     ps->pe_remidtype == PS_ID_SUBNET) &&
1905                     !check_if_v6(ps->pe_remid))
1906                         continue; /* not v6 address */
1907 
1908                 loc_sin6 = (struct sockaddr_in6 *)&ps->pe_locid_sa;
1909                 rem_sin6 = (struct sockaddr_in6 *)&ps->pe_remid_sa;
1910 
1911                 if (ps->pe_locid_plen < 0)
1912                         pfxlen = ADDRBITS_V6;
1913                 else
1914                         pfxlen = ps->pe_locid_plen;
1915                 if (!ip_addr_match((uint8_t *)&loc_sin6->sin6_addr, pfxlen,
1916                     (in6_addr_t *)local))
1917                         continue; /* local id mismatched */
1918 
1919                 if (ps->pe_remid_plen < 0)
1920                         pfxlen = ADDRBITS_V6;
1921                 else
1922                         pfxlen = ps->pe_remid_plen;
1923                 if (!ip_addr_match((uint8_t *)&rem_sin6->sin6_addr, pfxlen,
1924                     (in6_addr_t *)remote))
1925                         continue; /* remote id mismatched */
1926                 /* match found for both local and remote id */
1927                 break; /* out of loop */
1928         }
1929         if (ps != NULL)
1930                 PE_REFHOLD(ps);
1931         (void) pthread_rwlock_unlock(&ps_rwlock);
1932         return (ps); /* NULL if loop expires on its own */
1933 }
1934 
1935 /*
1936  * Lookup nth preshared key entry
1937  * Holds ps_rwlock as reader
1938  */
1939 preshared_entry_t *
1940 lookup_nth_ps(int n)
1941 {
1942         preshared_entry_t       *ps;
1943         int                     cnt;
1944 
1945         (void) pthread_rwlock_rdlock(&ps_rwlock);
1946         for (cnt = 0, ps = ps_head; (cnt < n) && (ps != NULL);
1947             cnt++, ps = ps->pe_next)
1948                 ;
1949         if (ps != NULL)
1950                 PE_REFHOLD(ps);
1951         (void) pthread_rwlock_unlock(&ps_rwlock);
1952         return (ps);
1953 }
1954 
1955 /*
1956  * Actual freeing function.
1957  */
1958 void
1959 free_preshared(preshared_entry_t *pe)
1960 {
1961         assert(pe->pe_refcnt == 0);
1962         free(pe->pe_locid);
1963         free(pe->pe_remid);
1964         /* Use memset()'s return value to our advantage. */
1965         free(memset(pe->pe_keybuf, 0, pe->pe_keybuf_bytes));
1966         free(pe);
1967 }
1968 
1969 /*
1970  * Read in a list of pre-shared keys.  Called from main() when the daemon first
1971  * starts.
1972  */
1973 void
1974 preshared_init(boolean_t ignore_errors)
1975 {
1976         const char *filename = PRESHARED_KEY_FILE;
1977         char *errorstr;
1978 
1979         bunyan_info(log, "Loading preshared keys", BUNYAN_T_END);
1980         errorstr = preshared_load(filename, -1, B_TRUE);
1981 
1982         if (errorstr != NULL) {
1983                 if (strncmp(errorstr, "DUP", 3) == 0)
1984                         errorstr = gettext("Duplicate entries ignored\n");
1985                 /*
1986                  * Error handling... Print to terminal, if exists.
1987                  * Debug logging already taken care of by other functions.
1988                  * Don't exit because we want to load other policy.
1989                  */
1990                 bunyan_error(log, "Error reading preshared file",
1991                     BUNYAN_T_STRING, "filename", filename,
1992                     BUNYAN_T_STRING, "errmsg", errorstr);
1993                 if (!ignore_errors)
1994                         err(EXIT_FAILURE, "Fatal errors in %s", filename);
1995         }
1996 }
1997 
1998 /*
1999  * Called when the daemon catches SIGHUP.
2000  * Currently equivalent to preshared_init().
2001  */
2002 void
2003 preshared_reload(void)
2004 {
2005         preshared_init(B_FALSE);
2006 }
2007 
2008 /*
2009  * Random Notes:
2010  * (a)
2011  * Maybe a better syntax for fields is following which eliminates
2012  * semantic relationships between two different fields (id and idtype) ???
2013  * E.g.
2014  * {
2015  *      ...
2016  *      localid ipv4            1.2.3.4
2017  *      remoteid rangev4        1.2.3.4-5.6.7.8
2018  *      ...
2019  *  }
2020  *  Current design causes us to delay certain verifications into a
2021  *  postprocess_XXX() routine which otherwise could be done while
2022  *  parsing if syntax was as above.
2023  *
2024  * (b)
2025  *      Current error handling has a generic design that prints only
2026  *      error message, entry number and line number. Other options are
2027  *      possible (e.g. parsekey() "original" code from danmcd prints
2028  *      error messages specific to the error context which have more
2029  *      detailed context). Perhaps we should change to direct printing
2030  *      of specific error messages globally later, but for now stick
2031  *      to the simple model coded above.
2032  * (c) The getnexttoken() part can be improved by passing it some context
2033  *      such as "expected token" and maybe the fieldname. This *may* help
2034  *      allow a more flexible syntax for complex tokens such as ranges.
2035  *      which cannot currently embed spaces but it would be nice to allow
2036  *      them to do that and be delimited with a context sensitive delimiter.
2037  * (d) Needs detection of duplicates in the database before inserting new
2038  *      entry.
2039  * (e) Can be enhanced to do hashes and better structures than a linked list
2040  *      of entries.
2041  */