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 -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 */
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)
368 {
369 struct lofi_ioctl li;
370
371 li.li_crypto_enabled = B_FALSE;
372 if (cipher != NULL) {
373 /* set up encryption for mapped file */
374 li.li_crypto_enabled = B_TRUE;
375 (void) strlcpy(li.li_cipher, cipher->name,
376 sizeof (li.li_cipher));
377 if (rksz > sizeof (li.li_key)) {
378 die(gettext("key too large"));
379 }
380 bcopy(rkey, li.li_key, rksz);
381 li.li_key_len = rksz << 3; /* convert to bits */
382
383 li.li_iv_type = cipher->iv_type;
384 li.li_iv_len = cipher->iv_len; /* 0 when no iv needed */
385 switch (cipher->iv_type) {
386 case IVM_ENC_BLKNO:
387 (void) strlcpy(li.li_iv_cipher, cipher->iv_name,
388 sizeof (li.li_iv_cipher));
389 break;
390 case IVM_NONE:
480 li.li_minor = name_to_minor(devicename);
481 if (li.li_minor == 0) {
482 die(gettext("malformed device name %s\n"), devicename);
483 }
484 if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) {
485 die(gettext("could not find filename for %s"), devicename);
486 }
487 (void) printf("%s\n", li.li_filename);
488 }
489
490 /*
491 * Print the list of all the mappings, including a header.
492 */
493 static void
494 print_mappings(int fd)
495 {
496 struct lofi_ioctl li;
497 int minor;
498 int maxminor;
499 char path[MAXPATHLEN];
500 char options[MAXPATHLEN];
501
502 li.li_minor = 0;
503 if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) {
504 die("ioctl");
505 }
506 maxminor = li.li_minor;
507
508 (void) printf(FORMAT, gettext("Block Device"), gettext("File"),
509 gettext("Options"));
510 for (minor = 1; minor <= maxminor; minor++) {
511 li.li_minor = minor;
512 if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) {
513 if (errno == ENXIO)
514 continue;
515 warn("ioctl");
516 break;
517 }
518 (void) snprintf(path, sizeof (path), "/dev/%s/%d",
519 LOFI_BLOCK_NAME, minor);
520 /*
521 * Encrypted lofi and compressed lofi are mutually exclusive.
522 */
523 if (li.li_crypto_enabled)
524 (void) snprintf(options, sizeof (options),
525 gettext("Encrypted"));
526 else if (li.li_algorithm[0] != '\0')
527 (void) snprintf(options, sizeof (options),
528 gettext("Compressed(%s)"), li.li_algorithm);
529 else
530 (void) snprintf(options, sizeof (options), "-");
531
532 (void) printf(FORMAT, path, li.li_filename, options);
533 }
534 }
535
536 /*
537 * Verify the cipher selected by user.
538 */
539 static mech_alias_t *
540 ciph2mech(const char *alias)
541 {
542 int i;
543
544 for (i = 0; i < mech_aliases_count; i++) {
545 if (strcasecmp(alias, mech_aliases[i].alias) == 0)
546 return (&mech_aliases[i]);
547 }
548 return (NULL);
549 }
1772 return (segsize);
1773 }
1774
1775 int
1776 main(int argc, char *argv[])
1777 {
1778 int lfd;
1779 int c;
1780 const char *devicename = NULL;
1781 const char *filename = NULL;
1782 const char *algname = COMPRESS_ALGORITHM;
1783 int openflag;
1784 int minor;
1785 int compress_index;
1786 uint32_t segsize = SEGSIZE;
1787 static char *lofictl = "/dev/" LOFI_CTL_NAME;
1788 boolean_t force = B_FALSE;
1789 const char *pname;
1790 boolean_t errflag = B_FALSE;
1791 boolean_t addflag = B_FALSE;
1792 boolean_t deleteflag = B_FALSE;
1793 boolean_t ephflag = B_FALSE;
1794 boolean_t compressflag = B_FALSE;
1795 boolean_t uncompressflag = B_FALSE;
1796 /* the next two work together for -c, -k, -T, -e options only */
1797 boolean_t need_crypto = B_FALSE; /* if any -c, -k, -T, -e */
1798 boolean_t cipher_only = B_TRUE; /* if -c only */
1799 const char *keyfile = NULL;
1800 mech_alias_t *cipher = NULL;
1801 token_spec_t *token = NULL;
1802 char *rkey = NULL;
1803 size_t rksz = 0;
1804 char realfilename[MAXPATHLEN];
1805
1806 pname = getpname(argv[0]);
1807
1808 (void) setlocale(LC_ALL, "");
1809 (void) textdomain(TEXT_DOMAIN);
1810
1811 while ((c = getopt(argc, argv, "a:c:Cd:efk:o:s:T:U")) != EOF) {
1812 switch (c) {
1813 case 'a':
1814 addflag = B_TRUE;
1815 if ((filename = realpath(optarg, realfilename)) == NULL)
1816 die("%s", optarg);
1817 if (((argc - optind) > 0) && (*argv[optind] != '-')) {
1818 /* optional device */
1819 devicename = argv[optind];
1820 optind++;
1821 }
1822 break;
1823 case 'C':
1824 compressflag = B_TRUE;
1825 if (((argc - optind) > 1) && (*argv[optind] != '-')) {
1826 /* optional algorithm */
1827 algname = argv[optind];
1828 optind++;
1829 }
1830 check_algorithm_validity(algname, &compress_index);
1831 break;
1846 devicename = optarg;
1847 else {
1848 if ((filename = realpath(optarg,
1849 realfilename)) == NULL)
1850 die("%s", optarg);
1851 }
1852 break;
1853 case 'e':
1854 ephflag = B_TRUE;
1855 need_crypto = B_TRUE;
1856 cipher_only = B_FALSE; /* need to unset cipher_only */
1857 break;
1858 case 'f':
1859 force = B_TRUE;
1860 break;
1861 case 'k':
1862 keyfile = optarg;
1863 need_crypto = B_TRUE;
1864 cipher_only = B_FALSE; /* need to unset cipher_only */
1865 break;
1866 case 's':
1867 segsize = convert_to_num(optarg);
1868 if (segsize < DEV_BSIZE || !ISP2(segsize))
1869 die(gettext("segment size %s is invalid "
1870 "or not a multiple of minimum block "
1871 "size %ld\n"), optarg, DEV_BSIZE);
1872 break;
1873 case 'T':
1874 if ((token = parsetoken(optarg)) == NULL) {
1875 errflag = B_TRUE;
1876 warn(
1877 gettext("invalid token key specifier %s\n"),
1878 optarg);
1879 }
1880 need_crypto = B_TRUE;
1881 cipher_only = B_FALSE; /* need to unset cipher_only */
1882 break;
1883 case 'U':
1884 uncompressflag = B_TRUE;
1885 break;
1886 case '?':
1887 default:
1888 errflag = B_TRUE;
1889 break;
1890 }
1891 }
1892
1893 /* Check for mutually exclusive combinations of options */
1894 if (errflag ||
1895 (addflag && deleteflag) ||
1896 (!addflag && need_crypto) ||
1897 ((compressflag || uncompressflag) && (addflag || deleteflag)))
1898 usage(pname);
1899
1900 /* ephemeral key, and key from either file or token are incompatible */
1901 if (ephflag && (keyfile != NULL || token != NULL)) {
1902 die(gettext("ephemeral key cannot be used with keyfile"
1903 " or token key\n"));
1904 }
1905
1906 /*
1907 * "-c" but no "-k", "-T", "-e", or "-T -k" means derive key from
1908 * command line passphrase
1909 */
1910
1911 switch (argc - optind) {
1912 case 0: /* no more args */
1913 if (compressflag || uncompressflag) /* needs filename */
1914 usage(pname);
1915 break;
1992
1993 init_crypto(token, cipher, &sess);
1994
1995 if (cipher_only) {
1996 getkeyfromuser(cipher, &rkey, &rksz);
1997 } else if (token != NULL) {
1998 getkeyfromtoken(sess, token, keyfile, cipher,
1999 &rkey, &rksz);
2000 } else {
2001 /* this also handles ephemeral keys */
2002 getkeyfromfile(keyfile, cipher, &rkey, &rksz);
2003 }
2004
2005 end_crypto(sess);
2006 }
2007
2008 /*
2009 * Now to the real work.
2010 */
2011 if (addflag)
2012 add_mapping(lfd, devicename, filename, cipher, rkey, rksz);
2013 else if (compressflag)
2014 lofi_compress(&lfd, filename, compress_index, segsize);
2015 else if (uncompressflag)
2016 lofi_uncompress(lfd, filename);
2017 else if (deleteflag)
2018 delete_mapping(lfd, devicename, filename, force);
2019 else if (filename || devicename)
2020 print_one_mapping(lfd, devicename, filename);
2021 else
2022 print_mappings(lfd);
2023
2024 if (lfd != -1)
2025 (void) close(lfd);
2026 closelib();
2027 return (E_SUCCESS);
2028 }
|
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 */
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:
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 }
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;
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;
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 }
|