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