Print this page
5857 add -o option to lofiadm
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Andy Stormont <astormont@racktopsystems.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>


   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 Joyent, Inc.  All rights reserved.
  25  *
  26  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  27  * Copyright (c) 2014 Gary Mills

  28  */
  29 
  30 /*
  31  * lofiadm - administer lofi(7d). Very simple, add and remove file<->device
  32  * associations, and display status. All the ioctls are private between
  33  * lofi and lofiadm, and so are very simple - device information is
  34  * communicated via a minor number.
  35  */
  36 
  37 #include <sys/types.h>
  38 #include <sys/param.h>
  39 #include <sys/lofi.h>
  40 #include <sys/stat.h>
  41 #include <sys/sysmacros.h>
  42 #include <netinet/in.h>
  43 #include <stdio.h>
  44 #include <fcntl.h>
  45 #include <locale.h>
  46 #include <string.h>
  47 #include <strings.h>


 136 
 137 lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = {
 138         {NULL,                  gzip_compress,  6,      "gzip"}, /* default */
 139         {NULL,                  gzip_compress,  6,      "gzip-6"},
 140         {NULL,                  gzip_compress,  9,      "gzip-9"},
 141         {NULL,                  lzma_compress,  0,      "lzma"}
 142 };
 143 
 144 /* For displaying lofi mappings */
 145 #define FORMAT                  "%-20s     %-30s        %s\n"
 146 
 147 #define COMPRESS_ALGORITHM      "gzip"
 148 #define COMPRESS_THRESHOLD      2048
 149 #define SEGSIZE                 131072
 150 #define BLOCK_SIZE              512
 151 #define KILOBYTE                1024
 152 #define MEGABYTE                (KILOBYTE * KILOBYTE)
 153 #define GIGABYTE                (KILOBYTE * MEGABYTE)
 154 #define LIBZ                    "libz.so.1"
 155 


 156 static void
 157 usage(const char *pname)
 158 {
 159         (void) fprintf(stderr, gettext(USAGE), pname, pname, pname,
 160             pname, pname, pname, pname, pname, pname, pname);
 161         exit(E_USAGE);
 162 }
 163 
 164 static int
 165 gzip_compress(void *src, size_t srclen, void *dst, size_t *dstlen, int level)
 166 {
 167         static int (*compress2p)(void *, ulong_t *, void *, size_t, int) = NULL;
 168         void *libz_hdl = NULL;
 169 
 170         /*
 171          * The first time we are called, attempt to dlopen()
 172          * libz.so.1 and get a pointer to the compress2() function
 173          */
 174         if (compress2p == NULL) {
 175                 if ((libz_hdl = openlib(LIBZ)) == NULL)


 818         copyfield(ti->key, FLD_LABEL);
 819 
 820         /*
 821          * If token specified and it only contains a key label, then
 822          * search all tokens for the key, otherwise only those with
 823          * matching name, mfr, and serno are used.
 824          */
 825         /*
 826          * That's how we'd like it to be, however, if only the key label
 827          * is specified, default to using softtoken.  It's easier.
 828          */
 829         if (ti->name == NULL && ti->mfr == NULL && ti->serno == NULL)
 830                 ti->name = strdup(pkcs11_default_token());
 831         return (ti);
 832 }
 833 
 834 /*
 835  * PBE the passphrase into a raw key
 836  */
 837 static void
 838 getkeyfromuser(mech_alias_t *cipher, char **raw_key, size_t *raw_key_sz)

 839 {
 840         CK_SESSION_HANDLE sess;
 841         CK_RV   rv;
 842         char    *pass = NULL;
 843         size_t  passlen = 0;
 844         void    *salt = NULL;   /* don't use NULL, see note on salt below */
 845         size_t  saltlen = 0;
 846         CK_KEY_TYPE ktype;
 847         void    *kvalue;
 848         size_t  klen;
 849 
 850         /* did init_crypto find a slot that supports this cipher? */
 851         if (cipher->slot == (CK_SLOT_ID)-1 || cipher->max_keysize == 0) {
 852                 rv = CKR_MECHANISM_INVALID;
 853                 goto cleanup;
 854         }
 855 
 856         rv = pkcs11_mech2keytype(cipher->type, &ktype);
 857         if (rv != CKR_OK)
 858                 goto cleanup;
 859 
 860         /*
 861          * use the passphrase to generate a PBE PKCS#5 secret key and
 862          * retrieve the raw key data to eventually pass it to the kernel;
 863          */
 864         rv = C_OpenSession(cipher->slot, CKF_SERIAL_SESSION, NULL, NULL, &sess);
 865         if (rv != CKR_OK)
 866                 goto cleanup;
 867 
 868         /* get user passphrase with 8 byte minimum */
 869         if (pkcs11_get_pass(NULL, &pass, &passlen, MIN_PASSLEN, B_TRUE) < 0) {

 870                 die(gettext("passphrases do not match\n"));
 871         }
 872 
 873         /*
 874          * salt should not be NULL, or else pkcs11_PasswdToKey() will
 875          * complain about CKR_MECHANISM_PARAM_INVALID; the following is
 876          * to make up for not having a salt until a proper one is used
 877          */
 878         salt = pass;
 879         saltlen = passlen;
 880 
 881         klen = cipher->max_keysize;
 882         rv = pkcs11_PasswdToKey(sess, pass, passlen, salt, saltlen, ktype,
 883             cipher->max_keysize, &kvalue, &klen);
 884 
 885         (void) C_CloseSession(sess);
 886 
 887         if (rv != CKR_OK) {
 888                 goto cleanup;
 889         }


1742                 die(gettext("open: %s"), filename);
1743         }
1744         error = fstat64(fd, &buf);
1745         if (error == -1) {
1746                 die(gettext("fstat: %s"), filename);
1747         } else if (!S_ISLOFIABLE(buf.st_mode)) {
1748                 die(gettext("%s is not a regular file, "
1749                     "block, or character device\n"),
1750                     filename);
1751         } else if ((buf.st_size % DEV_BSIZE) != 0) {
1752                 die(gettext("size of %s is not a multiple of %d\n"),
1753                     filename, DEV_BSIZE);
1754         }
1755         (void) close(fd);
1756 
1757         if (name_to_minor(filename) != 0) {
1758                 die(gettext("cannot use %s on itself\n"), LOFI_DRIVER_NAME);
1759         }
1760 }
1761 



































1762 static uint32_t
1763 convert_to_num(const char *str)
1764 {
1765         int len;
1766         uint32_t segsize, mult = 1;
1767 
1768         len = strlen(str);
1769         if (len && isalpha(str[len - 1])) {
1770                 switch (str[len - 1]) {
1771                 case 'k':
1772                 case 'K':
1773                         mult = KILOBYTE;
1774                         break;
1775                 case 'b':
1776                 case 'B':
1777                         mult = BLOCK_SIZE;
1778                         break;
1779                 case 'm':
1780                 case 'M':
1781                         mult = MEGABYTE;


1815         boolean_t rdflag = B_FALSE;
1816         boolean_t deleteflag = B_FALSE;
1817         boolean_t ephflag = B_FALSE;
1818         boolean_t compressflag = B_FALSE;
1819         boolean_t uncompressflag = B_FALSE;
1820         /* the next two work together for -c, -k, -T, -e options only */
1821         boolean_t need_crypto = B_FALSE;        /* if any -c, -k, -T, -e */
1822         boolean_t cipher_only = B_TRUE;         /* if -c only */
1823         const char *keyfile = NULL;
1824         mech_alias_t *cipher = NULL;
1825         token_spec_t *token = NULL;
1826         char    *rkey = NULL;
1827         size_t  rksz = 0;
1828         char realfilename[MAXPATHLEN];
1829 
1830         pname = getpname(argv[0]);
1831 
1832         (void) setlocale(LC_ALL, "");
1833         (void) textdomain(TEXT_DOMAIN);
1834 
1835         while ((c = getopt(argc, argv, "a:c:Cd:efk:o:rs:T:U")) != EOF) {
1836                 switch (c) {
1837                 case 'a':
1838                         addflag = B_TRUE;
1839                         if ((filename = realpath(optarg, realfilename)) == NULL)
1840                                 die("%s", optarg);
1841                         if (((argc - optind) > 0) && (*argv[optind] != '-')) {
1842                                 /* optional device */
1843                                 devicename = argv[optind];
1844                                 optind++;
1845                         }
1846                         break;
1847                 case 'C':
1848                         compressflag = B_TRUE;
1849                         if (((argc - optind) > 1) && (*argv[optind] != '-')) {
1850                                 /* optional algorithm */
1851                                 algname = argv[optind];
1852                                 optind++;
1853                         }
1854                         check_algorithm_validity(algname, &compress_index);
1855                         break;


2004          *    in which case the passphrase unlocks the token
2005          * If only the cipher is specified, reconfirm the passphrase
2006          * to ensure the user hasn't mis-entered it.  Otherwise, the
2007          * token will enforce the token passphrase.
2008          */
2009         if (need_crypto) {
2010                 CK_SESSION_HANDLE       sess;
2011 
2012                 /* pick a cipher if none specified */
2013                 if (cipher == NULL)
2014                         cipher = DEFAULT_CIPHER;
2015 
2016                 if (!kernel_cipher_check(cipher))
2017                         die(gettext(
2018                             "use \"cryptoadm list -m\" to find available "
2019                             "mechanisms\n"));
2020 
2021                 init_crypto(token, cipher, &sess);
2022 
2023                 if (cipher_only) {
2024                         getkeyfromuser(cipher, &rkey, &rksz);

2025                 } else if (token != NULL) {
2026                         getkeyfromtoken(sess, token, keyfile, cipher,
2027                             &rkey, &rksz);
2028                 } else {
2029                         /* this also handles ephemeral keys */
2030                         getkeyfromfile(keyfile, cipher, &rkey, &rksz);
2031                 }
2032 
2033                 end_crypto(sess);
2034         }
2035 
2036         /*
2037          * Now to the real work.
2038          */
2039         if (addflag)
2040                 add_mapping(lfd, devicename, filename, cipher, rkey, rksz,
2041                     rdflag);
2042         else if (compressflag)
2043                 lofi_compress(&lfd, filename, compress_index, segsize);
2044         else if (uncompressflag)


   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 Joyent, Inc.  All rights reserved.
  25  *
  26  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  27  * Copyright (c) 2014 Gary Mills
  28  * Copyright (c) 2016 Andrey Sokolov
  29  */
  30 
  31 /*
  32  * lofiadm - administer lofi(7d). Very simple, add and remove file<->device
  33  * associations, and display status. All the ioctls are private between
  34  * lofi and lofiadm, and so are very simple - device information is
  35  * communicated via a minor number.
  36  */
  37 
  38 #include <sys/types.h>
  39 #include <sys/param.h>
  40 #include <sys/lofi.h>
  41 #include <sys/stat.h>
  42 #include <sys/sysmacros.h>
  43 #include <netinet/in.h>
  44 #include <stdio.h>
  45 #include <fcntl.h>
  46 #include <locale.h>
  47 #include <string.h>
  48 #include <strings.h>


 137 
 138 lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = {
 139         {NULL,                  gzip_compress,  6,      "gzip"}, /* default */
 140         {NULL,                  gzip_compress,  6,      "gzip-6"},
 141         {NULL,                  gzip_compress,  9,      "gzip-9"},
 142         {NULL,                  lzma_compress,  0,      "lzma"}
 143 };
 144 
 145 /* For displaying lofi mappings */
 146 #define FORMAT                  "%-20s     %-30s        %s\n"
 147 
 148 #define COMPRESS_ALGORITHM      "gzip"
 149 #define COMPRESS_THRESHOLD      2048
 150 #define SEGSIZE                 131072
 151 #define BLOCK_SIZE              512
 152 #define KILOBYTE                1024
 153 #define MEGABYTE                (KILOBYTE * KILOBYTE)
 154 #define GIGABYTE                (KILOBYTE * MEGABYTE)
 155 #define LIBZ                    "libz.so.1"
 156 
 157 const char lofi_crypto_magic[6] = LOFI_CRYPTO_MAGIC;
 158 
 159 static void
 160 usage(const char *pname)
 161 {
 162         (void) fprintf(stderr, gettext(USAGE), pname, pname, pname,
 163             pname, pname, pname, pname, pname, pname, pname);
 164         exit(E_USAGE);
 165 }
 166 
 167 static int
 168 gzip_compress(void *src, size_t srclen, void *dst, size_t *dstlen, int level)
 169 {
 170         static int (*compress2p)(void *, ulong_t *, void *, size_t, int) = NULL;
 171         void *libz_hdl = NULL;
 172 
 173         /*
 174          * The first time we are called, attempt to dlopen()
 175          * libz.so.1 and get a pointer to the compress2() function
 176          */
 177         if (compress2p == NULL) {
 178                 if ((libz_hdl = openlib(LIBZ)) == NULL)


 821         copyfield(ti->key, FLD_LABEL);
 822 
 823         /*
 824          * If token specified and it only contains a key label, then
 825          * search all tokens for the key, otherwise only those with
 826          * matching name, mfr, and serno are used.
 827          */
 828         /*
 829          * That's how we'd like it to be, however, if only the key label
 830          * is specified, default to using softtoken.  It's easier.
 831          */
 832         if (ti->name == NULL && ti->mfr == NULL && ti->serno == NULL)
 833                 ti->name = strdup(pkcs11_default_token());
 834         return (ti);
 835 }
 836 
 837 /*
 838  * PBE the passphrase into a raw key
 839  */
 840 static void
 841 getkeyfromuser(mech_alias_t *cipher, char **raw_key, size_t *raw_key_sz,
 842     boolean_t with_confirmation)
 843 {
 844         CK_SESSION_HANDLE sess;
 845         CK_RV   rv;
 846         char    *pass = NULL;
 847         size_t  passlen = 0;
 848         void    *salt = NULL;   /* don't use NULL, see note on salt below */
 849         size_t  saltlen = 0;
 850         CK_KEY_TYPE ktype;
 851         void    *kvalue;
 852         size_t  klen;
 853 
 854         /* did init_crypto find a slot that supports this cipher? */
 855         if (cipher->slot == (CK_SLOT_ID)-1 || cipher->max_keysize == 0) {
 856                 rv = CKR_MECHANISM_INVALID;
 857                 goto cleanup;
 858         }
 859 
 860         rv = pkcs11_mech2keytype(cipher->type, &ktype);
 861         if (rv != CKR_OK)
 862                 goto cleanup;
 863 
 864         /*
 865          * use the passphrase to generate a PBE PKCS#5 secret key and
 866          * retrieve the raw key data to eventually pass it to the kernel;
 867          */
 868         rv = C_OpenSession(cipher->slot, CKF_SERIAL_SESSION, NULL, NULL, &sess);
 869         if (rv != CKR_OK)
 870                 goto cleanup;
 871 
 872         /* get user passphrase with 8 byte minimum */
 873         if (pkcs11_get_pass(NULL, &pass, &passlen, MIN_PASSLEN,
 874             with_confirmation) < 0) {
 875                 die(gettext("passphrases do not match\n"));
 876         }
 877 
 878         /*
 879          * salt should not be NULL, or else pkcs11_PasswdToKey() will
 880          * complain about CKR_MECHANISM_PARAM_INVALID; the following is
 881          * to make up for not having a salt until a proper one is used
 882          */
 883         salt = pass;
 884         saltlen = passlen;
 885 
 886         klen = cipher->max_keysize;
 887         rv = pkcs11_PasswdToKey(sess, pass, passlen, salt, saltlen, ktype,
 888             cipher->max_keysize, &kvalue, &klen);
 889 
 890         (void) C_CloseSession(sess);
 891 
 892         if (rv != CKR_OK) {
 893                 goto cleanup;
 894         }


1747                 die(gettext("open: %s"), filename);
1748         }
1749         error = fstat64(fd, &buf);
1750         if (error == -1) {
1751                 die(gettext("fstat: %s"), filename);
1752         } else if (!S_ISLOFIABLE(buf.st_mode)) {
1753                 die(gettext("%s is not a regular file, "
1754                     "block, or character device\n"),
1755                     filename);
1756         } else if ((buf.st_size % DEV_BSIZE) != 0) {
1757                 die(gettext("size of %s is not a multiple of %d\n"),
1758                     filename, DEV_BSIZE);
1759         }
1760         (void) close(fd);
1761 
1762         if (name_to_minor(filename) != 0) {
1763                 die(gettext("cannot use %s on itself\n"), LOFI_DRIVER_NAME);
1764         }
1765 }
1766 
1767 static boolean_t
1768 check_file_is_encrypted(const char *filename)
1769 {
1770         int     fd;
1771         char    buf[sizeof (lofi_crypto_magic)];
1772         int     got;
1773         int     rest = sizeof (lofi_crypto_magic);
1774 
1775         fd = open64(filename, O_RDONLY);
1776         if (fd == -1)
1777                 die(gettext("failed to open: %s"), filename);
1778 
1779         if (lseek(fd, CRYOFF, SEEK_SET) != CRYOFF)
1780                 die(gettext("failed to seek to offset 0x%lx in file %s"),
1781                     CRYOFF, filename);
1782 
1783         do {
1784                 got = read(fd, buf + sizeof (lofi_crypto_magic) - rest, rest);
1785                 if ((got == 0) || ((got == -1) && (errno != EINTR)))
1786                         die(gettext("failed to read crypto header"
1787                             " at offset 0x%lx in file %s"), CRYOFF, filename);
1788 
1789                 if (got > 0)
1790                         rest -= got;
1791         } while (rest > 0);
1792 
1793         while (close(fd) == -1) {
1794                 if (errno != EINTR)
1795                         die(gettext("failed to close file %s"), filename);
1796         }
1797 
1798         return (strncmp(buf, lofi_crypto_magic,
1799             sizeof (lofi_crypto_magic)) == 0);
1800 }
1801 
1802 static uint32_t
1803 convert_to_num(const char *str)
1804 {
1805         int len;
1806         uint32_t segsize, mult = 1;
1807 
1808         len = strlen(str);
1809         if (len && isalpha(str[len - 1])) {
1810                 switch (str[len - 1]) {
1811                 case 'k':
1812                 case 'K':
1813                         mult = KILOBYTE;
1814                         break;
1815                 case 'b':
1816                 case 'B':
1817                         mult = BLOCK_SIZE;
1818                         break;
1819                 case 'm':
1820                 case 'M':
1821                         mult = MEGABYTE;


1855         boolean_t rdflag = B_FALSE;
1856         boolean_t deleteflag = B_FALSE;
1857         boolean_t ephflag = B_FALSE;
1858         boolean_t compressflag = B_FALSE;
1859         boolean_t uncompressflag = B_FALSE;
1860         /* the next two work together for -c, -k, -T, -e options only */
1861         boolean_t need_crypto = B_FALSE;        /* if any -c, -k, -T, -e */
1862         boolean_t cipher_only = B_TRUE;         /* if -c only */
1863         const char *keyfile = NULL;
1864         mech_alias_t *cipher = NULL;
1865         token_spec_t *token = NULL;
1866         char    *rkey = NULL;
1867         size_t  rksz = 0;
1868         char realfilename[MAXPATHLEN];
1869 
1870         pname = getpname(argv[0]);
1871 
1872         (void) setlocale(LC_ALL, "");
1873         (void) textdomain(TEXT_DOMAIN);
1874 
1875         while ((c = getopt(argc, argv, "a:c:Cd:efk:rs:T:U")) != EOF) {
1876                 switch (c) {
1877                 case 'a':
1878                         addflag = B_TRUE;
1879                         if ((filename = realpath(optarg, realfilename)) == NULL)
1880                                 die("%s", optarg);
1881                         if (((argc - optind) > 0) && (*argv[optind] != '-')) {
1882                                 /* optional device */
1883                                 devicename = argv[optind];
1884                                 optind++;
1885                         }
1886                         break;
1887                 case 'C':
1888                         compressflag = B_TRUE;
1889                         if (((argc - optind) > 1) && (*argv[optind] != '-')) {
1890                                 /* optional algorithm */
1891                                 algname = argv[optind];
1892                                 optind++;
1893                         }
1894                         check_algorithm_validity(algname, &compress_index);
1895                         break;


2044          *    in which case the passphrase unlocks the token
2045          * If only the cipher is specified, reconfirm the passphrase
2046          * to ensure the user hasn't mis-entered it.  Otherwise, the
2047          * token will enforce the token passphrase.
2048          */
2049         if (need_crypto) {
2050                 CK_SESSION_HANDLE       sess;
2051 
2052                 /* pick a cipher if none specified */
2053                 if (cipher == NULL)
2054                         cipher = DEFAULT_CIPHER;
2055 
2056                 if (!kernel_cipher_check(cipher))
2057                         die(gettext(
2058                             "use \"cryptoadm list -m\" to find available "
2059                             "mechanisms\n"));
2060 
2061                 init_crypto(token, cipher, &sess);
2062 
2063                 if (cipher_only) {
2064                         getkeyfromuser(cipher, &rkey, &rksz,
2065                             !check_file_is_encrypted(filename));
2066                 } else if (token != NULL) {
2067                         getkeyfromtoken(sess, token, keyfile, cipher,
2068                             &rkey, &rksz);
2069                 } else {
2070                         /* this also handles ephemeral keys */
2071                         getkeyfromfile(keyfile, cipher, &rkey, &rksz);
2072                 }
2073 
2074                 end_crypto(sess);
2075         }
2076 
2077         /*
2078          * Now to the real work.
2079          */
2080         if (addflag)
2081                 add_mapping(lfd, devicename, filename, cipher, rkey, rksz,
2082                     rdflag);
2083         else if (compressflag)
2084                 lofi_compress(&lfd, filename, compress_index, segsize);
2085         else if (uncompressflag)