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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 Joyent, Inc.  All rights reserved.
  25  *
  26  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  27  * Copyright (c) 2014 Gary Mills
  28  * Copyright (c) 2016 Andrey Sokolov
  29  */
  30 
  31 /*
  32  * lofiadm - administer lofi(7d). Very simple, add and remove file<->device
  33  * associations, and display status. All the ioctls are private between
  34  * lofi and lofiadm, and so are very simple - device information is
  35  * communicated via a minor number.
  36  */
  37 
  38 #include <sys/types.h>
  39 #include <sys/param.h>
  40 #include <sys/lofi.h>
  41 #include <sys/stat.h>
  42 #include <sys/sysmacros.h>
  43 #include <netinet/in.h>
  44 #include <stdio.h>
  45 #include <fcntl.h>
  46 #include <locale.h>
  47 #include <string.h>
  48 #include <strings.h>
  49 #include <errno.h>
  50 #include <stdlib.h>
  51 #include <unistd.h>
  52 #include <stropts.h>
  53 #include <libdevinfo.h>
  54 #include <libgen.h>
  55 #include <ctype.h>
  56 #include <dlfcn.h>
  57 #include <limits.h>
  58 #include <security/cryptoki.h>
  59 #include <cryptoutil.h>
  60 #include <sys/crypto/ioctl.h>
  61 #include <sys/crypto/ioctladmin.h>
  62 #include "utils.h"
  63 #include <LzmaEnc.h>
  64 
  65 /* Only need the IV len #defines out of these files, nothing else. */
  66 #include <aes/aes_impl.h>
  67 #include <des/des_impl.h>
  68 #include <blowfish/blowfish_impl.h>
  69 
  70 static const char USAGE[] =
  71         "Usage: %s [-r] -a file [ device ]\n"
  72         "       %s [-r] -c crypto_algorithm -a file [device]\n"
  73         "       %s [-r] -c crypto_algorithm -k raw_key_file -a file [device]\n"
  74         "       %s [-r] -c crypto_algorithm -T [token]:[manuf]:[serial]:key "
  75         "-a file [device]\n"
  76         "       %s [-r] -c crypto_algorithm -T [token]:[manuf]:[serial]:key "
  77         "-k wrapped_key_file -a file [device]\n"
  78         "       %s [-r] -c crypto_algorithm -e -a file [device]\n"
  79         "       %s -d file | device\n"
  80         "       %s -C [gzip|gzip-6|gzip-9|lzma] [-s segment_size] file\n"
  81         "       %s -U file\n"
  82         "       %s [ file | device ]\n";
  83 
  84 typedef struct token_spec {
  85         char    *name;
  86         char    *mfr;
  87         char    *serno;
  88         char    *key;
  89 } token_spec_t;
  90 
  91 typedef struct mech_alias {
  92         char    *alias;
  93         CK_MECHANISM_TYPE type;
  94         char    *name;          /* for ioctl */
  95         char    *iv_name;       /* for ioctl */
  96         size_t  iv_len;         /* for ioctl */
  97         iv_method_t iv_type;    /* for ioctl */
  98         size_t  min_keysize;    /* in bytes */
  99         size_t  max_keysize;    /* in bytes */
 100         token_spec_t *token;
 101         CK_SLOT_ID slot;
 102 } mech_alias_t;
 103 
 104 static mech_alias_t mech_aliases[] = {
 105         /* Preferred one should always be listed first. */
 106         { "aes-256-cbc", CKM_AES_CBC, "CKM_AES_CBC", "CKM_AES_ECB", AES_IV_LEN,
 107             IVM_ENC_BLKNO, ULONG_MAX, 0L, NULL, (CK_SLOT_ID) -1 },
 108         { "aes-192-cbc", CKM_AES_CBC, "CKM_AES_CBC", "CKM_AES_ECB", AES_IV_LEN,
 109             IVM_ENC_BLKNO, ULONG_MAX, 0L, NULL, (CK_SLOT_ID) -1 },
 110         { "aes-128-cbc", CKM_AES_CBC, "CKM_AES_CBC", "CKM_AES_ECB", AES_IV_LEN,
 111             IVM_ENC_BLKNO, ULONG_MAX, 0L, NULL, (CK_SLOT_ID) -1 },
 112         { "des3-cbc", CKM_DES3_CBC, "CKM_DES3_CBC", "CKM_DES3_ECB", DES_IV_LEN,
 113             IVM_ENC_BLKNO, ULONG_MAX, 0L, NULL, (CK_SLOT_ID)-1 },
 114         { "blowfish-cbc", CKM_BLOWFISH_CBC, "CKM_BLOWFISH_CBC",
 115             "CKM_BLOWFISH_ECB", BLOWFISH_IV_LEN, IVM_ENC_BLKNO, ULONG_MAX,
 116             0L, NULL, (CK_SLOT_ID)-1 }
 117         /*
 118          * A cipher without an iv requirement would look like this:
 119          * { "aes-xex", CKM_AES_XEX, "CKM_AES_XEX", NULL, 0,
 120          *    IVM_NONE, ULONG_MAX, 0L, NULL, (CK_SLOT_ID)-1 }
 121          */
 122 };
 123 
 124 int     mech_aliases_count = (sizeof (mech_aliases) / sizeof (mech_alias_t));
 125 
 126 /* Preferred cipher, if one isn't specified on command line. */
 127 #define DEFAULT_CIPHER  (&mech_aliases[0])
 128 
 129 #define DEFAULT_CIPHER_NUM      64      /* guess # kernel ciphers available */
 130 #define DEFAULT_MECHINFO_NUM    16      /* guess # kernel mechs available */
 131 #define MIN_PASSLEN             8       /* min acceptable passphrase size */
 132 
 133 static int gzip_compress(void *src, size_t srclen, void *dst,
 134         size_t *destlen, int level);
 135 static int lzma_compress(void *src, size_t srclen, void *dst,
 136         size_t *destlen, int level);
 137 
 138 lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = {
 139         {NULL,                  gzip_compress,  6,      "gzip"}, /* default */
 140         {NULL,                  gzip_compress,  6,      "gzip-6"},
 141         {NULL,                  gzip_compress,  9,      "gzip-9"},
 142         {NULL,                  lzma_compress,  0,      "lzma"}
 143 };
 144 
 145 /* For displaying lofi mappings */
 146 #define FORMAT                  "%-20s     %-30s        %s\n"
 147 
 148 #define COMPRESS_ALGORITHM      "gzip"
 149 #define COMPRESS_THRESHOLD      2048
 150 #define SEGSIZE                 131072
 151 #define BLOCK_SIZE              512
 152 #define KILOBYTE                1024
 153 #define MEGABYTE                (KILOBYTE * KILOBYTE)
 154 #define GIGABYTE                (KILOBYTE * MEGABYTE)
 155 #define LIBZ                    "libz.so.1"
 156 
 157 const char lofi_crypto_magic[6] = LOFI_CRYPTO_MAGIC;
 158 
 159 static void
 160 usage(const char *pname)
 161 {
 162         (void) fprintf(stderr, gettext(USAGE), pname, pname, pname,
 163             pname, pname, pname, pname, pname, pname, pname);
 164         exit(E_USAGE);
 165 }
 166 
 167 static int
 168 gzip_compress(void *src, size_t srclen, void *dst, size_t *dstlen, int level)
 169 {
 170         static int (*compress2p)(void *, ulong_t *, void *, size_t, int) = NULL;
 171         void *libz_hdl = NULL;
 172 
 173         /*
 174          * The first time we are called, attempt to dlopen()
 175          * libz.so.1 and get a pointer to the compress2() function
 176          */
 177         if (compress2p == NULL) {
 178                 if ((libz_hdl = openlib(LIBZ)) == NULL)
 179                         die(gettext("could not find %s. "
 180                             "gzip compression unavailable\n"), LIBZ);
 181 
 182                 if ((compress2p =
 183                     (int (*)(void *, ulong_t *, void *, size_t, int))
 184                     dlsym(libz_hdl, "compress2")) == NULL) {
 185                         closelib();
 186                         die(gettext("could not find the correct %s. "
 187                             "gzip compression unavailable\n"), LIBZ);
 188                 }
 189         }
 190 
 191         if ((*compress2p)(dst, (ulong_t *)dstlen, src, srclen, level) != 0)
 192                 return (-1);
 193         return (0);
 194 }
 195 
 196 /*ARGSUSED*/
 197 static void
 198 *SzAlloc(void *p, size_t size)
 199 {
 200         return (malloc(size));
 201 }
 202 
 203 /*ARGSUSED*/
 204 static void
 205 SzFree(void *p, void *address, size_t size)
 206 {
 207         free(address);
 208 }
 209 
 210 static ISzAlloc g_Alloc = {
 211         SzAlloc,
 212         SzFree
 213 };
 214 
 215 #define LZMA_UNCOMPRESSED_SIZE  8
 216 #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNCOMPRESSED_SIZE)
 217 
 218 /*ARGSUSED*/
 219 static int
 220 lzma_compress(void *src, size_t srclen, void *dst,
 221     size_t *dstlen, int level)
 222 {
 223         CLzmaEncProps props;
 224         size_t outsize2;
 225         size_t outsizeprocessed;
 226         size_t outpropssize = LZMA_PROPS_SIZE;
 227         uint64_t t = 0;
 228         SRes res;
 229         Byte *dstp;
 230         int i;
 231 
 232         outsize2 = *dstlen;
 233 
 234         LzmaEncProps_Init(&props);
 235 
 236         /*
 237          * The LZMA compressed file format is as follows -
 238          *
 239          * Offset Size(bytes) Description
 240          * 0            1       LZMA properties (lc, lp, lp (encoded))
 241          * 1            4       Dictionary size (little endian)
 242          * 5            8       Uncompressed size (little endian)
 243          * 13                   Compressed data
 244          */
 245 
 246         /* set the dictionary size to be 8MB */
 247         props.dictSize = 1 << 23;
 248 
 249         if (*dstlen < LZMA_HEADER_SIZE)
 250                 return (SZ_ERROR_OUTPUT_EOF);
 251 
 252         dstp = (Byte *)dst;
 253         t = srclen;
 254         /*
 255          * Set the uncompressed size in the LZMA header
 256          * The LZMA properties (specified in 'props')
 257          * will be set by the call to LzmaEncode()
 258          */
 259         for (i = 0; i < LZMA_UNCOMPRESSED_SIZE; i++, t >>= 8) {
 260                 dstp[LZMA_PROPS_SIZE + i] = (Byte)t;
 261         }
 262 
 263         outsizeprocessed = outsize2 - LZMA_HEADER_SIZE;
 264         res = LzmaEncode(dstp + LZMA_HEADER_SIZE, &outsizeprocessed,
 265             src, srclen, &props, dstp, &outpropssize, 0, NULL,
 266             &g_Alloc, &g_Alloc);
 267 
 268         if (res != 0)
 269                 return (-1);
 270 
 271         *dstlen = outsizeprocessed + LZMA_HEADER_SIZE;
 272         return (0);
 273 }
 274 
 275 /*
 276  * Translate a lofi device name to a minor number. We might be asked
 277  * to do this when there is no association (such as when the user specifies
 278  * a particular device), so we can only look at the string.
 279  */
 280 static int
 281 name_to_minor(const char *devicename)
 282 {
 283         int     minor;
 284 
 285         if (sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor) == 1) {
 286                 return (minor);
 287         }
 288         if (sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor) == 1) {
 289                 return (minor);
 290         }
 291         return (0);
 292 }
 293 
 294 /*
 295  * This might be the first time we've used this minor number. If so,
 296  * it might also be that the /dev links are in the process of being created
 297  * by devfsadmd (or that they'll be created "soon"). We cannot return
 298  * until they're there or the invoker of lofiadm might try to use them
 299  * and not find them. This can happen if a shell script is running on
 300  * an MP.
 301  */
 302 static int sleeptime = 2;       /* number of seconds to sleep between stat's */
 303 static int maxsleep = 120;      /* maximum number of seconds to sleep */
 304 
 305 static void
 306 wait_until_dev_complete(int minor)
 307 {
 308         struct stat64 buf;
 309         int     cursleep;
 310         char    blkpath[MAXPATHLEN];
 311         char    charpath[MAXPATHLEN];
 312         di_devlink_handle_t hdl;
 313 
 314         (void) snprintf(blkpath, sizeof (blkpath), "/dev/%s/%d",
 315             LOFI_BLOCK_NAME, minor);
 316         (void) snprintf(charpath, sizeof (charpath), "/dev/%s/%d",
 317             LOFI_CHAR_NAME, minor);
 318 
 319         /* Check if links already present */
 320         if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0)
 321                 return;
 322 
 323         /* First use di_devlink_init() */
 324         if (hdl = di_devlink_init("lofi", DI_MAKE_LINK)) {
 325                 (void) di_devlink_fini(&hdl);
 326                 goto out;
 327         }
 328 
 329         /*
 330          * Under normal conditions, di_devlink_init(DI_MAKE_LINK) above will
 331          * only fail if the caller is non-root. In that case, wait for
 332          * link creation via sysevents.
 333          */
 334         for (cursleep = 0; cursleep < maxsleep; cursleep += sleeptime) {
 335                 if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0)
 336                         return;
 337                 (void) sleep(sleeptime);
 338         }
 339 
 340         /* one last try */
 341 out:
 342         if (stat64(blkpath, &buf) == -1) {
 343                 die(gettext("%s was not created"), blkpath);
 344         }
 345         if (stat64(charpath, &buf) == -1) {
 346                 die(gettext("%s was not created"), charpath);
 347         }
 348 }
 349 
 350 /*
 351  * Map the file and return the minor number the driver picked for the file
 352  * DO NOT use this function if the filename is actually the device name.
 353  */
 354 static int
 355 lofi_map_file(int lfd, struct lofi_ioctl li, const char *filename)
 356 {
 357         int     minor;
 358 
 359         li.li_minor = 0;
 360         (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename));
 361         minor = ioctl(lfd, LOFI_MAP_FILE, &li);
 362         if (minor == -1) {
 363                 if (errno == ENOTSUP)
 364                         warn(gettext("encrypting compressed files is "
 365                             "unsupported"));
 366                 die(gettext("could not map file %s"), filename);
 367         }
 368         wait_until_dev_complete(minor);
 369         return (minor);
 370 }
 371 
 372 /*
 373  * Add a device association. If devicename is NULL, let the driver
 374  * pick a device.
 375  */
 376 static void
 377 add_mapping(int lfd, const char *devicename, const char *filename,
 378     mech_alias_t *cipher, const char *rkey, size_t rksz, boolean_t rdonly)
 379 {
 380         struct lofi_ioctl li;
 381 
 382         li.li_readonly = rdonly;
 383 
 384         li.li_crypto_enabled = B_FALSE;
 385         if (cipher != NULL) {
 386                 /* set up encryption for mapped file */
 387                 li.li_crypto_enabled = B_TRUE;
 388                 (void) strlcpy(li.li_cipher, cipher->name,
 389                     sizeof (li.li_cipher));
 390                 if (rksz > sizeof (li.li_key)) {
 391                         die(gettext("key too large"));
 392                 }
 393                 bcopy(rkey, li.li_key, rksz);
 394                 li.li_key_len = rksz << 3;        /* convert to bits */
 395 
 396                 li.li_iv_type = cipher->iv_type;
 397                 li.li_iv_len = cipher->iv_len;       /* 0 when no iv needed */
 398                 switch (cipher->iv_type) {
 399                 case IVM_ENC_BLKNO:
 400                         (void) strlcpy(li.li_iv_cipher, cipher->iv_name,
 401                             sizeof (li.li_iv_cipher));
 402                         break;
 403                 case IVM_NONE:
 404                         /* FALLTHROUGH */
 405                 default:
 406                         break;
 407                 }
 408         }
 409 
 410         if (devicename == NULL) {
 411                 int     minor;
 412 
 413                 /* pick one via the driver */
 414                 minor = lofi_map_file(lfd, li, filename);
 415                 /* if mapping succeeds, print the one picked */
 416                 (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor);
 417                 return;
 418         }
 419 
 420         /* use device we were given */
 421         li.li_minor = name_to_minor(devicename);
 422         if (li.li_minor == 0) {
 423                 die(gettext("malformed device name %s\n"), devicename);
 424         }
 425         (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename));
 426 
 427         /* if device is already in use li.li_minor won't change */
 428         if (ioctl(lfd, LOFI_MAP_FILE_MINOR, &li) == -1) {
 429                 if (errno == ENOTSUP)
 430                         warn(gettext("encrypting compressed files is "
 431                             "unsupported"));
 432                 die(gettext("could not map file %s to %s"), filename,
 433                     devicename);
 434         }
 435         wait_until_dev_complete(li.li_minor);
 436 }
 437 
 438 /*
 439  * Remove an association. Delete by device name if non-NULL, or by
 440  * filename otherwise.
 441  */
 442 static void
 443 delete_mapping(int lfd, const char *devicename, const char *filename,
 444     boolean_t force)
 445 {
 446         struct lofi_ioctl li;
 447 
 448         li.li_force = force;
 449         li.li_cleanup = B_FALSE;
 450 
 451         if (devicename == NULL) {
 452                 /* delete by filename */
 453                 (void) strlcpy(li.li_filename, filename,
 454                     sizeof (li.li_filename));
 455                 li.li_minor = 0;
 456                 if (ioctl(lfd, LOFI_UNMAP_FILE, &li) == -1) {
 457                         die(gettext("could not unmap file %s"), filename);
 458                 }
 459                 return;
 460         }
 461 
 462         /* delete by device */
 463         li.li_minor = name_to_minor(devicename);
 464         if (li.li_minor == 0) {
 465                 die(gettext("malformed device name %s\n"), devicename);
 466         }
 467         if (ioctl(lfd, LOFI_UNMAP_FILE_MINOR, &li) == -1) {
 468                 die(gettext("could not unmap device %s"), devicename);
 469         }
 470 }
 471 
 472 /*
 473  * Show filename given devicename, or devicename given filename.
 474  */
 475 static void
 476 print_one_mapping(int lfd, const char *devicename, const char *filename)
 477 {
 478         struct lofi_ioctl li;
 479 
 480         if (devicename == NULL) {
 481                 /* given filename, print devicename */
 482                 li.li_minor = 0;
 483                 (void) strlcpy(li.li_filename, filename,
 484                     sizeof (li.li_filename));
 485                 if (ioctl(lfd, LOFI_GET_MINOR, &li) == -1) {
 486                         die(gettext("could not find device for %s"), filename);
 487                 }
 488                 (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, li.li_minor);
 489                 return;
 490         }
 491 
 492         /* given devicename, print filename */
 493         li.li_minor = name_to_minor(devicename);
 494         if (li.li_minor == 0) {
 495                 die(gettext("malformed device name %s\n"), devicename);
 496         }
 497         if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) {
 498                 die(gettext("could not find filename for %s"), devicename);
 499         }
 500         (void) printf("%s\n", li.li_filename);
 501 }
 502 
 503 /*
 504  * Print the list of all the mappings, including a header.
 505  */
 506 static void
 507 print_mappings(int fd)
 508 {
 509         struct lofi_ioctl li;
 510         int     minor;
 511         int     maxminor;
 512         char    path[MAXPATHLEN];
 513         char    options[MAXPATHLEN] = { 0 };
 514 
 515         li.li_minor = 0;
 516         if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) {
 517                 die("ioctl");
 518         }
 519         maxminor = li.li_minor;
 520 
 521         (void) printf(FORMAT, gettext("Block Device"), gettext("File"),
 522             gettext("Options"));
 523         for (minor = 1; minor <= maxminor; minor++) {
 524                 li.li_minor = minor;
 525                 if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) {
 526                         if (errno == ENXIO)
 527                                 continue;
 528                         warn("ioctl");
 529                         break;
 530                 }
 531                 (void) snprintf(path, sizeof (path), "/dev/%s/%d",
 532                     LOFI_BLOCK_NAME, minor);
 533 
 534                 options[0] = '\0';
 535 
 536                 /*
 537                  * Encrypted lofi and compressed lofi are mutually exclusive.
 538                  */
 539                 if (li.li_crypto_enabled)
 540                         (void) snprintf(options, sizeof (options),
 541                             gettext("Encrypted"));
 542                 else if (li.li_algorithm[0] != '\0')
 543                         (void) snprintf(options, sizeof (options),
 544                             gettext("Compressed(%s)"), li.li_algorithm);
 545                 if (li.li_readonly) {
 546                         if (strlen(options) != 0) {
 547                                 (void) strlcat(options, ",", sizeof (options));
 548                                 (void) strlcat(options, "Readonly",
 549                                     sizeof (options));
 550                         } else {
 551                                 (void) snprintf(options, sizeof (options),
 552                                     gettext("Readonly"));
 553                         }
 554                 }
 555                 if (strlen(options) == 0)
 556                         (void) snprintf(options, sizeof (options), "-");
 557 
 558                 (void) printf(FORMAT, path, li.li_filename, options);
 559         }
 560 }
 561 
 562 /*
 563  * Verify the cipher selected by user.
 564  */
 565 static mech_alias_t *
 566 ciph2mech(const char *alias)
 567 {
 568         int     i;
 569 
 570         for (i = 0; i < mech_aliases_count; i++) {
 571                 if (strcasecmp(alias, mech_aliases[i].alias) == 0)
 572                         return (&mech_aliases[i]);
 573         }
 574         return (NULL);
 575 }
 576 
 577 /*
 578  * Verify user selected cipher is also available in kernel.
 579  *
 580  * While traversing kernel list of mechs, if the cipher is supported in the
 581  * kernel for both encryption and decryption, it also picks up the min/max
 582  * key size.
 583  */
 584 static boolean_t
 585 kernel_cipher_check(mech_alias_t *cipher)
 586 {
 587         boolean_t ciph_ok = B_FALSE;
 588         boolean_t iv_ok = B_FALSE;
 589         int     i;
 590         int     count;
 591         crypto_get_mechanism_list_t *kciphers = NULL;
 592         crypto_get_all_mechanism_info_t *kinfo = NULL;
 593         int     fd = -1;
 594         size_t  keymin;
 595         size_t  keymax;
 596 
 597         /* if cipher doesn't need iv generating mech, bypass that check now */
 598         if (cipher->iv_name == NULL)
 599                 iv_ok = B_TRUE;
 600 
 601         /* allocate some space for the list of kernel ciphers */
 602         count = DEFAULT_CIPHER_NUM;
 603         kciphers = malloc(sizeof (crypto_get_mechanism_list_t) +
 604             sizeof (crypto_mech_name_t) * (count - 1));
 605         if (kciphers == NULL)
 606                 die(gettext("failed to allocate memory for list of "
 607                     "kernel mechanisms"));
 608         kciphers->ml_count = count;
 609 
 610         /* query crypto device to get list of kernel ciphers */
 611         if ((fd = open("/dev/crypto", O_RDWR)) == -1) {
 612                 warn(gettext("failed to open %s"), "/dev/crypto");
 613                 goto kcc_out;
 614         }
 615 
 616         if (ioctl(fd, CRYPTO_GET_MECHANISM_LIST, kciphers) == -1) {
 617                 warn(gettext("CRYPTO_GET_MECHANISM_LIST ioctl failed"));
 618                 goto kcc_out;
 619         }
 620 
 621         if (kciphers->ml_return_value == CRYPTO_BUFFER_TOO_SMALL) {
 622                 count = kciphers->ml_count;
 623                 free(kciphers);
 624                 kciphers = malloc(sizeof (crypto_get_mechanism_list_t) +
 625                     sizeof (crypto_mech_name_t) * (count - 1));
 626                 if (kciphers == NULL) {
 627                         warn(gettext("failed to allocate memory for list of "
 628                             "kernel mechanisms"));
 629                         goto kcc_out;
 630                 }
 631                 kciphers->ml_count = count;
 632 
 633                 if (ioctl(fd, CRYPTO_GET_MECHANISM_LIST, kciphers) == -1) {
 634                         warn(gettext("CRYPTO_GET_MECHANISM_LIST ioctl failed"));
 635                         goto kcc_out;
 636                 }
 637         }
 638 
 639         if (kciphers->ml_return_value != CRYPTO_SUCCESS) {
 640                 warn(gettext(
 641                     "CRYPTO_GET_MECHANISM_LIST ioctl return value = %d\n"),
 642                     kciphers->ml_return_value);
 643                 goto kcc_out;
 644         }
 645 
 646         /*
 647          * scan list of kernel ciphers looking for the selected one and if
 648          * it needs an iv generated using another cipher, also look for that
 649          * additional cipher to be used for generating the iv
 650          */
 651         count = kciphers->ml_count;
 652         for (i = 0; i < count && !(ciph_ok && iv_ok); i++) {
 653                 if (!ciph_ok &&
 654                     strcasecmp(cipher->name, kciphers->ml_list[i]) == 0)
 655                         ciph_ok = B_TRUE;
 656                 if (!iv_ok &&
 657                     strcasecmp(cipher->iv_name, kciphers->ml_list[i]) == 0)
 658                         iv_ok = B_TRUE;
 659         }
 660         free(kciphers);
 661         kciphers = NULL;
 662 
 663         if (!ciph_ok)
 664                 warn(gettext("%s mechanism not supported in kernel\n"),
 665                     cipher->name);
 666         if (!iv_ok)
 667                 warn(gettext("%s mechanism not supported in kernel\n"),
 668                     cipher->iv_name);
 669 
 670         if (ciph_ok) {
 671                 /* Get the details about the user selected cipher */
 672                 count = DEFAULT_MECHINFO_NUM;
 673                 kinfo = malloc(sizeof (crypto_get_all_mechanism_info_t) +
 674                     sizeof (crypto_mechanism_info_t) * (count - 1));
 675                 if (kinfo == NULL) {
 676                         warn(gettext("failed to allocate memory for "
 677                             "kernel mechanism info"));
 678                         goto kcc_out;
 679                 }
 680                 kinfo->mi_count = count;
 681                 (void) strlcpy(kinfo->mi_mechanism_name, cipher->name,
 682                     CRYPTO_MAX_MECH_NAME);
 683 
 684                 if (ioctl(fd, CRYPTO_GET_ALL_MECHANISM_INFO, kinfo) == -1) {
 685                         warn(gettext(
 686                             "CRYPTO_GET_ALL_MECHANISM_INFO ioctl failed"));
 687                         goto kcc_out;
 688                 }
 689 
 690                 if (kinfo->mi_return_value == CRYPTO_BUFFER_TOO_SMALL) {
 691                         count = kinfo->mi_count;
 692                         free(kinfo);
 693                         kinfo = malloc(
 694                             sizeof (crypto_get_all_mechanism_info_t) +
 695                             sizeof (crypto_mechanism_info_t) * (count - 1));
 696                         if (kinfo == NULL) {
 697                                 warn(gettext("failed to allocate memory for "
 698                                     "kernel mechanism info"));
 699                                 goto kcc_out;
 700                         }
 701                         kinfo->mi_count = count;
 702                         (void) strlcpy(kinfo->mi_mechanism_name, cipher->name,
 703                             CRYPTO_MAX_MECH_NAME);
 704 
 705                         if (ioctl(fd, CRYPTO_GET_ALL_MECHANISM_INFO, kinfo) ==
 706                             -1) {
 707                                 warn(gettext("CRYPTO_GET_ALL_MECHANISM_INFO "
 708                                     "ioctl failed"));
 709                                 goto kcc_out;
 710                         }
 711                 }
 712 
 713                 if (kinfo->mi_return_value != CRYPTO_SUCCESS) {
 714                         warn(gettext("CRYPTO_GET_ALL_MECHANISM_INFO ioctl "
 715                             "return value = %d\n"), kinfo->mi_return_value);
 716                         goto kcc_out;
 717                 }
 718 
 719                 /* Set key min and max size */
 720                 count = kinfo->mi_count;
 721                 i = 0;
 722                 if (i < count) {
 723                         keymin = kinfo->mi_list[i].mi_min_key_size;
 724                         keymax = kinfo->mi_list[i].mi_max_key_size;
 725                         if (kinfo->mi_list[i].mi_keysize_unit &
 726                             CRYPTO_KEYSIZE_UNIT_IN_BITS) {
 727                                 keymin = CRYPTO_BITS2BYTES(keymin);
 728                                 keymax = CRYPTO_BITS2BYTES(keymax);
 729 
 730                         }
 731                         cipher->min_keysize = keymin;
 732                         cipher->max_keysize = keymax;
 733                 }
 734                 free(kinfo);
 735                 kinfo = NULL;
 736 
 737                 if (i == count) {
 738                         (void) close(fd);
 739                         die(gettext(
 740                             "failed to find usable %s kernel mechanism, "
 741                             "use \"cryptoadm list -m\" to find available "
 742                             "mechanisms\n"),
 743                             cipher->name);
 744                 }
 745         }
 746 
 747         /* Note: key min/max, unit size, usage for iv cipher are not checked. */
 748 
 749         return (ciph_ok && iv_ok);
 750 
 751 kcc_out:
 752         if (kinfo != NULL)
 753                 free(kinfo);
 754         if (kciphers != NULL)
 755                 free(kciphers);
 756         if (fd != -1)
 757                 (void) close(fd);
 758         return (B_FALSE);
 759 }
 760 
 761 /*
 762  * Break up token spec into its components (non-destructive)
 763  */
 764 static token_spec_t *
 765 parsetoken(char *spec)
 766 {
 767 #define FLD_NAME        0
 768 #define FLD_MANUF       1
 769 #define FLD_SERIAL      2
 770 #define FLD_LABEL       3
 771 #define NFIELDS         4
 772 #define nullfield(i)    ((field[(i)+1] - field[(i)]) <= 1)
 773 #define copyfield(fld, i)       \
 774                 {                                                       \
 775                         int     n;                                      \
 776                         (fld) = NULL;                                   \
 777                         if ((n = (field[(i)+1] - field[(i)])) > 1) { \
 778                                 if (((fld) = malloc(n)) != NULL) {      \
 779                                         (void) strncpy((fld), field[(i)], n); \
 780                                         ((fld))[n - 1] = '\0';          \
 781                                 }                                       \
 782                         }                                               \
 783                 }
 784 
 785         int     i;
 786         char    *field[NFIELDS + 1];    /* +1 to catch extra delimiters */
 787         token_spec_t *ti = NULL;
 788 
 789         if (spec == NULL)
 790                 return (NULL);
 791 
 792         /*
 793          * Correct format is "[name]:[manuf]:[serial]:key". Can't use
 794          * strtok because it treats ":::key" and "key:::" and "key" all
 795          * as the same thing, and we can't have the :s compressed away.
 796          */
 797         field[0] = spec;
 798         for (i = 1; i < NFIELDS + 1; i++) {
 799                 field[i] = strchr(field[i-1], ':');
 800                 if (field[i] == NULL)
 801                         break;
 802                 field[i]++;
 803         }
 804         if (i < NFIELDS)             /* not enough fields */
 805                 return (NULL);
 806         if (field[NFIELDS] != NULL)     /* too many fields */
 807                 return (NULL);
 808         field[NFIELDS] = strchr(field[NFIELDS-1], '\0') + 1;
 809 
 810         /* key label can't be empty */
 811         if (nullfield(FLD_LABEL))
 812                 return (NULL);
 813 
 814         ti = malloc(sizeof (token_spec_t));
 815         if (ti == NULL)
 816                 return (NULL);
 817 
 818         copyfield(ti->name, FLD_NAME);
 819         copyfield(ti->mfr, FLD_MANUF);
 820         copyfield(ti->serno, FLD_SERIAL);
 821         copyfield(ti->key, FLD_LABEL);
 822 
 823         /*
 824          * If token specified and it only contains a key label, then
 825          * search all tokens for the key, otherwise only those with
 826          * matching name, mfr, and serno are used.
 827          */
 828         /*
 829          * That's how we'd like it to be, however, if only the key label
 830          * is specified, default to using softtoken.  It's easier.
 831          */
 832         if (ti->name == NULL && ti->mfr == NULL && ti->serno == NULL)
 833                 ti->name = strdup(pkcs11_default_token());
 834         return (ti);
 835 }
 836 
 837 /*
 838  * PBE the passphrase into a raw key
 839  */
 840 static void
 841 getkeyfromuser(mech_alias_t *cipher, char **raw_key, size_t *raw_key_sz,
 842     boolean_t with_confirmation)
 843 {
 844         CK_SESSION_HANDLE sess;
 845         CK_RV   rv;
 846         char    *pass = NULL;
 847         size_t  passlen = 0;
 848         void    *salt = NULL;   /* don't use NULL, see note on salt below */
 849         size_t  saltlen = 0;
 850         CK_KEY_TYPE ktype;
 851         void    *kvalue;
 852         size_t  klen;
 853 
 854         /* did init_crypto find a slot that supports this cipher? */
 855         if (cipher->slot == (CK_SLOT_ID)-1 || cipher->max_keysize == 0) {
 856                 rv = CKR_MECHANISM_INVALID;
 857                 goto cleanup;
 858         }
 859 
 860         rv = pkcs11_mech2keytype(cipher->type, &ktype);
 861         if (rv != CKR_OK)
 862                 goto cleanup;
 863 
 864         /*
 865          * use the passphrase to generate a PBE PKCS#5 secret key and
 866          * retrieve the raw key data to eventually pass it to the kernel;
 867          */
 868         rv = C_OpenSession(cipher->slot, CKF_SERIAL_SESSION, NULL, NULL, &sess);
 869         if (rv != CKR_OK)
 870                 goto cleanup;
 871 
 872         /* get user passphrase with 8 byte minimum */
 873         if (pkcs11_get_pass(NULL, &pass, &passlen, MIN_PASSLEN,
 874             with_confirmation) < 0) {
 875                 die(gettext("passphrases do not match\n"));
 876         }
 877 
 878         /*
 879          * salt should not be NULL, or else pkcs11_PasswdToKey() will
 880          * complain about CKR_MECHANISM_PARAM_INVALID; the following is
 881          * to make up for not having a salt until a proper one is used
 882          */
 883         salt = pass;
 884         saltlen = passlen;
 885 
 886         klen = cipher->max_keysize;
 887         rv = pkcs11_PasswdToKey(sess, pass, passlen, salt, saltlen, ktype,
 888             cipher->max_keysize, &kvalue, &klen);
 889 
 890         (void) C_CloseSession(sess);
 891 
 892         if (rv != CKR_OK) {
 893                 goto cleanup;
 894         }
 895 
 896         /* assert(klen == cipher->max_keysize); */
 897         *raw_key_sz = klen;
 898         *raw_key = (char *)kvalue;
 899         return;
 900 
 901 cleanup:
 902         die(gettext("failed to generate %s key from passphrase: %s"),
 903             cipher->alias, pkcs11_strerror(rv));
 904 }
 905 
 906 /*
 907  * Read raw key from file; also handles ephemeral keys.
 908  */
 909 void
 910 getkeyfromfile(const char *pathname, mech_alias_t *cipher, char **key,
 911     size_t *ksz)
 912 {
 913         int     fd;
 914         struct stat sbuf;
 915         boolean_t notplain = B_FALSE;
 916         ssize_t cursz;
 917         ssize_t nread;
 918 
 919         /* ephemeral keys are just random data */
 920         if (pathname == NULL) {
 921                 *ksz = cipher->max_keysize;
 922                 *key = malloc(*ksz);
 923                 if (*key == NULL)
 924                         die(gettext("failed to allocate memory for"
 925                             " ephemeral key"));
 926                 if (pkcs11_get_urandom(*key, *ksz) < 0) {
 927                         free(*key);
 928                         die(gettext("failed to get enough random data"));
 929                 }
 930                 return;
 931         }
 932 
 933         /*
 934          * If the remaining section of code didn't also check for secure keyfile
 935          * permissions and whether the key is within cipher min and max lengths,
 936          * (or, if those things moved out of this block), we could have had:
 937          *      if (pkcs11_read_data(pathname, key, ksz) < 0)
 938          *              handle_error();
 939          */
 940 
 941         if ((fd = open(pathname, O_RDONLY, 0)) == -1)
 942                 die(gettext("open of keyfile (%s) failed"), pathname);
 943 
 944         if (fstat(fd, &sbuf) == -1)
 945                 die(gettext("fstat of keyfile (%s) failed"), pathname);
 946 
 947         if (S_ISREG(sbuf.st_mode)) {
 948                 if ((sbuf.st_mode & (S_IWGRP | S_IWOTH)) != 0)
 949                         die(gettext("insecure permissions on keyfile %s\n"),
 950                             pathname);
 951 
 952                 *ksz = sbuf.st_size;
 953                 if (*ksz < cipher->min_keysize || cipher->max_keysize < *ksz) {
 954                         warn(gettext("%s: invalid keysize: %d\n"),
 955                             pathname, (int)*ksz);
 956                         die(gettext("\t%d <= keysize <= %d\n"),
 957                             cipher->min_keysize, cipher->max_keysize);
 958                 }
 959         } else {
 960                 *ksz = cipher->max_keysize;
 961                 notplain = B_TRUE;
 962         }
 963 
 964         *key = malloc(*ksz);
 965         if (*key == NULL)
 966                 die(gettext("failed to allocate memory for key from file"));
 967 
 968         for (cursz = 0, nread = 0; cursz < *ksz; cursz += nread) {
 969                 nread = read(fd, *key, *ksz);
 970                 if (nread > 0)
 971                         continue;
 972                 /*
 973                  * nread == 0.  If it's not a regular file we were trying to
 974                  * get the maximum keysize of data possible for this cipher.
 975                  * But if we've got at least the minimum keysize of data,
 976                  * round down to the nearest keysize unit and call it good.
 977                  * If we haven't met the minimum keysize, that's an error.
 978                  * If it's a regular file, nread = 0 is also an error.
 979                  */
 980                 if (nread == 0 && notplain && cursz >= cipher->min_keysize) {
 981                         *ksz = (cursz / cipher->min_keysize) *
 982                             cipher->min_keysize;
 983                         break;
 984                 }
 985                 die(gettext("%s: can't read all keybytes"), pathname);
 986         }
 987         (void) close(fd);
 988 }
 989 
 990 /*
 991  * Read the raw key from token, or from a file that was wrapped with a
 992  * key from token
 993  */
 994 void
 995 getkeyfromtoken(CK_SESSION_HANDLE sess,
 996     token_spec_t *token, const char *keyfile, mech_alias_t *cipher,
 997     char **raw_key, size_t *raw_key_sz)
 998 {
 999         CK_RV   rv = CKR_OK;
1000         CK_BBOOL trueval = B_TRUE;
1001         CK_OBJECT_CLASS kclass;         /* secret key or RSA private key */
1002         CK_KEY_TYPE ktype;              /* from selected cipher or CKK_RSA */
1003         CK_KEY_TYPE raw_ktype;          /* from selected cipher */
1004         CK_ATTRIBUTE    key_tmpl[] = {
1005                 { CKA_CLASS, NULL, 0 }, /* re-used for token key and unwrap */
1006                 { CKA_KEY_TYPE, NULL, 0 },      /* ditto */
1007                 { CKA_LABEL, NULL, 0 },
1008                 { CKA_TOKEN, NULL, 0 },
1009                 { CKA_PRIVATE, NULL, 0 }
1010             };
1011         CK_ULONG attrs = sizeof (key_tmpl) / sizeof (CK_ATTRIBUTE);
1012         int     i;
1013         char    *pass = NULL;
1014         size_t  passlen = 0;
1015         CK_OBJECT_HANDLE obj, rawobj;
1016         CK_ULONG num_objs = 1;          /* just want to find 1 token key */
1017         CK_MECHANISM unwrap = { CKM_RSA_PKCS, NULL, 0 };
1018         char    *rkey;
1019         size_t  rksz;
1020 
1021         if (token == NULL || token->key == NULL)
1022                 return;
1023 
1024         /* did init_crypto find a slot that supports this cipher? */
1025         if (cipher->slot == (CK_SLOT_ID)-1 || cipher->max_keysize == 0) {
1026                 die(gettext("failed to find any cryptographic provider, "
1027                     "use \"cryptoadm list -p\" to find providers: %s\n"),
1028                     pkcs11_strerror(CKR_MECHANISM_INVALID));
1029         }
1030 
1031         if (pkcs11_get_pass(token->name, &pass, &passlen, 0, B_FALSE) < 0)
1032                 die(gettext("unable to get passphrase"));
1033 
1034         /* use passphrase to login to token */
1035         if (pass != NULL && passlen > 0) {
1036                 rv = C_Login(sess, CKU_USER, (CK_UTF8CHAR_PTR)pass, passlen);
1037                 if (rv != CKR_OK) {
1038                         die(gettext("cannot login to the token %s: %s\n"),
1039                             token->name, pkcs11_strerror(rv));
1040                 }
1041         }
1042 
1043         rv = pkcs11_mech2keytype(cipher->type, &raw_ktype);
1044         if (rv != CKR_OK) {
1045                 die(gettext("failed to get key type for cipher %s: %s\n"),
1046                     cipher->name, pkcs11_strerror(rv));
1047         }
1048 
1049         /*
1050          * If no keyfile was given, then the token key is secret key to
1051          * be used for encryption/decryption.  Otherwise, the keyfile
1052          * contains a wrapped secret key, and the token is actually the
1053          * unwrapping RSA private key.
1054          */
1055         if (keyfile == NULL) {
1056                 kclass = CKO_SECRET_KEY;
1057                 ktype = raw_ktype;
1058         } else {
1059                 kclass = CKO_PRIVATE_KEY;
1060                 ktype = CKK_RSA;
1061         }
1062 
1063         /* Find the key in the token first */
1064         for (i = 0; i < attrs; i++) {
1065                 switch (key_tmpl[i].type) {
1066                 case CKA_CLASS:
1067                         key_tmpl[i].pValue = &kclass;
1068                         key_tmpl[i].ulValueLen = sizeof (kclass);
1069                         break;
1070                 case CKA_KEY_TYPE:
1071                         key_tmpl[i].pValue = &ktype;
1072                         key_tmpl[i].ulValueLen = sizeof (ktype);
1073                         break;
1074                 case CKA_LABEL:
1075                         key_tmpl[i].pValue = token->key;
1076                         key_tmpl[i].ulValueLen = strlen(token->key);
1077                         break;
1078                 case CKA_TOKEN:
1079                         key_tmpl[i].pValue = &trueval;
1080                         key_tmpl[i].ulValueLen = sizeof (trueval);
1081                         break;
1082                 case CKA_PRIVATE:
1083                         key_tmpl[i].pValue = &trueval;
1084                         key_tmpl[i].ulValueLen = sizeof (trueval);
1085                         break;
1086                 default:
1087                         break;
1088                 }
1089         }
1090         rv = C_FindObjectsInit(sess, key_tmpl, attrs);
1091         if (rv != CKR_OK)
1092                 die(gettext("cannot find key %s: %s\n"), token->key,
1093                     pkcs11_strerror(rv));
1094         rv = C_FindObjects(sess, &obj, 1, &num_objs);
1095         (void) C_FindObjectsFinal(sess);
1096 
1097         if (num_objs == 0) {
1098                 die(gettext("cannot find key %s\n"), token->key);
1099         } else if (rv != CKR_OK) {
1100                 die(gettext("cannot find key %s: %s\n"), token->key,
1101                     pkcs11_strerror(rv));
1102         }
1103 
1104         /*
1105          * No keyfile means when token key is found, convert it to raw key,
1106          * and done.  Otherwise still need do an unwrap to create yet another
1107          * obj and that needs to be converted to raw key before we're done.
1108          */
1109         if (keyfile == NULL) {
1110                 /* obj contains raw key, extract it */
1111                 rv = pkcs11_ObjectToKey(sess, obj, (void **)&rkey, &rksz,
1112                     B_FALSE);
1113                 if (rv != CKR_OK) {
1114                         die(gettext("failed to get key value for %s"
1115                             " from token %s, %s\n"), token->key,
1116                             token->name, pkcs11_strerror(rv));
1117                 }
1118         } else {
1119                 getkeyfromfile(keyfile, cipher, &rkey, &rksz);
1120 
1121                 /*
1122                  * Got the wrapping RSA obj and the wrapped key from file.
1123                  * Unwrap the key from file with RSA obj to get rawkey obj.
1124                  */
1125 
1126                 /* re-use the first two attributes of key_tmpl */
1127                 kclass = CKO_SECRET_KEY;
1128                 ktype = raw_ktype;
1129 
1130                 rv = C_UnwrapKey(sess, &unwrap, obj, (CK_BYTE_PTR)rkey,
1131                     rksz, key_tmpl, 2, &rawobj);
1132                 if (rv != CKR_OK) {
1133                         die(gettext("failed to unwrap key in keyfile %s,"
1134                             " %s\n"), keyfile, pkcs11_strerror(rv));
1135                 }
1136                 /* rawobj contains raw key, extract it */
1137                 rv = pkcs11_ObjectToKey(sess, rawobj, (void **)&rkey, &rksz,
1138                     B_TRUE);
1139                 if (rv != CKR_OK) {
1140                         die(gettext("failed to get unwrapped key value for"
1141                             " key in keyfile %s, %s\n"), keyfile,
1142                             pkcs11_strerror(rv));
1143                 }
1144         }
1145 
1146         /* validate raw key size */
1147         if (rksz < cipher->min_keysize || cipher->max_keysize < rksz) {
1148                 warn(gettext("%s: invalid keysize: %d\n"), keyfile, (int)rksz);
1149                 die(gettext("\t%d <= keysize <= %d\n"), cipher->min_keysize,
1150                     cipher->max_keysize);
1151         }
1152 
1153         *raw_key_sz = rksz;
1154         *raw_key = (char *)rkey;
1155 }
1156 
1157 /*
1158  * Set up cipher key limits and verify PKCS#11 can be done
1159  * match_token_cipher is the function pointer used by
1160  * pkcs11_GetCriteriaSession() init_crypto.
1161  */
1162 boolean_t
1163 match_token_cipher(CK_SLOT_ID slot_id, void *args, CK_RV *rv)
1164 {
1165         token_spec_t *token;
1166         mech_alias_t *cipher;
1167         CK_TOKEN_INFO tokinfo;
1168         CK_MECHANISM_INFO mechinfo;
1169         boolean_t token_match;
1170 
1171         /*
1172          * While traversing slot list, pick up the following info per slot:
1173          * - if token specified, whether it matches this slot's token info
1174          * - if the slot supports the PKCS#5 PBKD2 cipher
1175          *
1176          * If the user said on the command line
1177          *      -T tok:mfr:ser:lab -k keyfile
1178          *      -c cipher -T tok:mfr:ser:lab -k keyfile
1179          * the given cipher or the default cipher apply to keyfile,
1180          * If the user said instead
1181          *      -T tok:mfr:ser:lab
1182          *      -c cipher -T tok:mfr:ser:lab
1183          * the key named "lab" may or may not agree with the given
1184          * cipher or the default cipher.  In those cases, cipher will
1185          * be overridden with the actual cipher type of the key "lab".
1186          */
1187         *rv = CKR_FUNCTION_FAILED;
1188 
1189         if (args == NULL) {
1190                 return (B_FALSE);
1191         }
1192 
1193         cipher = (mech_alias_t *)args;
1194         token = cipher->token;
1195 
1196         if (C_GetMechanismInfo(slot_id, cipher->type, &mechinfo) != CKR_OK) {
1197                 return (B_FALSE);
1198         }
1199 
1200         if (token == NULL) {
1201                 if (C_GetMechanismInfo(slot_id, CKM_PKCS5_PBKD2, &mechinfo) !=
1202                     CKR_OK) {
1203                         return (B_FALSE);
1204                 }
1205                 goto foundit;
1206         }
1207 
1208         /* does the token match the token spec? */
1209         if (token->key == NULL || (C_GetTokenInfo(slot_id, &tokinfo) != CKR_OK))
1210                 return (B_FALSE);
1211 
1212         token_match = B_TRUE;
1213 
1214         if (token->name != NULL && (token->name)[0] != '\0' &&
1215             strncmp((char *)token->name, (char *)tokinfo.label,
1216             TOKEN_LABEL_SIZE) != 0)
1217                 token_match = B_FALSE;
1218         if (token->mfr != NULL && (token->mfr)[0] != '\0' &&
1219             strncmp((char *)token->mfr, (char *)tokinfo.manufacturerID,
1220             TOKEN_MANUFACTURER_SIZE) != 0)
1221                 token_match = B_FALSE;
1222         if (token->serno != NULL && (token->serno)[0] != '\0' &&
1223             strncmp((char *)token->serno, (char *)tokinfo.serialNumber,
1224             TOKEN_SERIAL_SIZE) != 0)
1225                 token_match = B_FALSE;
1226 
1227         if (!token_match)
1228                 return (B_FALSE);
1229 
1230 foundit:
1231         cipher->slot = slot_id;
1232         return (B_TRUE);
1233 }
1234 
1235 /*
1236  * Clean up crypto loose ends
1237  */
1238 static void
1239 end_crypto(CK_SESSION_HANDLE sess)
1240 {
1241         (void) C_CloseSession(sess);
1242         (void) C_Finalize(NULL);
1243 }
1244 
1245 /*
1246  * Set up crypto, opening session on slot that matches token and cipher
1247  */
1248 static void
1249 init_crypto(token_spec_t *token, mech_alias_t *cipher,
1250     CK_SESSION_HANDLE_PTR sess)
1251 {
1252         CK_RV   rv;
1253 
1254         cipher->token = token;
1255 
1256         /* Turn off Metaslot so that we can see actual tokens */
1257         if (setenv("METASLOT_ENABLED", "false", 1) < 0) {
1258                 die(gettext("could not disable Metaslot"));
1259         }
1260 
1261         rv = pkcs11_GetCriteriaSession(match_token_cipher, (void *)cipher,
1262             sess);
1263         if (rv != CKR_OK) {
1264                 end_crypto(*sess);
1265                 if (rv == CKR_HOST_MEMORY) {
1266                         die("malloc");
1267                 }
1268                 die(gettext("failed to find any cryptographic provider, "
1269                     "use \"cryptoadm list -p\" to find providers: %s\n"),
1270                     pkcs11_strerror(rv));
1271         }
1272 }
1273 
1274 /*
1275  * Uncompress a file.
1276  *
1277  * First map the file in to establish a device
1278  * association, then read from it. On-the-fly
1279  * decompression will automatically uncompress
1280  * the file if it's compressed
1281  *
1282  * If the file is mapped and a device association
1283  * has been established, disallow uncompressing
1284  * the file until it is unmapped.
1285  */
1286 static void
1287 lofi_uncompress(int lfd, const char *filename)
1288 {
1289         struct lofi_ioctl li;
1290         char buf[MAXBSIZE];
1291         char devicename[32];
1292         char tmpfilename[MAXPATHLEN];
1293         char *x;
1294         char *dir = NULL;
1295         char *file = NULL;
1296         int minor = 0;
1297         struct stat64 statbuf;
1298         int compfd = -1;
1299         int uncompfd = -1;
1300         ssize_t rbytes;
1301 
1302         /*
1303          * Disallow uncompressing the file if it is
1304          * already mapped.
1305          */
1306         li.li_crypto_enabled = B_FALSE;
1307         li.li_minor = 0;
1308         (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename));
1309         if (ioctl(lfd, LOFI_GET_MINOR, &li) != -1)
1310                 die(gettext("%s must be unmapped before uncompressing"),
1311                     filename);
1312 
1313         /* Zero length files don't need to be uncompressed */
1314         if (stat64(filename, &statbuf) == -1)
1315                 die(gettext("stat: %s"), filename);
1316         if (statbuf.st_size == 0)
1317                 return;
1318 
1319         minor = lofi_map_file(lfd, li, filename);
1320         (void) snprintf(devicename, sizeof (devicename), "/dev/%s/%d",
1321             LOFI_BLOCK_NAME, minor);
1322 
1323         /* If the file isn't compressed, we just return */
1324         if ((ioctl(lfd, LOFI_CHECK_COMPRESSED, &li) == -1) ||
1325             (li.li_algorithm[0] == '\0')) {
1326                 delete_mapping(lfd, devicename, filename, B_TRUE);
1327                 die("%s is not compressed\n", filename);
1328         }
1329 
1330         if ((compfd = open64(devicename, O_RDONLY | O_NONBLOCK)) == -1) {
1331                 delete_mapping(lfd, devicename, filename, B_TRUE);
1332                 die(gettext("open: %s"), filename);
1333         }
1334         /* Create a temp file in the same directory */
1335         x = strdup(filename);
1336         dir = strdup(dirname(x));
1337         free(x);
1338         x = strdup(filename);
1339         file = strdup(basename(x));
1340         free(x);
1341         (void) snprintf(tmpfilename, sizeof (tmpfilename),
1342             "%s/.%sXXXXXX", dir, file);
1343         free(dir);
1344         free(file);
1345 
1346         if ((uncompfd = mkstemp64(tmpfilename)) == -1) {
1347                 (void) close(compfd);
1348                 delete_mapping(lfd, devicename, filename, B_TRUE);
1349                 die("%s could not be uncompressed\n", filename);
1350         }
1351 
1352         /*
1353          * Set the mode bits and the owner of this temporary
1354          * file to be that of the original uncompressed file
1355          */
1356         (void) fchmod(uncompfd, statbuf.st_mode);
1357 
1358         if (fchown(uncompfd, statbuf.st_uid, statbuf.st_gid) == -1) {
1359                 (void) close(compfd);
1360                 (void) close(uncompfd);
1361                 delete_mapping(lfd, devicename, filename, B_TRUE);
1362                 die("%s could not be uncompressed\n", filename);
1363         }
1364 
1365         /* Now read from the device in MAXBSIZE-sized chunks */
1366         for (;;) {
1367                 rbytes = read(compfd, buf, sizeof (buf));
1368 
1369                 if (rbytes <= 0)
1370                         break;
1371 
1372                 if (write(uncompfd, buf, rbytes) != rbytes) {
1373                         rbytes = -1;
1374                         break;
1375                 }
1376         }
1377 
1378         (void) close(compfd);
1379         (void) close(uncompfd);
1380 
1381         /* Delete the mapping */
1382         delete_mapping(lfd, devicename, filename, B_TRUE);
1383 
1384         /*
1385          * If an error occured while reading or writing, rbytes will
1386          * be negative
1387          */
1388         if (rbytes < 0) {
1389                 (void) unlink(tmpfilename);
1390                 die(gettext("could not read from %s"), filename);
1391         }
1392 
1393         /* Rename the temp file to the actual file */
1394         if (rename(tmpfilename, filename) == -1)
1395                 (void) unlink(tmpfilename);
1396 }
1397 
1398 /*
1399  * Compress a file
1400  */
1401 static void
1402 lofi_compress(int *lfd, const char *filename, int compress_index,
1403     uint32_t segsize)
1404 {
1405         struct lofi_ioctl lic;
1406         lofi_compress_info_t *li;
1407         struct flock lock;
1408         char tmpfilename[MAXPATHLEN];
1409         char comp_filename[MAXPATHLEN];
1410         char algorithm[MAXALGLEN];
1411         char *x;
1412         char *dir = NULL, *file = NULL;
1413         uchar_t *uncompressed_seg = NULL;
1414         uchar_t *compressed_seg = NULL;
1415         uint32_t compressed_segsize;
1416         uint32_t len_compressed, count;
1417         uint32_t index_entries, index_sz;
1418         uint64_t *index = NULL;
1419         uint64_t offset;
1420         size_t real_segsize;
1421         struct stat64 statbuf;
1422         int compfd = -1, uncompfd = -1;
1423         int tfd = -1;
1424         ssize_t rbytes, wbytes, lastread;
1425         int i, type;
1426 
1427         /*
1428          * Disallow compressing the file if it is
1429          * already mapped
1430          */
1431         lic.li_minor = 0;
1432         (void) strlcpy(lic.li_filename, filename, sizeof (lic.li_filename));
1433         if (ioctl(*lfd, LOFI_GET_MINOR, &lic) != -1)
1434                 die(gettext("%s must be unmapped before compressing"),
1435                     filename);
1436 
1437         /*
1438          * Close the control device so other operations
1439          * can use it
1440          */
1441         (void) close(*lfd);
1442         *lfd = -1;
1443 
1444         li = &lofi_compress_table[compress_index];
1445 
1446         /*
1447          * The size of the buffer to hold compressed data must
1448          * be slightly larger than the compressed segment size.
1449          *
1450          * The compress functions use part of the buffer as
1451          * scratch space to do calculations.
1452          * Ref: http://www.zlib.net/manual.html#compress2
1453          */
1454         compressed_segsize = segsize + (segsize >> 6);
1455         compressed_seg = (uchar_t *)malloc(compressed_segsize + SEGHDR);
1456         uncompressed_seg = (uchar_t *)malloc(segsize);
1457 
1458         if (compressed_seg == NULL || uncompressed_seg == NULL)
1459                 die(gettext("No memory"));
1460 
1461         if ((uncompfd = open64(filename, O_RDWR|O_LARGEFILE, 0)) == -1)
1462                 die(gettext("open: %s"), filename);
1463 
1464         lock.l_type = F_WRLCK;
1465         lock.l_whence = SEEK_SET;
1466         lock.l_start = 0;
1467         lock.l_len = 0;
1468 
1469         /*
1470          * Use an advisory lock to ensure that only a
1471          * single lofiadm process compresses a given
1472          * file at any given time
1473          *
1474          * A close on the file descriptor automatically
1475          * closes all lock state on the file
1476          */
1477         if (fcntl(uncompfd, F_SETLKW, &lock) == -1)
1478                 die(gettext("fcntl: %s"), filename);
1479 
1480         if (fstat64(uncompfd, &statbuf) == -1) {
1481                 (void) close(uncompfd);
1482                 die(gettext("fstat: %s"), filename);
1483         }
1484 
1485         /* Zero length files don't need to be compressed */
1486         if (statbuf.st_size == 0) {
1487                 (void) close(uncompfd);
1488                 return;
1489         }
1490 
1491         /*
1492          * Create temporary files in the same directory that
1493          * will hold the intermediate data
1494          */
1495         x = strdup(filename);
1496         dir = strdup(dirname(x));
1497         free(x);
1498         x = strdup(filename);
1499         file = strdup(basename(x));
1500         free(x);
1501         (void) snprintf(tmpfilename, sizeof (tmpfilename),
1502             "%s/.%sXXXXXX", dir, file);
1503         (void) snprintf(comp_filename, sizeof (comp_filename),
1504             "%s/.%sXXXXXX", dir, file);
1505         free(dir);
1506         free(file);
1507 
1508         if ((tfd = mkstemp64(tmpfilename)) == -1)
1509                 goto cleanup;
1510 
1511         if ((compfd = mkstemp64(comp_filename)) == -1)
1512                 goto cleanup;
1513 
1514         /*
1515          * Set the mode bits and owner of the compressed
1516          * file to be that of the original uncompressed file
1517          */
1518         (void) fchmod(compfd, statbuf.st_mode);
1519 
1520         if (fchown(compfd, statbuf.st_uid, statbuf.st_gid) == -1)
1521                 goto cleanup;
1522 
1523         /*
1524          * Calculate the number of index entries required.
1525          * index entries are stored as an array. adding
1526          * a '2' here accounts for the fact that the last
1527          * segment may not be a multiple of the segment size
1528          */
1529         index_sz = (statbuf.st_size / segsize) + 2;
1530         index = malloc(sizeof (*index) * index_sz);
1531 
1532         if (index == NULL)
1533                 goto cleanup;
1534 
1535         offset = 0;
1536         lastread = segsize;
1537         count = 0;
1538 
1539         /*
1540          * Now read from the uncompressed file in 'segsize'
1541          * sized chunks, compress what was read in and
1542          * write it out to a temporary file
1543          */
1544         for (;;) {
1545                 rbytes = read(uncompfd, uncompressed_seg, segsize);
1546 
1547                 if (rbytes <= 0)
1548                         break;
1549 
1550                 if (lastread < segsize)
1551                         goto cleanup;
1552 
1553                 /*
1554                  * Account for the first byte that
1555                  * indicates whether a segment is
1556                  * compressed or not
1557                  */
1558                 real_segsize = segsize - 1;
1559                 (void) li->l_compress(uncompressed_seg, rbytes,
1560                     compressed_seg + SEGHDR, &real_segsize, li->l_level);
1561 
1562                 /*
1563                  * If the length of the compressed data is more
1564                  * than a threshold then there isn't any benefit
1565                  * to be had from compressing this segment - leave
1566                  * it uncompressed.
1567                  *
1568                  * NB. In case an error occurs during compression (above)
1569                  * the 'real_segsize' isn't changed. The logic below
1570                  * ensures that that segment is left uncompressed.
1571                  */
1572                 len_compressed = real_segsize;
1573                 if (segsize <= COMPRESS_THRESHOLD ||
1574                     real_segsize > (segsize - COMPRESS_THRESHOLD)) {
1575                         (void) memcpy(compressed_seg + SEGHDR, uncompressed_seg,
1576                             rbytes);
1577                         type = UNCOMPRESSED;
1578                         len_compressed = rbytes;
1579                 } else {
1580                         type = COMPRESSED;
1581                 }
1582 
1583                 /*
1584                  * Set the first byte or the SEGHDR to
1585                  * indicate if it's compressed or not
1586                  */
1587                 *compressed_seg = type;
1588                 wbytes = write(tfd, compressed_seg, len_compressed + SEGHDR);
1589                 if (wbytes != (len_compressed + SEGHDR)) {
1590                         rbytes = -1;
1591                         break;
1592                 }
1593 
1594                 index[count] = BE_64(offset);
1595                 offset += wbytes;
1596                 lastread = rbytes;
1597                 count++;
1598         }
1599 
1600         (void) close(uncompfd);
1601 
1602         if (rbytes < 0)
1603                 goto cleanup;
1604         /*
1605          * The last index entry is a sentinel entry. It does not point to
1606          * an actual compressed segment but helps in computing the size of
1607          * the compressed segment. The size of each compressed segment is
1608          * computed by subtracting the current index value from the next
1609          * one (the compressed blocks are stored sequentially)
1610          */
1611         index[count++] = BE_64(offset);
1612 
1613         /*
1614          * Now write the compressed data along with the
1615          * header information to this file which will
1616          * later be renamed to the original uncompressed
1617          * file name
1618          *
1619          * The header is as follows -
1620          *
1621          * Signature (name of the compression algorithm)
1622          * Compression segment size (a multiple of 512)
1623          * Number of index entries
1624          * Size of the last block
1625          * The array containing the index entries
1626          *
1627          * the header is always stored in network byte
1628          * order
1629          */
1630         (void) bzero(algorithm, sizeof (algorithm));
1631         (void) strlcpy(algorithm, li->l_name, sizeof (algorithm));
1632         if (write(compfd, algorithm, sizeof (algorithm))
1633             != sizeof (algorithm))
1634                 goto cleanup;
1635 
1636         segsize = htonl(segsize);
1637         if (write(compfd, &segsize, sizeof (segsize)) != sizeof (segsize))
1638                 goto cleanup;
1639 
1640         index_entries = htonl(count);
1641         if (write(compfd, &index_entries, sizeof (index_entries)) !=
1642             sizeof (index_entries))
1643                 goto cleanup;
1644 
1645         lastread = htonl(lastread);
1646         if (write(compfd, &lastread, sizeof (lastread)) != sizeof (lastread))
1647                 goto cleanup;
1648 
1649         for (i = 0; i < count; i++) {
1650                 if (write(compfd, index + i, sizeof (*index)) !=
1651                     sizeof (*index))
1652                         goto cleanup;
1653         }
1654 
1655         /* Header is written, now write the compressed data */
1656         if (lseek(tfd, 0, SEEK_SET) != 0)
1657                 goto cleanup;
1658 
1659         rbytes = wbytes = 0;
1660 
1661         for (;;) {
1662                 rbytes = read(tfd, compressed_seg, compressed_segsize + SEGHDR);
1663 
1664                 if (rbytes <= 0)
1665                         break;
1666 
1667                 if (write(compfd, compressed_seg, rbytes) != rbytes)
1668                         goto cleanup;
1669         }
1670 
1671         if (fstat64(compfd, &statbuf) == -1)
1672                 goto cleanup;
1673 
1674         /*
1675          * Round up the compressed file size to be a multiple of
1676          * DEV_BSIZE. lofi(7D) likes it that way.
1677          */
1678         if ((offset = statbuf.st_size % DEV_BSIZE) > 0) {
1679 
1680                 offset = DEV_BSIZE - offset;
1681 
1682                 for (i = 0; i < offset; i++)
1683                         uncompressed_seg[i] = '\0';
1684                 if (write(compfd, uncompressed_seg, offset) != offset)
1685                         goto cleanup;
1686         }
1687         (void) close(compfd);
1688         (void) close(tfd);
1689         (void) unlink(tmpfilename);
1690 cleanup:
1691         if (rbytes < 0) {
1692                 if (tfd != -1)
1693                         (void) unlink(tmpfilename);
1694                 if (compfd != -1)
1695                         (void) unlink(comp_filename);
1696                 die(gettext("error compressing file %s"), filename);
1697         } else {
1698                 /* Rename the compressed file to the actual file */
1699                 if (rename(comp_filename, filename) == -1) {
1700                         (void) unlink(comp_filename);
1701                         die(gettext("error compressing file %s"), filename);
1702                 }
1703         }
1704         if (compressed_seg != NULL)
1705                 free(compressed_seg);
1706         if (uncompressed_seg != NULL)
1707                 free(uncompressed_seg);
1708         if (index != NULL)
1709                 free(index);
1710         if (compfd != -1)
1711                 (void) close(compfd);
1712         if (uncompfd != -1)
1713                 (void) close(uncompfd);
1714         if (tfd != -1)
1715                 (void) close(tfd);
1716 }
1717 
1718 static int
1719 lofi_compress_select(const char *algname)
1720 {
1721         int i;
1722 
1723         for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) {
1724                 if (strcmp(lofi_compress_table[i].l_name, algname) == 0)
1725                         return (i);
1726         }
1727         return (-1);
1728 }
1729 
1730 static void
1731 check_algorithm_validity(const char *algname, int *compress_index)
1732 {
1733         *compress_index = lofi_compress_select(algname);
1734         if (*compress_index < 0)
1735                 die(gettext("invalid algorithm name: %s\n"), algname);
1736 }
1737 
1738 static void
1739 check_file_validity(const char *filename)
1740 {
1741         struct stat64 buf;
1742         int     error;
1743         int     fd;
1744 
1745         fd = open64(filename, O_RDONLY);
1746         if (fd == -1) {
1747                 die(gettext("open: %s"), filename);
1748         }
1749         error = fstat64(fd, &buf);
1750         if (error == -1) {
1751                 die(gettext("fstat: %s"), filename);
1752         } else if (!S_ISLOFIABLE(buf.st_mode)) {
1753                 die(gettext("%s is not a regular file, "
1754                     "block, or character device\n"),
1755                     filename);
1756         } else if ((buf.st_size % DEV_BSIZE) != 0) {
1757                 die(gettext("size of %s is not a multiple of %d\n"),
1758                     filename, DEV_BSIZE);
1759         }
1760         (void) close(fd);
1761 
1762         if (name_to_minor(filename) != 0) {
1763                 die(gettext("cannot use %s on itself\n"), LOFI_DRIVER_NAME);
1764         }
1765 }
1766 
1767 static boolean_t
1768 check_file_is_encrypted(const char *filename)
1769 {
1770         int     fd;
1771         char    buf[sizeof (lofi_crypto_magic)];
1772         int     got;
1773         int     rest = sizeof (lofi_crypto_magic);
1774 
1775         fd = open64(filename, O_RDONLY);
1776         if (fd == -1)
1777                 die(gettext("failed to open: %s"), filename);
1778 
1779         if (lseek(fd, CRYOFF, SEEK_SET) != CRYOFF)
1780                 die(gettext("failed to seek to offset 0x%lx in file %s"),
1781                     CRYOFF, filename);
1782 
1783         do {
1784                 got = read(fd, buf + sizeof (lofi_crypto_magic) - rest, rest);
1785                 if ((got == 0) || ((got == -1) && (errno != EINTR)))
1786                         die(gettext("failed to read crypto header"
1787                             " at offset 0x%lx in file %s"), CRYOFF, filename);
1788 
1789                 if (got > 0)
1790                         rest -= got;
1791         } while (rest > 0);
1792 
1793         while (close(fd) == -1) {
1794                 if (errno != EINTR)
1795                         die(gettext("failed to close file %s"), filename);
1796         }
1797 
1798         return (strncmp(buf, lofi_crypto_magic,
1799             sizeof (lofi_crypto_magic)) == 0);
1800 }
1801 
1802 static uint32_t
1803 convert_to_num(const char *str)
1804 {
1805         int len;
1806         uint32_t segsize, mult = 1;
1807 
1808         len = strlen(str);
1809         if (len && isalpha(str[len - 1])) {
1810                 switch (str[len - 1]) {
1811                 case 'k':
1812                 case 'K':
1813                         mult = KILOBYTE;
1814                         break;
1815                 case 'b':
1816                 case 'B':
1817                         mult = BLOCK_SIZE;
1818                         break;
1819                 case 'm':
1820                 case 'M':
1821                         mult = MEGABYTE;
1822                         break;
1823                 case 'g':
1824                 case 'G':
1825                         mult = GIGABYTE;
1826                         break;
1827                 default:
1828                         die(gettext("invalid segment size %s\n"), str);
1829                 }
1830         }
1831 
1832         segsize = atol(str);
1833         segsize *= mult;
1834 
1835         return (segsize);
1836 }
1837 
1838 int
1839 main(int argc, char *argv[])
1840 {
1841         int     lfd;
1842         int     c;
1843         const char *devicename = NULL;
1844         const char *filename = NULL;
1845         const char *algname = COMPRESS_ALGORITHM;
1846         int     openflag;
1847         int     minor;
1848         int     compress_index;
1849         uint32_t segsize = SEGSIZE;
1850         static char *lofictl = "/dev/" LOFI_CTL_NAME;
1851         boolean_t force = B_FALSE;
1852         const char *pname;
1853         boolean_t errflag = B_FALSE;
1854         boolean_t addflag = B_FALSE;
1855         boolean_t rdflag = B_FALSE;
1856         boolean_t deleteflag = B_FALSE;
1857         boolean_t ephflag = B_FALSE;
1858         boolean_t compressflag = B_FALSE;
1859         boolean_t uncompressflag = B_FALSE;
1860         /* the next two work together for -c, -k, -T, -e options only */
1861         boolean_t need_crypto = B_FALSE;        /* if any -c, -k, -T, -e */
1862         boolean_t cipher_only = B_TRUE;         /* if -c only */
1863         const char *keyfile = NULL;
1864         mech_alias_t *cipher = NULL;
1865         token_spec_t *token = NULL;
1866         char    *rkey = NULL;
1867         size_t  rksz = 0;
1868         char realfilename[MAXPATHLEN];
1869 
1870         pname = getpname(argv[0]);
1871 
1872         (void) setlocale(LC_ALL, "");
1873         (void) textdomain(TEXT_DOMAIN);
1874 
1875         while ((c = getopt(argc, argv, "a:c:Cd:efk:rs:T:U")) != EOF) {
1876                 switch (c) {
1877                 case 'a':
1878                         addflag = B_TRUE;
1879                         if ((filename = realpath(optarg, realfilename)) == NULL)
1880                                 die("%s", optarg);
1881                         if (((argc - optind) > 0) && (*argv[optind] != '-')) {
1882                                 /* optional device */
1883                                 devicename = argv[optind];
1884                                 optind++;
1885                         }
1886                         break;
1887                 case 'C':
1888                         compressflag = B_TRUE;
1889                         if (((argc - optind) > 1) && (*argv[optind] != '-')) {
1890                                 /* optional algorithm */
1891                                 algname = argv[optind];
1892                                 optind++;
1893                         }
1894                         check_algorithm_validity(algname, &compress_index);
1895                         break;
1896                 case 'c':
1897                         /* is the chosen cipher allowed? */
1898                         if ((cipher = ciph2mech(optarg)) == NULL) {
1899                                 errflag = B_TRUE;
1900                                 warn(gettext("cipher %s not allowed\n"),
1901                                     optarg);
1902                         }
1903                         need_crypto = B_TRUE;
1904                         /* cipher_only is already set */
1905                         break;
1906                 case 'd':
1907                         deleteflag = B_TRUE;
1908                         minor = name_to_minor(optarg);
1909                         if (minor != 0)
1910                                 devicename = optarg;
1911                         else {
1912                                 if ((filename = realpath(optarg,
1913                                     realfilename)) == NULL)
1914                                         die("%s", optarg);
1915                         }
1916                         break;
1917                 case 'e':
1918                         ephflag = B_TRUE;
1919                         need_crypto = B_TRUE;
1920                         cipher_only = B_FALSE;  /* need to unset cipher_only */
1921                         break;
1922                 case 'f':
1923                         force = B_TRUE;
1924                         break;
1925                 case 'k':
1926                         keyfile = optarg;
1927                         need_crypto = B_TRUE;
1928                         cipher_only = B_FALSE;  /* need to unset cipher_only */
1929                         break;
1930                 case 'r':
1931                         rdflag = B_TRUE;
1932                         break;
1933                 case 's':
1934                         segsize = convert_to_num(optarg);
1935                         if (segsize < DEV_BSIZE || !ISP2(segsize))
1936                                 die(gettext("segment size %s is invalid "
1937                                     "or not a multiple of minimum block "
1938                                     "size %ld\n"), optarg, DEV_BSIZE);
1939                         break;
1940                 case 'T':
1941                         if ((token = parsetoken(optarg)) == NULL) {
1942                                 errflag = B_TRUE;
1943                                 warn(
1944                                     gettext("invalid token key specifier %s\n"),
1945                                     optarg);
1946                         }
1947                         need_crypto = B_TRUE;
1948                         cipher_only = B_FALSE;  /* need to unset cipher_only */
1949                         break;
1950                 case 'U':
1951                         uncompressflag = B_TRUE;
1952                         break;
1953                 case '?':
1954                 default:
1955                         errflag = B_TRUE;
1956                         break;
1957                 }
1958         }
1959 
1960         /* Check for mutually exclusive combinations of options */
1961         if (errflag ||
1962             (addflag && deleteflag) ||
1963             (rdflag && !addflag) ||
1964             (!addflag && need_crypto) ||
1965             ((compressflag || uncompressflag) && (addflag || deleteflag)))
1966                 usage(pname);
1967 
1968         /* ephemeral key, and key from either file or token are incompatible */
1969         if (ephflag && (keyfile != NULL || token != NULL)) {
1970                 die(gettext("ephemeral key cannot be used with keyfile"
1971                     " or token key\n"));
1972         }
1973 
1974         /*
1975          * "-c" but no "-k", "-T", "-e", or "-T -k" means derive key from
1976          * command line passphrase
1977          */
1978 
1979         switch (argc - optind) {
1980         case 0: /* no more args */
1981                 if (compressflag || uncompressflag)     /* needs filename */
1982                         usage(pname);
1983                 break;
1984         case 1:
1985                 if (addflag || deleteflag)
1986                         usage(pname);
1987                 /* one arg means compress/uncompress the file ... */
1988                 if (compressflag || uncompressflag) {
1989                         if ((filename = realpath(argv[optind],
1990                             realfilename)) == NULL)
1991                                 die("%s", argv[optind]);
1992                 /* ... or without options means print the association */
1993                 } else {
1994                         minor = name_to_minor(argv[optind]);
1995                         if (minor != 0)
1996                                 devicename = argv[optind];
1997                         else {
1998                                 if ((filename = realpath(argv[optind],
1999                                     realfilename)) == NULL)
2000                                         die("%s", argv[optind]);
2001                         }
2002                 }
2003                 break;
2004         default:
2005                 usage(pname);
2006                 break;
2007         }
2008 
2009         if (addflag || compressflag || uncompressflag)
2010                 check_file_validity(filename);
2011 
2012         if (filename && !valid_abspath(filename))
2013                 exit(E_ERROR);
2014 
2015         /*
2016          * Here, we know the arguments are correct, the filename is an
2017          * absolute path, it exists and is a regular file. We don't yet
2018          * know that the device name is ok or not.
2019          */
2020 
2021         openflag = O_EXCL;
2022         if (addflag || deleteflag || compressflag || uncompressflag)
2023                 openflag |= O_RDWR;
2024         else
2025                 openflag |= O_RDONLY;
2026         lfd = open(lofictl, openflag);
2027         if (lfd == -1) {
2028                 if ((errno == EPERM) || (errno == EACCES)) {
2029                         die(gettext("you do not have permission to perform "
2030                             "that operation.\n"));
2031                 } else {
2032                         die(gettext("open: %s"), lofictl);
2033                 }
2034                 /*NOTREACHED*/
2035         }
2036 
2037         /*
2038          * No passphrase is needed for ephemeral key, or when key is
2039          * in a file and not wrapped by another key from a token.
2040          * However, a passphrase is needed in these cases:
2041          * 1. cipher with no ephemeral key, key file, or token,
2042          *    in which case the passphrase is used to build the key
2043          * 2. token with an optional cipher or optional key file,
2044          *    in which case the passphrase unlocks the token
2045          * If only the cipher is specified, reconfirm the passphrase
2046          * to ensure the user hasn't mis-entered it.  Otherwise, the
2047          * token will enforce the token passphrase.
2048          */
2049         if (need_crypto) {
2050                 CK_SESSION_HANDLE       sess;
2051 
2052                 /* pick a cipher if none specified */
2053                 if (cipher == NULL)
2054                         cipher = DEFAULT_CIPHER;
2055 
2056                 if (!kernel_cipher_check(cipher))
2057                         die(gettext(
2058                             "use \"cryptoadm list -m\" to find available "
2059                             "mechanisms\n"));
2060 
2061                 init_crypto(token, cipher, &sess);
2062 
2063                 if (cipher_only) {
2064                         getkeyfromuser(cipher, &rkey, &rksz,
2065                             !check_file_is_encrypted(filename));
2066                 } else if (token != NULL) {
2067                         getkeyfromtoken(sess, token, keyfile, cipher,
2068                             &rkey, &rksz);
2069                 } else {
2070                         /* this also handles ephemeral keys */
2071                         getkeyfromfile(keyfile, cipher, &rkey, &rksz);
2072                 }
2073 
2074                 end_crypto(sess);
2075         }
2076 
2077         /*
2078          * Now to the real work.
2079          */
2080         if (addflag)
2081                 add_mapping(lfd, devicename, filename, cipher, rkey, rksz,
2082                     rdflag);
2083         else if (compressflag)
2084                 lofi_compress(&lfd, filename, compress_index, segsize);
2085         else if (uncompressflag)
2086                 lofi_uncompress(lfd, filename);
2087         else if (deleteflag)
2088                 delete_mapping(lfd, devicename, filename, force);
2089         else if (filename || devicename)
2090                 print_one_mapping(lfd, devicename, filename);
2091         else
2092                 print_mappings(lfd);
2093 
2094         if (lfd != -1)
2095                 (void) close(lfd);
2096         closelib();
2097         return (E_SUCCESS);
2098 }