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