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)
|