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